Skip to content

Commit f071fe7

Browse files
feat(sample): enable sample app for anoncreds verification
1 parent e519192 commit f071fe7

File tree

10 files changed

+259
-18
lines changed

10 files changed

+259
-18
lines changed

EdgeAgentSDK/EdgeAgent/Sources/EdgeAgent+Credentials.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,11 @@ public extension EdgeAgent {
9191

9292
func verifyPresentation(message: Message) async throws -> Bool {
9393
do {
94-
return try await pollux.verifyPresentation(message: message, options: [])
94+
let downloader = DownloadDataWithResolver(castor: castor)
95+
return try await pollux.verifyPresentation(message: message, options: [
96+
.credentialDefinitionDownloader(downloader: downloader),
97+
.schemaDownloader(downloader: downloader)
98+
])
9599
} catch {
96100
logger.error(error: error)
97101
throw error

EdgeAgentSDK/Pollux/Sources/Operation/Anoncreds/CreateAnoncredCredentialRequest.swift

+18-13
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,24 @@ private struct Schema: Codable {
1111
let issuerId: String
1212
}
1313

14-
struct StorableCredentialRequestMetadata: StorableCredential {
15-
let metadataJson: Data
16-
let storingId: String
17-
var recoveryId: String { "anoncreds+metadata"}
18-
var credentialData: Data { metadataJson }
19-
var queryIssuer: String? { nil }
20-
var querySubject: String? { nil }
21-
var queryCredentialCreated: Date? { nil }
22-
var queryCredentialUpdated: Date? { nil }
23-
var queryCredentialSchema: String? { nil }
24-
var queryValidUntil: Date? { nil }
25-
var queryRevoked: Bool? { nil }
26-
var queryAvailableClaims: [String] { [] }
14+
public struct StorableCredentialRequestMetadata: StorableCredential {
15+
public let metadataJson: Data
16+
public let storingId: String
17+
public var recoveryId: String { "anoncreds+metadata"}
18+
public var credentialData: Data { metadataJson }
19+
public var queryIssuer: String? { nil }
20+
public var querySubject: String? { nil }
21+
public var queryCredentialCreated: Date? { nil }
22+
public var queryCredentialUpdated: Date? { nil }
23+
public var queryCredentialSchema: String? { nil }
24+
public var queryValidUntil: Date? { nil }
25+
public var queryRevoked: Bool? { nil }
26+
public var queryAvailableClaims: [String] { [] }
27+
28+
public init(metadataJson: Data, storingId: String) {
29+
self.metadataJson = metadataJson
30+
self.storingId = storingId
31+
}
2732
}
2833

2934
struct CreateAnoncredCredentialRequest {

Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
EE6C7F5429C2754500D866AD /* DIDListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C7F5329C2754500D866AD /* DIDListView.swift */; };
4747
EE6C7F5629C2758100D866AD /* DIDListViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C7F5529C2758100D866AD /* DIDListViewState.swift */; };
4848
EE6C7F5829C275C400D866AD /* DIDListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C7F5729C275C400D866AD /* DIDListViewModel.swift */; };
49+
EE6FE6D22BFE0691001673F3 /* MockAnoncredsIssuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6FE6D12BFE0691001673F3 /* MockAnoncredsIssuer.swift */; };
4950
EE75147C29C3766800FFFAA4 /* DIDDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE75147B29C3766800FFFAA4 /* DIDDetailViewModel.swift */; };
5051
EE75147E29C376E700FFFAA4 /* DIDDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE75147D29C376E700FFFAA4 /* DIDDetailView.swift */; };
5152
EE75148029C378DB00FFFAA4 /* DIDDetailViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE75147F29C378DB00FFFAA4 /* DIDDetailViewState.swift */; };
@@ -173,6 +174,7 @@
173174
EE6C7F5329C2754500D866AD /* DIDListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DIDListView.swift; sourceTree = "<group>"; };
174175
EE6C7F5529C2758100D866AD /* DIDListViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DIDListViewState.swift; sourceTree = "<group>"; };
175176
EE6C7F5729C275C400D866AD /* DIDListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DIDListViewModel.swift; sourceTree = "<group>"; };
177+
EE6FE6D12BFE0691001673F3 /* MockAnoncredsIssuer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAnoncredsIssuer.swift; sourceTree = "<group>"; };
176178
EE75147B29C3766800FFFAA4 /* DIDDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DIDDetailViewModel.swift; sourceTree = "<group>"; };
177179
EE75147D29C376E700FFFAA4 /* DIDDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DIDDetailView.swift; sourceTree = "<group>"; };
178180
EE75147F29C378DB00FFFAA4 /* DIDDetailViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DIDDetailViewState.swift; sourceTree = "<group>"; };
@@ -643,6 +645,7 @@
643645
EEBC938E29C7311C0015A36E /* CredentialListViewState.swift */,
644646
EEBC939429C735910015A36E /* CredentialListViewModel.swift */,
645647
EEBC939629C737DE0015A36E /* CredentialListRouter.swift */,
648+
EE6FE6D12BFE0691001673F3 /* MockAnoncredsIssuer.swift */,
646649
);
647650
path = CredentialsList;
648651
sourceTree = "<group>";
@@ -944,6 +947,7 @@
944947
EE418AEF2BCFD926008766A6 /* PresentationsView.swift in Sources */,
945948
EE75148029C378DB00FFFAA4 /* DIDDetailViewState.swift in Sources */,
946949
EE92C42B2B7E1CA200FC0B6E /* DisablePreferenceKey.swift in Sources */,
950+
EE6FE6D22BFE0691001673F3 /* MockAnoncredsIssuer.swift in Sources */,
947951
EE6C7F5129C23A3400D866AD /* MediatorPageView.swift in Sources */,
948952
EE92C43D2B7E1F6A00FC0B6E /* AlreadyConnectedView.swift in Sources */,
949953
EE75A2F729479488007D4405 /* FancyToast.swift in Sources */,

Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/Verifier/PresentationCreate/CreatePresentationView.swift

