Skip to content

Commit 907eba5

Browse files
feat(pluto): add credential persistence
Fixes ATL-2648
1 parent 3d5404c commit 907eba5

21 files changed

+555
-93
lines changed

Domain/Sources/BBs/Pluto.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public protocol Pluto {
1212
func storeMessage(message: Message) -> AnyPublisher<Void, Error>
1313
func storeMessages(messages: [Message]) -> AnyPublisher<Void, Error>
1414
func storeMediator(peer: DID, routingDID: DID, mediatorDID: DID) -> AnyPublisher<Void, Error>
15+
func storeCredential(credential: VerifiableCredential) -> AnyPublisher<Void, Error>
1516

1617
func getAllPrismDIDs() -> AnyPublisher<[(did: DID, keyPairIndex: Int, alias: String?)], Error>
1718
func getPrismDIDInfo(did: DID) -> AnyPublisher<(did: DID, keyPairIndex: Int, alias: String?)?, Error>
@@ -37,4 +38,6 @@ public protocol Pluto {
3738
func getMessage(id: String) -> AnyPublisher<Message?, Error>
3839

3940
func getAllMediators() -> AnyPublisher<[(did: DID, routingDID: DID, mediatorDID: DID)], Error>
41+
42+
func getAllCredentials() -> AnyPublisher<[VerifiableCredential], Error>
4043
}

Domain/Sources/Models/Errors.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public enum PlutoError: Error {
3131
case messageMissingFromOrToDIDError
3232
case didPairIsNotPersistedError
3333
case holderDIDAlreadyPairingError
34+
case unknownCredentialTypeError
35+
case invalidCredentialJsonError
3436
}
3537

3638
public enum PolluxError: Error {
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,5 @@
1-
import Domain
21
import Foundation
32

4-
struct JWTCredentialPayload {
5-
struct JWTVerfiableCredential {
6-
let context: Set<String>
7-
let type: Set<String>
8-
let credentialSchema: VerifiableCredentialTypeContainer?
9-
let credentialSubject: String
10-
let credentialStatus: VerifiableCredentialTypeContainer?
11-
let refreshService: VerifiableCredentialTypeContainer?
12-
let evidence: VerifiableCredentialTypeContainer?
13-
let termsOfUse: VerifiableCredentialTypeContainer?
14-
}
15-
let iss: DID
16-
let sub: String?
17-
let verifiableCredential: JWTVerfiableCredential
18-
let nbf: Date
19-
let exp: Date?
20-
let jti: String?
21-
let aud: Set<String>
22-
}
23-
24-
extension JWTCredentialPayload: VerifiableCredential {
25-
var context: Set<String> { verifiableCredential.context }
26-
var type: Set<String> { verifiableCredential.type }
27-
var id: String? { jti }
28-
var issuer: DID { iss }
29-
var issuanceDate: Date { nbf }
30-
var expirationDate: Date? { exp }
31-
var credentialSchema: VerifiableCredentialTypeContainer? { verifiableCredential.credentialSchema }
32-
var credentialSubject: String { verifiableCredential.credentialSubject }
33-
var credentialStatus: VerifiableCredentialTypeContainer? { verifiableCredential.credentialStatus }
34-
var refreshService: VerifiableCredentialTypeContainer? { verifiableCredential.refreshService }
35-
var evidence: Domain.VerifiableCredentialTypeContainer? { verifiableCredential.evidence }
36-
var termsOfUse: Domain.VerifiableCredentialTypeContainer? { verifiableCredential.termsOfUse }
37-
var validFrom: Domain.VerifiableCredentialTypeContainer? { nil }
38-
var validUntil: Domain.VerifiableCredentialTypeContainer? { nil }
39-
var proof: String? { nil }
40-
}
41-
423
extension JWTCredentialPayload.JWTVerfiableCredential: Codable {
434
enum CodingKeys: String, CodingKey {
445
case context = "@context"
@@ -54,7 +15,11 @@ extension JWTCredentialPayload.JWTVerfiableCredential: Codable {
5415
public func encode(to encoder: Encoder) throws {
5516
var container = encoder.container(keyedBy: CodingKeys.self)
5617
try container.encode(self.context, forKey: .context)
57-
try container.encode(self.type, forKey: .type)
18+
if self.type.count != 1 {
19+
try container.encode(self.type, forKey: .type)
20+
} else if let value = self.type.first {
21+
try container.encode(value, forKey: .type)
22+
}
5823
try container.encode(self.credentialSubject, forKey: .credentialSubject)
5924
try container.encode(self.credentialStatus, forKey: .credentialStatus)
6025
try container.encode(self.credentialSchema, forKey: .credentialSchema)
@@ -65,29 +30,44 @@ extension JWTCredentialPayload.JWTVerfiableCredential: Codable {
6530

6631
public init(from decoder: Decoder) throws {
6732
let container = try decoder.container(keyedBy: CodingKeys.self)
68-
self.context = try container.decode(Set<String>.self, forKey: .context)
69-
self.type = try container.decode(Set<String>.self, forKey: .type)
70-
self.credentialSubject = try container.decode(String.self, forKey: .credentialSubject)
71-
self.credentialStatus = try? container.decode(
33+
let context = try container.decode(Set<String>.self, forKey: .context)
34+
let type: Set<String>
35+
if let value = try? container.decode(String.self, forKey: .type) {
36+
type = Set([value])
37+
} else {
38+
type = try container.decode(Set<String>.self, forKey: .type)
39+
}
40+
let credentialSubject = try container.decode(String.self, forKey: .credentialSubject)
41+
let credentialStatus = try? container.decode(
7242
VerifiableCredentialTypeContainer.self,
7343
forKey: .credentialStatus
7444
)
75-
self.credentialSchema = try? container.decode(
45+
let credentialSchema = try? container.decode(
7646
VerifiableCredentialTypeContainer.self,
7747
forKey: .credentialSchema
7848
)
79-
self.refreshService = try? container.decode(
49+
let refreshService = try? container.decode(
8050
VerifiableCredentialTypeContainer.self,
8151
forKey: .refreshService
8252
)
83-
self.evidence = try? container.decode(
53+
let evidence = try? container.decode(
8454
VerifiableCredentialTypeContainer.self,
8555
forKey: .evidence
8656
)
87-
self.termsOfUse = try? container.decode(
57+
let termsOfUse = try? container.decode(
8858
VerifiableCredentialTypeContainer.self,
8959
forKey: .termsOfUse
9060
)
61+
self.init(
62+
context: context,
63+
type: type,
64+
credentialSchema: credentialSchema,
65+
credentialSubject: credentialSubject,
66+
credentialStatus: credentialStatus,
67+
refreshService: refreshService,
68+
evidence: evidence,
69+
termsOfUse: termsOfUse
70+
)
9171
}
9272
}
9373

@@ -116,24 +96,34 @@ extension JWTCredentialPayload: Codable {
11696
public init(from decoder: Decoder) throws {
11797
let container = try decoder.container(keyedBy: CodingKeys.self)
11898
let didString = try container.decode(String.self, forKey: .iss)
119-
self.iss = try DID(string: didString)
120-
self.sub = try? container.decode(String.self, forKey: .sub)
121-
self.verifiableCredential = try container.decode(JWTVerfiableCredential.self, forKey: .verfiableCredential)
122-
self.nbf = try container.decode(
99+
let iss = try DID(string: didString)
100+
let sub = try? container.decode(String.self, forKey: .sub)
101+
let verifiableCredential = try container.decode(JWTVerfiableCredential.self, forKey: .verfiableCredential)
102+
let nbf = try container.decode(
123103
Date.self,
124104
forKey: .nbf
125105
)
126-
self.exp = try? container.decode(
106+
let exp = try? container.decode(
127107
Date.self,
128108
forKey: .exp
129109
)
130-
self.jti = try? container.decode(
110+
let jti = try container.decode(
131111
String.self,
132112
forKey: .jti
133113
)
134-
self.aud = (try? container.decode(
114+
let aud = (try? container.decode(
135115
Set<String>.self,
136116
forKey: .aud
137117
)) ?? Set<String>()
118+
119+
self.init(
120+
iss: iss,
121+
sub: sub,
122+
verifiableCredential: verifiableCredential,
123+
nbf: nbf,
124+
exp: exp,
125+
jti: jti,
126+
aud: aud
127+
)
138128
}
139129
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import Foundation
2+
3+
public struct JWTCredentialPayload {
4+
public struct JWTVerfiableCredential {
5+
public let context: Set<String>
6+
public let type: Set<String>
7+
public let credentialSchema: VerifiableCredentialTypeContainer?
8+
public let credentialSubject: String
9+
public let credentialStatus: VerifiableCredentialTypeContainer?
10+
public let refreshService: VerifiableCredentialTypeContainer?
11+
public let evidence: VerifiableCredentialTypeContainer?
12+
public let termsOfUse: VerifiableCredentialTypeContainer?
13+
14+
public init(
15+
context: Set<String> = Set(),
16+
type: Set<String> = Set(),
17+
credentialSchema: VerifiableCredentialTypeContainer? = nil,
18+
credentialSubject: String,
19+
credentialStatus: VerifiableCredentialTypeContainer? = nil,
20+
refreshService: VerifiableCredentialTypeContainer? = nil,
21+
evidence: VerifiableCredentialTypeContainer? = nil,
22+
termsOfUse: VerifiableCredentialTypeContainer? = nil
23+
) {
24+
self.context = context
25+
self.type = type
26+
self.credentialSchema = credentialSchema
27+
self.credentialSubject = credentialSubject
28+
self.credentialStatus = credentialStatus
29+
self.refreshService = refreshService
30+
self.evidence = evidence
31+
self.termsOfUse = termsOfUse
32+
}
33+
}
34+
public let iss: DID
35+
public let sub: String?
36+
public let verifiableCredential: JWTVerfiableCredential
37+
public let nbf: Date
38+
public let exp: Date?
39+
public let jti: String
40+
public let aud: Set<String>
41+
42+
public init(
43+
iss: DID,
44+
sub: String? = nil,
45+
verifiableCredential: JWTVerfiableCredential,
46+
nbf: Date,
47+
exp: Date? = nil,
48+
jti: String,
49+
aud: Set<String> = Set()
50+
) {
51+
self.iss = iss
52+
self.sub = sub
53+
self.verifiableCredential = verifiableCredential
54+
self.nbf = nbf
55+
self.exp = exp
56+
self.jti = jti
57+
self.aud = aud
58+
}
59+
}
60+
61+
extension JWTCredentialPayload: VerifiableCredential {
62+
public var credentialType: CredentialType { CredentialType.jwt }
63+
public var context: Set<String> { verifiableCredential.context }
64+
public var type: Set<String> { verifiableCredential.type }
65+
public var id: String { jti }
66+
public var issuer: DID { iss }
67+
public var issuanceDate: Date { nbf }
68+
public var expirationDate: Date? { exp }
69+
public var credentialSchema: VerifiableCredentialTypeContainer? { verifiableCredential.credentialSchema }
70+
public var credentialSubject: String { verifiableCredential.credentialSubject }
71+
public var credentialStatus: VerifiableCredentialTypeContainer? { verifiableCredential.credentialStatus }
72+
public var refreshService: VerifiableCredentialTypeContainer? { verifiableCredential.refreshService }
73+
public var evidence: Domain.VerifiableCredentialTypeContainer? { verifiableCredential.evidence }
74+
public var termsOfUse: Domain.VerifiableCredentialTypeContainer? { verifiableCredential.termsOfUse }
75+
public var validFrom: Domain.VerifiableCredentialTypeContainer? { nil }
76+
public var validUntil: Domain.VerifiableCredentialTypeContainer? { nil }
77+
public var proof: String? { nil }
78+
}

Domain/Sources/Models/VerifiableCredential.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,15 @@ public struct VerifiableCredentialTypeContainer: Codable {
2222
}
2323
}
2424

25+
public enum CredentialType {
26+
case jwt
27+
case w3c
28+
case unknown
29+
}
30+
2531
public protocol VerifiableCredential {
26-
var id: String? { get }
32+
var credentialType: CredentialType { get }
33+
var id: String { get }
2734
var context: Set<String> { get }
2835
var type: Set<String> { get }
2936
var issuer: DID { get }
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,5 @@
1-
import Domain
21
import Foundation
32

4-
struct W3CVerifiableCredential: VerifiableCredential {
5-
let context: Set<String>
6-
let type: Set<String>
7-
let id: String?
8-
let issuer: DID
9-
let issuanceDate: Date
10-
let expirationDate: Date?
11-
let credentialSchema: VerifiableCredentialTypeContainer?
12-
let credentialSubject: String
13-
let credentialStatus: VerifiableCredentialTypeContainer?
14-
let refreshService: VerifiableCredentialTypeContainer?
15-
let evidence: VerifiableCredentialTypeContainer?
16-
let termsOfUse: VerifiableCredentialTypeContainer?
17-
let validFrom: VerifiableCredentialTypeContainer?
18-
let validUntil: VerifiableCredentialTypeContainer?
19-
let proof: String?
20-
let aud: Set<String>
21-
}
22-
233
extension W3CVerifiableCredential: Codable {
244
enum CodingKeys: String, CodingKey {
255
case context = "@context"
@@ -43,7 +23,11 @@ extension W3CVerifiableCredential: Codable {
4323
public func encode(to encoder: Encoder) throws {
4424
var container = encoder.container(keyedBy: CodingKeys.self)
4525
try container.encode(self.context, forKey: .context)
46-
try container.encode(self.type, forKey: .type)
26+
if self.type.count != 1 {
27+
try container.encode(self.type, forKey: .type)
28+
} else if let value = self.type.first {
29+
try container.encode(value, forKey: .type)
30+
}
4731
try container.encode(self.id, forKey: .id)
4832
try container.encode(self.issuer.string, forKey: .issuer)
4933
try container.encode(self.issuanceDate, forKey: .issuanceDate)
@@ -62,37 +46,61 @@ extension W3CVerifiableCredential: Codable {
6246

6347
public init(from decoder: Decoder) throws {
6448
let container = try decoder.container(keyedBy: CodingKeys.self)
65-
self.context = (try? container.decode(Set<String>.self, forKey: .context)) ?? Set()
66-
self.type = (try? container.decode(Set<String>.self, forKey: .type)) ?? Set()
67-
self.id = try container.decode(String.self, forKey: .id)
49+
let context = (try? container.decode(Set<String>.self, forKey: .context)) ?? Set()
50+
let type: Set<String>
51+
if let value = try? container.decode(String.self, forKey: .type) {
52+
type = Set([value])
53+
} else {
54+
type = try container.decode(Set<String>.self, forKey: .type)
55+
}
56+
let id = try container.decode(String.self, forKey: .id)
6857
let didString = try container.decode(String.self, forKey: .issuer)
69-
self.issuer = try DID(string: didString)
70-
self.issuanceDate = try container.decode(Date.self, forKey: .issuanceDate)
71-
self.expirationDate = try? container.decode(Date.self, forKey: .expirationDate)
72-
self.validFrom = try? container.decode(VerifiableCredentialTypeContainer.self, forKey: .validFrom)
73-
self.validUntil = try? container.decode(VerifiableCredentialTypeContainer.self, forKey: .validUntil)
74-
self.proof = try? container.decode(String.self, forKey: .proof)
75-
self.aud = (try? container.decode(Set<String>.self, forKey: .proof)) ?? Set()
76-
self.credentialSubject = try container.decode(String.self, forKey: .credentialSubject)
77-
self.credentialStatus = try? container.decode(
58+
let issuer = try DID(string: didString)
59+
let issuanceDate = try container.decode(Date.self, forKey: .issuanceDate)
60+
let expirationDate = try? container.decode(Date.self, forKey: .expirationDate)
61+
let validFrom = try? container.decode(VerifiableCredentialTypeContainer.self, forKey: .validFrom)
62+
let validUntil = try? container.decode(VerifiableCredentialTypeContainer.self, forKey: .validUntil)
63+
let proof = try? container.decode(String.self, forKey: .proof)
64+
let aud = (try? container.decode(Set<String>.self, forKey: .proof)) ?? Set()
65+
let credentialSubject = try container.decode(String.self, forKey: .credentialSubject)
66+
let credentialStatus = try? container.decode(
7867
VerifiableCredentialTypeContainer.self,
7968
forKey: .credentialStatus
8069
)
81-
self.credentialSchema = try? container.decode(
70+
let credentialSchema = try? container.decode(
8271
VerifiableCredentialTypeContainer.self,
8372
forKey: .credentialSchema
8473
)
85-
self.refreshService = try? container.decode(
74+
let refreshService = try? container.decode(
8675
VerifiableCredentialTypeContainer.self,
8776
forKey: .refreshService
8877
)
89-
self.evidence = try? container.decode(
78+
let evidence = try? container.decode(
9079
VerifiableCredentialTypeContainer.self,
9180
forKey: .evidence
9281
)
93-
self.termsOfUse = try? container.decode(
82+
let termsOfUse = try? container.decode(
9483
VerifiableCredentialTypeContainer.self,
9584
forKey: .termsOfUse
9685
)
86+
87+
self.init(
88+
context: context,
89+
type: type,
90+
id: id,
91+
issuer: issuer,
92+
issuanceDate: issuanceDate,
93+
expirationDate: expirationDate,
94+
credentialSchema: credentialSchema,
95+
credentialSubject: credentialSubject,
96+
credentialStatus: credentialStatus,
97+
refreshService: refreshService,
98+
evidence: evidence,
99+
termsOfUse: termsOfUse,
100+
validFrom: validFrom,
101+
validUntil: validUntil,
102+
proof: proof,
103+
aud: aud
104+
)
97105
}
98106
}

0 commit comments

Comments
 (0)