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

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

26 Sep 2024 09:51AM UTC coverage: 42.623% (+1.9%) from 40.771%
11052319165

push

github

goncalo-frade-iohk
feat(edgeagent): adds support for connectionless issuance and presentation

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

70 of 134 new or added lines in 19 files covered. (52.24%)

2 existing lines in 2 files now uncovered.

5460 of 12810 relevant lines covered (42.62%)

100.02 hits per line

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

58.33
/EdgeAgentSDK/EdgeAgent/Sources/DIDCommAgent/DIDCommAgent+Invitations.swift
1
import Domain
2
import Foundation
3

4
public extension DIDCommAgent {
5
    /// Enumeration representing the type of invitation
6
    enum InvitationType {
7
        /// Struct representing a Prism Onboarding invitation
8
        public struct PrismOnboarding {
9
            /// Sender of the invitation
10
            public let from: String
11
            /// Onboarding endpoint
12
            public let endpoint: URL
13
            /// The own DID of the user
14
            public let ownDID: DID
15
        }
16

17
        /// Case representing a Prism Onboarding invitation
18
        case onboardingPrism(PrismOnboarding)
19
        /// Case representing a DIDComm Out-of-Band invitation
20
        case onboardingDIDComm(OutOfBandInvitation)
21
        /// Case representing a DIDComm Connectionless Presentation
22
        case connectionlessPresentation(RequestPresentation)
23
        /// Case representing a DIDComm Connectionless Issuance
24
        case connectionlessIssuance(OfferCredential3_0)
25
    }
26

27
    /// Parses the given string as an Out-of-Band invitation
28
    /// - Parameter url: The string to parse
29
    /// - Returns: The parsed Out-of-Band invitation
30
    /// - Throws: `EdgeAgentError` if the string is not a valid URL
31
    func parseOOBInvitation(url: String) throws -> OutOfBandInvitation {
6✔
32
        guard let messageData = Data(fromBase64URL: url) else {
6✔
33
            guard let url = URL(string: url) else {
2✔
NEW
34
                throw CommonError.invalidURLError(url: url)
×
35
            }
2✔
36
            return try parseOOBInvitation(url: url)
2✔
37
        }
4✔
38
        let message = try JSONDecoder.didComm().decode(OutOfBandInvitation.self, from: messageData)
4✔
39
        guard message.type == ProtocolTypes.didcomminvitation.rawValue else {
4✔
NEW
40
            throw EdgeAgentError.unknownInvitationTypeError
×
41
        }
4✔
42
        return message
4✔
43
    }
4✔
44

45
    /// Parses the given URL as an Out-of-Band invitation
46
    /// - Parameter url: The URL to parse
47
    /// - Returns: The parsed Out-of-Band invitation
48
    /// - Throws: `EdgeAgentError` if the URL is not a valid Out-of-Band invitation
49
    func parseOOBInvitation(url: URL) throws -> OutOfBandInvitation {
2✔
50
        return try DIDCommInvitationRunner(url: url).run()
2✔
51
    }
2✔
52

53
    /// Accepts a Prism Onboarding invitation and performs the onboarding process
54
    /// - Parameter invitation: The Prism Onboarding invitation to accept
55
    /// - Throws: `EdgeAgentError` if the onboarding process fails
56
    func acceptPrismInvitation(invitation: InvitationType.PrismOnboarding) async throws {
×
57
        struct SendDID: Encodable {
×
58
            let did: String
×
59
        }
×
60
        var request = URLRequest(url: invitation.endpoint)
×
61
        request.httpMethod = "POST"
×
62
        request.httpBody = try JSONEncoder().encode(SendDID(did: invitation.ownDID.string))
×
63
        request.setValue("application/json", forHTTPHeaderField: "content-type")
×
64
        do {
×
65
            let response = try await URLSession.shared.data(for: request)
×
66
            guard let urlResponse = response.1 as? HTTPURLResponse else {
×
67
                throw CommonError.invalidCoding(
×
68
                    message: "This should not happen cannot convert URLResponse to HTTPURLResponse"
×
69
                )
×
70
            }
×
71
            guard urlResponse.statusCode == 200 else {
×
72
                throw CommonError.httpError(
×
73
                    code: urlResponse.statusCode,
×
74
                    message: String(data: response.0, encoding: .utf8) ?? ""
×
75
                )
×
76
            }
×
77
        }
×
78
    }
×
79

80
    /// Parses the given string as an invitation
81
    /// - Parameter str: The string to parse
82
    /// - Returns: The parsed invitation
83
    /// - Throws: `EdgeAgentError` if the invitation is not a valid Prism or OOB type
84
    func parseInvitation(str: String) async throws -> InvitationType {
6✔
85
        if let prismOnboarding = try? await parsePrismInvitation(str: str) {
6✔
86
            return .onboardingPrism(prismOnboarding)
×
87
        } else if let oobMessage = try? parseOOBInvitation(url: str) {
6✔
88
            if let attachment = oobMessage.attachments?.first {
6✔
89
                let invitationType = try await parseAttachmentConnectionlessMessage(oob: oobMessage, attachment: attachment)
4✔
90
                switch invitationType {
4✔
91
                case .connectionlessPresentation(let message):
4✔
92
                    try await pluto.storeMessage(
2✔
93
                        message: message.makeMessage(),
2✔
94
                        direction: .received
2✔
95
                    ).first().await()
2✔
96
                case .connectionlessIssuance(let message):
4✔
97
                    try await pluto.storeMessage(
2✔
98
                        message: message.makeMessage(),
2✔
99
                        direction: .received
2✔
100
                    ).first().await()
2✔
101
                default:
4✔
NEW
102
                    break
×
103
                }
4✔
104
                return invitationType
4✔
105
            }
4✔
106
            return .onboardingDIDComm(oobMessage)
2✔
107
        }
6✔
108
        throw EdgeAgentError.unknownInvitationTypeError
×
109
    }
6✔
110

111
    /// Parses the given string as a Prism Onboarding invitation
112
    /// - Parameter str: The string to parse
113
    /// - Returns: The parsed Prism Onboarding invitation
114
    /// - Throws: `EdgeAgentError` if the string is not a valid Prism Onboarding invitation
115
    func parsePrismInvitation(
116
        str: String
117
    ) async throws -> InvitationType.PrismOnboarding {
6✔
118
        let prismOnboarding = try PrismOnboardingInvitation(jsonString: str)
6✔
119
        guard
6✔
120
            let url = URL(string: prismOnboarding.body.onboardEndpoint)
6✔
121
        else { throw CommonError.invalidURLError(url: prismOnboarding.body.onboardEndpoint) }
6✔
122

6✔
123
        let ownDID = try await createNewPeerDID(
6✔
124
            services: [.init(
6✔
125
                id: "#didcomm-1",
6✔
126
                type: ["DIDCommMessaging"],
6✔
127
                serviceEndpoint: [.init(
6✔
128
                    uri: "https://localhost:8080/didcomm"
6✔
129
                )]
6✔
130
            )],
6✔
131
            updateMediator: false
6✔
132
        )
6✔
133

6✔
134
        return .init(
6✔
135
            from: prismOnboarding.body.from,
6✔
136
            endpoint: url,
6✔
137
            ownDID: ownDID
6✔
138
        )
6✔
139
    }
6✔
140

141
    /// Accepts an Out-of-Band (DIDComm) invitation and establishes a new connection
142
    /// - Parameter invitation: The Out-of-Band invitation to accept
143
    /// - Throws: `EdgeAgentError` if there is no mediator available or other errors occur during the acceptance process
144
    func acceptDIDCommInvitation(invitation: OutOfBandInvitation) async throws {
×
145
        guard
×
146
            let connectionManager
×
147
        else { throw EdgeAgentError.noMediatorAvailableError }
×
148
        logger.info(message: "Start accept DIDComm invitation")
×
149
        let ownDID = try await createNewPeerDID(updateMediator: true)
×
150

×
151
        logger.info(message: "Sending DIDComm Connection message")
×
152

×
153
        let pair = try await DIDCommConnectionRunner(
×
154
            invitationMessage: invitation,
×
155
            pluto: pluto,
×
156
            ownDID: ownDID,
×
157
            connection: connectionManager
×
158
        ).run()
×
159
        try await connectionManager.addConnection(pair)
×
160
    }
×
161

162
    private func parseAttachmentConnectionlessMessage(
163
        oob: OutOfBandInvitation,
164
        attachment: AttachmentDescriptor
165
    ) async throws -> InvitationType {
4✔
166
        let newDID = try await createNewPeerDID(updateMediator: true)
4✔
167
        switch attachment.data {
4✔
168
        case let value as AttachmentJsonData:
4✔
169
            let normalizeJson = try JSONEncoder.didComm().encode(value.json)
4✔
170
            let message = try JSONDecoder.didComm().decode(Message.self, from: normalizeJson)
4✔
171
            if let request = try? RequestPresentation(fromMessage: message, toDID: newDID) {
4✔
172
                return .connectionlessPresentation(request)
2✔
173
            }
2✔
174
            else if let offer = try? OfferCredential3_0(fromMessage: message, toDID: newDID){
2✔
175
                return .connectionlessIssuance(offer)
2✔
176
            }
2✔
NEW
177
            return .onboardingDIDComm(oob)
×
178

4✔
179
        case let value as AttachmentBase64:
4✔
NEW
180
            let message = try JSONDecoder.didComm().decode(Message.self, from: try value.decoded())
×
NEW
181
            if let request = try? RequestPresentation(fromMessage: message, toDID: newDID) {
×
NEW
182
                return .connectionlessPresentation(request)
×
NEW
183
            }
×
NEW
184
            else if let offer = try? OfferCredential3_0(fromMessage: message, toDID: newDID){
×
NEW
185
                return .connectionlessIssuance(offer)
×
NEW
186
            }
×
NEW
187
            return .onboardingDIDComm(oob)
×
188
        default:
4✔
NEW
189
            return .onboardingDIDComm(oob)
×
190
        }
4✔
191
    }
4✔
192
}
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

© 2025 Coveralls, Inc