+3
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,10 @@ struct AnoncredsClaimView: View {
149149

150150
var body: some View {
151151
TextField("Name", text: $claim.name)
152+
.textInputAutocapitalization(.never)
152153
TextField("Predicate", text: $claim.predicate)
154+
TextField("Value", text: $claim.value)
155+
.keyboardType(.numberPad)
153156
}
154157
}
155158

Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/Verifier/PresentationCreate/CreatePresentationViewModel.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,12 @@ class CreatePresentationViewModelImpl: CreatePresentationViewModel {
8585
claimFilters: anoncredsClaims.map {
8686
ClaimFilter(
8787
paths: [],
88-
type: "",
88+
type: $0.name,
8989
required: true,
9090
name: $0.name,
9191
format: nil,
92-
const: nil,
93-
pattern: $0.predicate
92+
const: $0.value.isEmpty ? nil : $0.value,
93+
pattern: $0.predicate.isEmpty ? nil : $0.predicate
9494
)
9595
}
9696
)

Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/Verifier/PresentationCreate/CreatePresentationViewState.swift

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct CreatePresentationViewState {
2222
struct AnoncredsClaim {
2323
var name: String = ""
2424
var predicate: String = ""
25+
var value: String = ""
2526
}
2627

2728
struct Connection: Identifiable, Hashable {

Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Credentials/CredentialsList/CredentialListViewModel.swift

+34-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ final class CredentialListViewModelImpl: CredentialListViewModel {
101101

102102
Task {
103103
let credentials = try await self.agent.verifiableCredentials().first().await()
104-
guard credentials.isEmpty else {
104+
let linkSecret = try await self.agent.pluto.getLinkSecret().first().await()
105+
guard credentials.isEmpty, linkSecret != nil else {
105106
return
106107
}
107108
try await buildMockCredentials()
@@ -174,6 +175,7 @@ final class CredentialListViewModelImpl: CredentialListViewModel {
174175
try await makeDemoCredentialJWT(value: "aliceTest")
175176
try await makeDemoCredentialJWT(value: "failed")
176177
try await makeDemoCredentialJWT(value: "[email protected]")
178+
// try await makeDemoAnoncredsCredential(value: "")
177179
}
178180

179181
private func makeDemoCredentialJWT(value: String) async throws {
@@ -205,6 +207,37 @@ final class CredentialListViewModelImpl: CredentialListViewModel {
205207
let credential = try JWTCredential(data: jwt.jwtString.tryToData())
206208
try await pluto.storeCredential(credential: credential).first().await()
207209
}
210+
211+
private func makeDemoAnoncredsCredential(value: String) async throws {
212+
let mockedIssuer = MockAnoncredsIssuer()
213+
let offer = try mockedIssuer.createOffer()
214+
guard let linkSecretStorable = try await pluto.getLinkSecret().first().await() else {
215+
throw UnknownError.somethingWentWrongError(customMessage: nil, underlyingErrors: nil)
216+
}
217+
let linkSecret = try await apollo.restoreKey(linkSecretStorable)
218+
219+
let credDef = mockedIssuer.credDef
220+
let defDownloader = MockDownloader(returnData: try credDef.getJson().data(using: .utf8)!)
221+
let schemaDownloader = MockDownloader(returnData: mockedIssuer.getSchemaJson().data(using: .utf8)!)
222+
let prover = MockAnoncredsProver(linkSecret: linkSecret, credDef: credDef)
223+
let request = try prover.createRequest(offer: offer)
224+
let credentialMetadata = try StorableCredentialRequestMetadata(
225+
metadataJson: request.1.getJson().tryData(using: .utf8),
226+
storingId: "1"
227+
)
228+
try await pluto.storeCredential(credential: credentialMetadata).first().await()
229+
let issuedMessage = try mockedIssuer.issueCredential(offer: offer, request: request.0)
230+
let credential = try await agent.pollux.parseCredential(
231+
issuedCredential: issuedMessage,
232+
options: [
233+
.linkSecret(id: "test", secret: linkSecret.raw.tryToString()),
234+
.credentialDefinitionDownloader(downloader: defDownloader),
235+
.schemaDownloader(downloader: schemaDownloader)
236+
]
237+
)
238+
239+
try await pluto.storeCredential(credential: credential.storable!).first().await()
240+
}
208241
}
209242

210243
private func getRequests(messages: [Message]) -> [CredentialListViewState.Requests] {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import AnoncredsSwift
2+
import Domain
3+
import Foundation
4+
5+
struct MockAnoncredsIssuer {
6+
7+
let issuer = "mock:issuer_id/path&q=bar"
8+
let linkSecret: LinkSecret
9+
let schema: Schema
10+
let credDef: CredentialDefinition
11+
let credDefPriv: CredentialDefinitionPrivate
12+
let credDefCorrProof: CredentialKeyCorrectnessProof
13+
14+
init() {
15+
self.linkSecret = try! LinkSecret.newFromValue(valueString: "65965334953670062552662719679603258895632947953618378932199361160021795698890")
16+
17+
self.schema = try! Issuer().createSchema(
18+
schemaName: "mock:uri2",
19+
schemaVersion: "0.1.0",
20+
issuerId: issuer,
21+
attrNames: ["name", "sex", "age"]
22+
)
23+
24+
let credDef = try! Issuer().createCredentialDefinition(
25+
schemaId: schema.name,
26+
schema: schema,
27+
issuerId: issuer,
28+
tag: "tag",
29+
signatureType: .cl,
30+
config: .init(supportRevocation: false)
31+
)
32+
33+
self.credDef = credDef.credentialDefinition
34+
self.credDefPriv = credDef.credentialDefinitionPrivate
35+
self.credDefCorrProof = credDef.credentialKeyCorrectnessProof
36+
}
37+
38+
func createCredDefinition() throws {
39+
let credDef = try! Issuer().createCredentialDefinition(
40+
schemaId: "http://localhost:8000/schemas/test",
41+
schema: schema,
42+
issuerId: issuer,
43+
tag: "test",
44+
signatureType: .cl,
45+
config: .init(supportRevocation: false)
46+
)
47+
}
48+
49+
func createOffer() throws -> CredentialOffer {
50+
try Issuer().createCredentialOffer(
51+
schemaId: "mock:uri2",
52+
credDefId: "mock:uri3",
53+
correctnessProof: credDefCorrProof
54+
)
55+
}
56+
57+
func createOfferMessage() throws -> Message {
58+
let offer = try createOffer().getJson()
59+
60+
return Message(
61+
piuri: "https://didcomm.org/issue-credential/3.0/offer-credential",
62+
body: Data(),
63+
attachments: [
64+
.init(
65+
id: "test1",
66+
mediaType: nil,
67+
data: AttachmentBase64(base64: offer.data(using: .utf8)!.base64EncodedString()),
68+
filename: nil,
69+
format: "anoncreds/[email protected]",
70+
lastmodTime: nil,
71+
byteCount: nil,
72+
description: nil
73+
)
74+
],
75+
thid: "1"
76+
)
77+
}
78+
79+
func issueCredential(
80+
offer: CredentialOffer,
81+
request: CredentialRequest,
82+
name: String = "Test",
83+
sex: String = "M",
84+
age: String = "31"
85+
) throws -> Message {
86+
let issued = try Issuer().createCredential(
87+
credDef: credDef,
88+
credDefPrivate: credDefPriv,
89+
credOffer: offer,
90+
credRequest: request,
91+
credValues: [
92+
.init(raw: "name", encoded: name),
93+
.init(raw: "sex", encoded: sex),
94+
.init(raw: "age", encoded: age)
95+
],
96+
revRegId: nil,
97+
revStatusList: nil,
98+
revocationConfig: nil
99+
).getJson()
100+
101+
return Message(
102+
piuri: "https://didcomm.org/issue-credential/3.0/issue-credential",
103+
body: Data(),
104+
attachments: [
105+
.init(
106+
id: "test1",
107+
mediaType: nil,
108+
data: AttachmentBase64(base64: issued.data(using: .utf8)!.base64EncodedString()),
109+
filename: nil,
110+
format: "anoncreds/[email protected]",
111+
lastmodTime: nil,
112+
byteCount: nil,
113+
description: nil
114+
)
115+
],
116+
thid: "1"
117+
)
118+
}
119+
120+
func createPresentationRequest() throws -> (message: Message, requestStr: String) {
121+
let presentation = """
122+
{"nonce":"1103253414365527824079144","name":"proof_req_1","version":"0.1","requested_attributes":{"sex":{"name":"sex", "restrictions":{"attr::sex::value":"M","cred_def_id":"mock:uri3"}}},"requested_predicates":{"age":{"name":"age", "p_type":">=", "p_value":18}}}
123+
"""
124+
return (Message(
125+
piuri: "",
126+
body: Data(),
127+
attachments: [
128+
.init(
129+
data: AttachmentBase64(base64: try presentation.tryData(using: .utf8).base64EncodedString())
130+
)
131+
]
132+
), presentation)
133+
}
134+
135+
func getSchemaJson() -> String {
136+
"""
137+
{"name":"\(schema.name)","issuerId":"\(schema.issuerId)","version":"\(schema.version)","attrNames":["name", "sex", "age"]}
138+
"""
139+
}
140+
141+
func verifyPresentation(presentation: String, request: String) throws -> Bool {
142+
let presentation = try Presentation(jsonString: presentation)
143+
let request = try PresentationRequest(jsonString: request)
144+
let credDef = self.credDef
145+
let schema = self.schema
146+
return try Verifier().verifyPresentation(
147+
presentation: presentation,
148+
presentationRequest: request,
149+
schemas: ["mock:uri2": schema],
150+
credentialDefinitions: ["mock:uri3": credDef]
151+
)
152+
}
153+
}
154+
155+
struct MockDownloader: Downloader {
156+
let returnData: Data
157+
func downloadFromEndpoint(urlOrDID: String) async throws -> Data {
158+
return returnData
159+
}
160+
}
161+
162+
struct MockAnoncredsProver {
163+
let did = "did:test:adsadiada"
164+
let linkSecret: Key
165+
let credDef: CredentialDefinition
166+
167+
init(linkSecret: Key, credDef: CredentialDefinition) {
168+
self.linkSecret = linkSecret
169+
self.credDef = credDef
170+
}
171+
172+
func createRequest(offer: CredentialOffer) throws -> (CredentialRequest, CredentialRequestMetadata) {
173+
let result = try Prover().createCredentialRequest(
174+
entropy: "did",
175+
proverDid: nil,
176+
credDef: credDef,
177+
linkSecret: try AnoncredsSwift.LinkSecret.newFromValue(valueString: linkSecret.raw.tryToString()),
178+
linkSecretId: "test",
179+
credentialOffer: offer
180+
)
181+
return (result.request, result.metadata)
182+
}
183+
}

Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Messages/MessageDetail/MessageDetailViewModel.swift

+4
Original file line numberDiff line numberDiff line change
@@ -259,5 +259,9 @@ private func getTitle(for protocolType: ProtocolTypes) -> String {
259259
return "Pickup Received"
260260
case .didcommCredentialPreview3_0:
261261
return "Credential Preview"
262+
case .didcommRevocationNotification:
263+
return "Revocation Notification"
264+
case .didcommReportProblem:
265+
return "Problem Reporting"
262266
}
263267
}

Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Messages/MessagesList/MessagesListViewModel.swift

+4
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ final class MessagesListViewModelImpl: MessageListViewModel {
101101
return "Pickup Received"
102102
case .didcommCredentialPreview3_0:
103103
return "Credential Preview"
104+
case .didcommRevocationNotification:
105+
return "Revocation Notification"
106+
case .didcommReportProblem:
107+
return "Report Problem"
104108
}
105109
}
106110

0 commit comments

Comments
 (0)