• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hyperledger / identus-edge-agent-sdk-swift / 11049785480

25 Sep 2024 02:40PM UTC coverage: 40.771% (-3.2%) from 43.981%
11049785480

push

github

goncalo-frade-iohk
feat!(agent): agent separation of concerns

BREAKING CHANGE: This is a refactor, from now on the EdgeAgent will not have any reference with DIDComm and a DIDCommAgent will replace this.
EdgeAgent now will scope all the logic that is inherent to it removing any transport layer association, and new agents like DIDCommAgent will scope the EdgeAgent functionalities for a transport layer.

With this Pollux also has some significant changes so it is not aggregated to the DIDComm Message.

OIDCAgent will take part of OIDC transport layer communication.

Signed-off-by: goncalo-frade-iohk <goncalo.frade@iohk.io>

232 of 1063 new or added lines in 19 files covered. (21.83%)

187 existing lines in 14 files now uncovered.

5193 of 12737 relevant lines covered (40.77%)

97.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

16.6
/EdgeAgentSDK/EdgeAgent/Sources/DIDCommAgent/DIDCommAgent+Credentials.swift
1
import Core
2
import Combine
3
import Domain
4
import Foundation
5
import Logging
6
import JSONWebToken
7

8
public extension DIDCommAgent {
9

10
    /// This function initiates a presentation request for a specific type of credential, specifying the sender's and receiver's DIDs, and any claim filters applicable.
11
    ///
12
    /// - Parameters:
13
    ///   - type: The type of the credential for which the presentation is requested.
14
    ///   - fromDID: The decentralized identifier (DID) of the entity initiating the request.
15
    ///   - toDID: The decentralized identifier (DID) of the entity to which the request is being sent.
16
    ///   - claimFilters: A collection of filters specifying the claims required in the credential.
17
    /// - Returns: The initiated request for presentation.
18
    /// - Throws: EdgeAgentError, if there is a problem initiating the presentation request.
19
    func initiatePresentationRequest(
20
        type: CredentialType,
21
        fromDID: DID,
22
        toDID: DID,
23
        claimFilters: [ClaimFilter]
24
    ) async throws -> RequestPresentation {
8✔
25
        let rqstStr = try await edgeAgent.initiatePresentationRequest(
8✔
26
            type: type,
8✔
27
            fromDID: fromDID,
8✔
28
            toDID: toDID,
8✔
29
            claimFilters: claimFilters
8✔
30
        )
8✔
31
        let attachment: AttachmentDescriptor
8✔
32
        switch type {
8✔
33
        case .jwt:
8✔
34
            let data = try AttachmentBase64(base64: rqstStr.tryToData().base64URLEncoded())
6✔
35
            attachment = AttachmentDescriptor(
6✔
36
                mediaType: "application/json",
6✔
37
                data: data,
6✔
38
                format: "dif/presentation-exchange/definitions@v1.0"
6✔
39
            )
6✔
40
        case .anoncred:
8✔
41
            let data = try AttachmentBase64(base64: rqstStr.tryToData().base64URLEncoded())
2✔
42
            attachment = AttachmentDescriptor(
2✔
43
                mediaType: "application/json",
2✔
44
                data: data,
2✔
45
                format: "anoncreds/proof-request@v1.0"
2✔
46
            )
2✔
47
        }
8✔
48

8✔
49
        return RequestPresentation(
8✔
50
            body: .init(
8✔
51
                proofTypes: [ProofTypes(
8✔
52
                    schema: "",
8✔
53
                    requiredFields: claimFilters.flatMap(\.paths),
10✔
54
                    trustIssuers: nil
8✔
55
                )]
8✔
56
            ),
8✔
57
            attachments: [attachment],
8✔
58
            thid: nil,
8✔
59
            from: fromDID,
8✔
60
            to: toDID
8✔
61
        )
8✔
62
    }
8✔
63

64
    /// This function verifies the presentation contained within a message.
65
    ///
66
    /// - Parameters:
67
    ///   - message: The message containing the presentation to be verified.
68
    /// - Returns: A Boolean value indicating whether the presentation is valid (`true`) or not (`false`).
69
    /// - Throws: EdgeAgentError, if there is a problem verifying the presentation.
70

NEW
71
    func verifyPresentation(message: Message) async throws -> Bool {
×
NEW
72
        do {
×
NEW
73
            let downloader = DownloadDataWithResolver(castor: castor)
×
NEW
74
            guard
×
NEW
75
                let attachment = message.attachments.first,
×
NEW
76
                let requestId = message.thid
×
NEW
77
            else {
×
NEW
78
                throw PolluxError.couldNotFindPresentationInAttachments
×
NEW
79
            }
×
NEW
80

×
NEW
81
            let jsonData: Data
×
NEW
82
            switch attachment.data {
×
NEW
83
            case let attchedData as AttachmentBase64:
×
NEW
84
                guard let decoded = Data(fromBase64URL: attchedData.base64) else {
×
NEW
85
                    throw CommonError.invalidCoding(message: "Invalid base64 url attachment")
×
NEW
86
                }
×
NEW
87
                jsonData = decoded
×
NEW
88
            case let attchedData as AttachmentJsonData:
×
NEW
89
                jsonData = attchedData.data
×
NEW
90
            default:
×
NEW
91
                throw EdgeAgentError.invalidAttachmentFormat(nil)
×
NEW
92
            }
×
NEW
93

×
NEW
94
            guard let format = attachment.format else {
×
NEW
95
                throw EdgeAgentError.invalidAttachmentFormat(nil)
×
NEW
96
            }
×
NEW
97

×
NEW
98
            return try await pollux.verifyPresentation(
×
NEW
99
                type: format,
×
NEW
100
                presentationPayload: jsonData,
×
NEW
101
                options: [
×
NEW
102
                    .presentationRequestId(requestId),
×
NEW
103
                    .credentialDefinitionDownloader(downloader: downloader),
×
NEW
104
                    .schemaDownloader(downloader: downloader)
×
NEW
105
            ])
×
NEW
106
        } catch {
×
NEW
107
            logger.error(error: error)
×
NEW
108
            throw error
×
NEW
109
        }
×
NEW
110
    }
×
111

112
    /// This function parses an issued credential message, stores and returns the verifiable credential.
113
    ///
114
    /// - Parameters:
115
    ///   - message: Issue credential Message.
116
    /// - Returns: The parsed verifiable credential.
117
    /// - Throws: EdgeAgentError, if there is a problem parsing the credential.
NEW
118
    func processIssuedCredentialMessage(message: IssueCredential3_0) async throws -> Credential {
×
NEW
119
        guard
×
NEW
120
            let linkSecret = try await pluto.getLinkSecret().first().await()
×
NEW
121
        else { throw EdgeAgentError.cannotFindDIDKeyPairIndex }
×
NEW
122

×
NEW
123
        let restored = try await self.apollo.restoreKey(linkSecret)
×
NEW
124
        guard
×
NEW
125
            let linkSecretString = String(data: restored.raw, encoding: .utf8)
×
NEW
126
        else { throw EdgeAgentError.cannotFindDIDKeyPairIndex }
×
NEW
127

×
NEW
128
        let downloader = DownloadDataWithResolver(castor: castor)
×
NEW
129
        guard 
×
NEW
130
            let attachment = message.attachments.first,
×
NEW
131
            let format = attachment.format
×
NEW
132
        else {
×
NEW
133
            throw PolluxError.unsupportedIssuedMessage
×
NEW
134
        }
×
NEW
135

×
NEW
136
        let jsonData: Data
×
NEW
137
        switch attachment.data {
×
NEW
138
        case let attchedData as AttachmentBase64:
×
NEW
139
            guard let decoded = Data(fromBase64URL: attchedData.base64) else {
×
NEW
140
                throw CommonError.invalidCoding(message: "Invalid base64 url attachment")
×
NEW
141
            }
×
NEW
142
            jsonData = decoded
×
NEW
143
        case let attchedData as AttachmentJsonData:
×
NEW
144
            jsonData = attchedData.data
×
NEW
145
        default:
×
NEW
146
            throw EdgeAgentError.invalidAttachmentFormat(nil)
×
NEW
147
        }
×
NEW
148

×
NEW
149
        let credential = try await pollux.parseCredential(
×
NEW
150
            type: format,
×
NEW
151
            credentialPayload: jsonData,
×
NEW
152
            options: [
×
NEW
153
                .linkSecret(id: "", secret: linkSecretString),
×
NEW
154
                .credentialDefinitionDownloader(downloader: downloader),
×
NEW
155
                .schemaDownloader(downloader: downloader)
×
NEW
156
            ]
×
NEW
157
        )
×
NEW
158

×
NEW
159
        guard let storableCredential = credential.storable else {
×
NEW
160
            return credential
×
NEW
161
        }
×
NEW
162
        try await pluto
×
NEW
163
            .storeCredential(credential: storableCredential)
×
NEW
164
            .first()
×
NEW
165
            .await()
×
NEW
166
        return credential
×
NEW
167
    }
×
168

169
    /// This function prepares a request credential from an offer given the subject DID.
170
    ///
171
    /// - Parameters:
172
    ///   - did: Subject DID.
173
    ///   - did: Received offer credential.
174
    /// - Returns: Created request credential
175
    /// - Throws: EdgeAgentError, if there is a problem creating the request credential.
NEW
176
    func prepareRequestCredentialWithIssuer(did: DID, offer: OfferCredential3_0) async throws -> RequestCredential3_0? {
×
NEW
177
        guard did.method == "prism" else { throw PolluxError.invalidPrismDID }
×
NEW
178
        let didInfo = try await pluto
×
NEW
179
            .getDIDInfo(did: did)
×
NEW
180
            .first()
×
NEW
181
            .await()
×
NEW
182

×
NEW
183
        guard let storedPrivateKey = didInfo?.privateKeys.first else { throw EdgeAgentError.cannotFindDIDKeyPairIndex }
×
NEW
184

×
NEW
185
        let privateKey = try await apollo.restorePrivateKey(storedPrivateKey)
×
NEW
186

×
NEW
187
        guard
×
NEW
188
            let exporting = privateKey.exporting,
×
NEW
189
            let linkSecret = try await pluto.getLinkSecret().first().await()
×
NEW
190
        else { throw EdgeAgentError.cannotFindDIDKeyPairIndex }
×
NEW
191

×
NEW
192
        let restored = try await self.apollo.restoreKey(linkSecret)
×
NEW
193
        guard
×
NEW
194
            let linkSecretString = String(data: restored.raw, encoding: .utf8)
×
NEW
195
        else { throw EdgeAgentError.cannotFindDIDKeyPairIndex }
×
NEW
196

×
NEW
197
        let downloader = DownloadDataWithResolver(castor: castor)
×
NEW
198
        guard
×
NEW
199
            let attachment = offer.attachments.first,
×
NEW
200
            let offerFormat = attachment.format
×
NEW
201
        else {
×
NEW
202
            throw PolluxError.unsupportedIssuedMessage
×
NEW
203
        }
×
NEW
204

×
NEW
205
        let jsonData: Data
×
NEW
206
        switch attachment.data {
×
NEW
207
        case let attchedData as AttachmentBase64:
×
NEW
208
            guard let decoded = Data(fromBase64URL: attchedData.base64) else {
×
NEW
209
                throw CommonError.invalidCoding(message: "Invalid base64 url attachment")
×
NEW
210
            }
×
NEW
211
            jsonData = decoded
×
NEW
212
        case let attchedData as AttachmentJsonData:
×
NEW
213
            jsonData = attchedData.data
×
NEW
214
        default:
×
NEW
215
            throw EdgeAgentError.invalidAttachmentFormat(nil)
×
NEW
216
        }
×
NEW
217
        let requestString = try await pollux.processCredentialRequest(
×
NEW
218
            type: offerFormat,
×
NEW
219
            offerPayload: jsonData,
×
NEW
220
            options: [
×
NEW
221
                .exportableKey(exporting),
×
NEW
222
                .subjectDID(did),
×
NEW
223
                .linkSecret(id: did.string, secret: linkSecretString),
×
NEW
224
                .credentialDefinitionDownloader(downloader: downloader),
×
NEW
225
                .schemaDownloader(downloader: downloader)
×
NEW
226
            ]
×
NEW
227
        )
×
NEW
228

×
NEW
229
        guard
×
NEW
230
            let base64String = requestString.data(using: .utf8)?.base64EncodedString()
×
NEW
231
        else {
×
NEW
232
            throw CommonError.invalidCoding(message: "Could not encode to base64")
×
NEW
233
        }
×
NEW
234
        guard
×
NEW
235
            let offerPiuri = ProtocolTypes(rawValue: offer.type)
×
NEW
236
        else {
×
NEW
237
            throw EdgeAgentError.invalidMessageType(
×
NEW
238
                type: offer.type,
×
NEW
239
                shouldBe: [
×
NEW
240
                    ProtocolTypes.didcommOfferCredential3_0.rawValue
×
NEW
241
                ]
×
NEW
242
            )
×
NEW
243
        }
×
NEW
244
        let format: String
×
NEW
245
        switch offerFormat {
×
NEW
246
        case "prism/jwt":
×
NEW
247
            format = "prism/jwt"
×
NEW
248
        case "vc+sd-jwt":
×
NEW
249
            format = "vc+sd-jwt"
×
NEW
250
        case "anoncreds/credential-offer@v1.0":
×
NEW
251
            format = "anoncreds/credential-request@v1.0"
×
NEW
252
        default:
×
NEW
253
            throw EdgeAgentError.invalidMessageType(
×
NEW
254
                type: offerFormat,
×
NEW
255
                shouldBe: [
×
NEW
256
                    "prism/jwt",
×
NEW
257
                    "anoncreds/credential-offer@v1.0"
×
NEW
258
                ]
×
NEW
259
            )
×
NEW
260
        }
×
NEW
261

×
NEW
262
        let type = offerPiuri == .didcommOfferCredential ?
×
NEW
263
            ProtocolTypes.didcommRequestCredential :
×
NEW
264
            ProtocolTypes.didcommRequestCredential3_0
×
NEW
265

×
NEW
266
        let requestCredential = RequestCredential3_0(
×
NEW
267
            body: .init(
×
NEW
268
                goalCode: offer.body.goalCode,
×
NEW
269
                comment: offer.body.comment
×
NEW
270
            ),
×
NEW
271
            type: type.rawValue,
×
NEW
272
            attachments: [.init(
×
NEW
273
                data: AttachmentBase64(base64: base64String),
×
NEW
274
                format: format
×
NEW
275
            )],
×
NEW
276
            thid: offer.thid,
×
NEW
277
            from: offer.to,
×
NEW
278
            to: offer.from
×
NEW
279
        )
×
NEW
280
        return requestCredential
×
NEW
281
    }
×
282
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc