diff --git a/Package.swift b/Package.swift index 704031c..5eb0c10 100644 --- a/Package.swift +++ b/Package.swift @@ -20,12 +20,10 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/swift-libp2p/swift-multibase.git", .upToNextMajor(from: "0.0.1")), - .package(url: "https://github.com/beatt83/didcore-swift.git", .upToNextMinor(from: "1.1.0")), + .package(url: "https://github.com/beatt83/didcore-swift.git", .upToNextMinor(from: "2.0.0")), .package(url: "https://github.com/beatt83/jose-swift.git", .upToNextMinor(from: "2.2.1")) ], targets: [ - // Targets are the basic building blocks of a package, defining a module or a test suite. - // Targets can depend on other targets in this package and products from dependencies. .target( name: "DIDCommSwift", dependencies: [ diff --git a/Sources/DIDCommSwift/Models/Routing/ServiceTree.swift b/Sources/DIDCommSwift/Models/Routing/ServiceTree.swift index 2550567..022ce06 100644 --- a/Sources/DIDCommSwift/Models/Routing/ServiceTree.swift +++ b/Sources/DIDCommSwift/Models/Routing/ServiceTree.swift @@ -89,7 +89,7 @@ private func buildBranchsTree( private func getRoutingURIAndKeys(document: DIDDocument) throws -> [(uri: String, keys: [String])] { try document.services? - .first { $0.type.contains("DIDCommMessaging") } + .first { (try? $0.toDIDCommService()) != nil } .map { try $0.toDIDCommService().serviceEndpoint .map { ($0.uri, $0.routingKeys) } @@ -98,71 +98,172 @@ private func getRoutingURIAndKeys(document: DIDDocument) throws -> [(uri: String private func getRoutingKeys(document: DIDDocument) throws -> [String] { try document.services? - .first { $0.type.contains("DIDCommMessaging") } + .first { (try? $0.toDIDCommService()) != nil } .flatMap { try $0.toDIDCommService().serviceEndpoint .flatMap(\.routingKeys) } ?? [] } -private extension DIDDocument.Service { +private extension AnyCodable { func toDIDCommService() throws -> Routing.DIDCommService { - guard self.type == didcommServiceType else { - throw DIDCommError.notDidCommServiceType + guard + let dic = value as? [String: Any], + let id = dic["id"] as? String, + let type = dic["type"] as? String, + type == didcommServiceType, + let serviceEndpoint = dic["serviceEndpoint"] + else { throw DIDCommError.notDidCommServiceType } + + switch serviceEndpoint { + case let endpoint as String: + return try parseServiceString(id: id, type: type, service: endpoint) + case let endpoint as [String]: + return try parseServiceStringArray(id: id, type: type, service: endpoint) + case let endpoint as [String: Any]: + return try parseServiceDic(id: id, type: type, service: endpoint) + case let endpoint as [[String: Any]]: + return try parseServiceArrayDic(id: id, type: type, service: endpoint) + case let endpoint as AnyCodable: + return try parseServiceAnyCodable(id: id, type: type, service: endpoint) + case let endpoint as [AnyCodable]: + return try parseServiceAnyCodableArray(id: id, type: type, service: endpoint) + default: + return .init( + id: id, + type: type, + serviceEndpoint: [] + ) + } + } + + func parseServiceString(id: String, type: String, service: String) throws -> Routing.DIDCommService { + return .init( + id: id, + type: type, + serviceEndpoint: [ + .init(uri: service, accept: [], routingKeys: []) + ] + ) + } + + func parseServiceStringArray(id: String, type: String, service: [String]) throws -> Routing.DIDCommService { + return .init( + id: id, + type: type, + serviceEndpoint: service.map { + .init(uri: $0, accept: [], routingKeys: []) + } + ) + } + + func parseServiceDic(id: String, type: String, service: [String: Any]) throws -> Routing.DIDCommService { + guard let uri = service["uri"] as? String else { + throw DIDCommError.missingUri } - switch self.serviceEndpoint.value { + return .init( + id: id, + type: type, + serviceEndpoint: [ + .init( + uri: uri, + accept: (service["accept"] as? [String]) ?? [], + routingKeys: (service["routing_keys"] as? [String]) ?? [] + ) + ] + ) + } + + func parseServiceArrayDic(id: String, type: String, service: [[String: Any]]) throws -> Routing.DIDCommService { + return .init( + id: id, + type: type, + serviceEndpoint: try service.map { + guard let uri = $0["uri"] as? String else { + throw DIDCommError.missingUri + } + return .init( + uri: uri, + accept: ($0["accept"] as? [String]) ?? [], + routingKeys: ($0["routing_keys"] as? [String]) ?? [] + ) + } + ) + } + + func parseServiceAnyCodableArray(id: String, type: String, service: [AnyCodable]) throws -> Routing.DIDCommService { + return .init( + id: id, + type: type, + serviceEndpoint: try service.flatMap { try parseServiceEndpoint(serviceEndpoint: $0) } + ) + } + + func parseServiceAnyCodable(id: String, type: String, service: AnyCodable) throws -> Routing.DIDCommService { + switch service.value { case let value as String: + return try parseServiceString(id: id, type: type, service: value) + case let value as [String]: + return try parseServiceStringArray(id: id, type: type, service: value) + case let value as [String: Any]: + return try parseServiceDic(id: id, type: type, service: value) + case let value as [[String: Any]]: + return try parseServiceArrayDic(id: id, type: type, service: value) + case let value as AnyCodable: return .init( - id: self.id, - type: self.type, - serviceEndpoint: [ - .init(uri: value, accept: [], routingKeys: []) - ] + id: id, + type: type, + serviceEndpoint: try parseServiceEndpoint(serviceEndpoint: value) ) - case let value as [String]: + case let value as [AnyCodable]: return .init( - id: self.id, - type: self.type, - serviceEndpoint: value.map { - .init(uri: $0, accept: [], routingKeys: []) - } + id: id, + type: type, + serviceEndpoint: try value.flatMap { try parseServiceEndpoint(serviceEndpoint: $0) } ) + default: + return .init( + id: id, + type: type, + serviceEndpoint: [] + ) + } + } + + func parseServiceEndpoint(serviceEndpoint: AnyCodable) throws -> [Routing.DIDCommService.ServiceEndpoint] { + switch serviceEndpoint.value { + case let value as String: + return [ + .init(uri: value, accept: [], routingKeys: []) + ] + case let value as [String]: + return value.map { + .init(uri: $0, accept: [], routingKeys: []) + } case let value as [String: Any]: guard let uri = value["uri"] as? String else { throw DIDCommError.missingUri } - return .init( - id: self.id, - type: self.type, - serviceEndpoint: [ - .init( - uri: uri, - accept: (value["accept"] as? [String]) ?? [], - routingKeys: (value["routing_keys"] as? [String]) ?? [] - ) - ] - ) + return [ + .init( + uri: uri, + accept: (value["accept"] as? [String]) ?? [], + routingKeys: (value["routing_keys"] as? [String]) ?? [] + ) + ] case let value as [[String: Any]]: - return .init( - id: self.id, - type: self.type, - serviceEndpoint: try value.map { - guard let uri = $0["uri"] as? String else { - throw DIDCommError.missingUri - } - return .init( - uri: uri, - accept: ($0["accept"] as? [String]) ?? [], - routingKeys: ($0["routing_keys"] as? [String]) ?? [] - ) + return try value.map { + guard let uri = $0["uri"] as? String else { + throw DIDCommError.missingUri } - ) + return .init( + uri: uri, + accept: ($0["accept"] as? [String]) ?? [], + routingKeys: ($0["routing_keys"] as? [String]) ?? [] + ) + } default: - return .init( - id: self.id, - type: self.type, - serviceEndpoint: [] - ) + return [] } } } diff --git a/Tests/DIDCommSwiftTests/TestData/Mock/DIDAliceMockData.swift b/Tests/DIDCommSwiftTests/TestData/Mock/DIDAliceMockData.swift index 26b5ef4..5f6c720 100644 --- a/Tests/DIDCommSwiftTests/TestData/Mock/DIDAliceMockData.swift +++ b/Tests/DIDCommSwiftTests/TestData/Mock/DIDAliceMockData.swift @@ -157,15 +157,23 @@ let aliceAuthMethodSecp256k1 = DIDDocument.VerificationMethod( ) ) -let aliceServiceRoutingKeys = DIDDocument.Service( - id: "service1", - type: "DIDCommMessaging", - serviceEndpoint: AnyCodable(dictionaryLiteral: - ("uri", "http://didcomm.com"), - ("accept", [String]()), - ("routing_keys", ["did:example:alice#key-x25519-1"]) - ) -) +//let aliceServiceEndpoint = AnyCodable(dictionaryLiteral: +// ("uri", "http://didcomm.com"), +// ("accept", [String]()), +// ("routing_keys", ["did:example:alice#key-x25519-1"]) +// ) + +let aliceServiceRoutingKeysDic = [ + "id": "service1", + "type": "DIDCommMessaging", + "serviceEndpoint": [ + "uri": "http://didcomm.com", + "accept": [String](), + "routing_keys": ["did:example:alice#key-x25519-1"] + ] +] as! [String: Any] + +let aliceServiceRoutingKeys = AnyCodable(aliceServiceRoutingKeysDic) let didDocAliceSpecTestVectors = DIDDocument( id: "did:example:alice", diff --git a/Tests/DIDCommSwiftTests/TestData/Mock/DIDBobMockData.swift b/Tests/DIDCommSwiftTests/TestData/Mock/DIDBobMockData.swift index 192852e..93f4e3c 100644 --- a/Tests/DIDCommSwiftTests/TestData/Mock/DIDBobMockData.swift +++ b/Tests/DIDCommSwiftTests/TestData/Mock/DIDBobMockData.swift @@ -365,34 +365,82 @@ let bobServiceMultipleMediators = DIDDocument.Service( ) ) -let bobMediatorServices1 = DIDDocument.Service( - id: "service1", - type: "DIDCommMessaging", - serviceEndpoint: AnyCodable(dictionaryLiteral: - ("uri", "http://didcomm.com"), - ("accept", [String]()), - ("routing_keys", [String]()) - ) +let bobServiceEndpoint1 = AnyCodable(dictionaryLiteral: + ("uri", "http://didcomm.com"), + ("accept", [String]()), + ("routing_keys", [String]()) ) -let bobMediatorServices2 = DIDDocument.Service( - id: "service1", - type: "DIDCommMessaging", - serviceEndpoint: AnyCodable(dictionaryLiteral: - ("uri", "http://didcomm.com"), - ("accept", [String]()), - ("routing_keys", ["did:example:bob#key-x25519-1"]) - ) +let bobServiceEndpoint2 = AnyCodable(dictionaryLiteral: + ("uri", "http://didcomm.com"), + ("accept", [String]()), + ("routing_keys", ["did:example:bob#key-x25519-1"]) ) -let bobMediatorServices3 = DIDDocument.Service( - id: "service1", - type: "DIDCommMessaging", - serviceEndpoint: AnyCodable(dictionaryLiteral: - ("uri", "http://didcomm.com"), - ("accept", [String]()), - ("routing_keys", [String]()) - ) +let bobServiceEndpoint3 = AnyCodable(dictionaryLiteral: + ("uri", "http://didcomm.com"), + ("accept", [String]()), + ("routing_keys", ["did:example:alice#key-x25519-1"]) +) + +let bobMediatorServiceEndpoint1 = AnyCodable(dictionaryLiteral: + ("uri", "http://didcomm.com"), + ("accept", [String]()), + ("routing_keys", [String]()) +) + +let bobMediatorServiceEndpoint2 = AnyCodable(dictionaryLiteral: + ("uri", "http://didcomm.com"), + ("accept", [String]()), + ("routing_keys", ["did:example:bob#key-x25519-1"]) +) + +let bobMediatorServiceEndpoint3 = AnyCodable(dictionaryLiteral: + ("uri", "http://didcomm.com"), + ("accept", [String]()), + ("routing_keys", [String]()) +) + +let bobMediatorServices1 = AnyCodable(dictionaryLiteral: + ("id", "service1"), + ("type", "DIDCommMessaging"), + ("serviceEndpoint", [bobMediatorServiceEndpoint1]) +) + +let bobMediatorServices2 = AnyCodable(dictionaryLiteral: + ("id", "service2"), + ("type", "DIDCommMessaging"), + ("serviceEndpoint", [bobMediatorServiceEndpoint2]) +) + +let bobMediatorServices3 = AnyCodable(dictionaryLiteral: + ("id", "service3"), + ("type", "DIDCommMessaging"), + ("serviceEndpoint", [bobMediatorServiceEndpoint3]) +) + +let bobMediatorMultipleMediators = AnyCodable(dictionaryLiteral: + ("id", "service1"), + ("type", "DIDCommMessaging"), + ("serviceEndpoint", AnyCodable( + arrayLiteral: + [ + "uri": "did:example:bobMediator1", + "accept": [String](), + "routing_keys": [String]() + ] as [String: Any], + [ + "uri": "did:example:bobMediator2", + "accept": [String](), + "routing_keys": [String]() + ] as [String: Any], + [ + "uri": "did:example:bobMediator3", + "accept": [String](), + "routing_keys": ["did:example:bob#key-x25519-1"] + ] as [String: Any] + + )) ) @@ -422,6 +470,18 @@ let didDocBobTestVectors = DIDDocument( ] ) +let bobServiceEndpoint = AnyCodable(dictionaryLiteral: + ("uri", "http://example.com/path"), + ("accept", ["didcomm/v2", "didcomm/aip2;env=rfc587"]), + ("routing_keys", ["did:example:mediator1#key-x25519-1"]) + ) + +let bobService = AnyCodable(dictionaryLiteral: + ("id", "did:example:123456789abcdefghi#didcomm-1"), + ("type", ""), + ("serviceEndpoint", bobServiceEndpoint) +) + let didDocBobWithNoSecrets = DIDDocument( id: "did:example:bob", verificationMethods: [ @@ -454,19 +514,7 @@ let didDocBobWithNoSecrets = DIDDocument( .stringValue("did:example:bob#key-p521-2"), .stringValue("did:example:bob#key-p521-not-secrets-1"), ], - services: [ - .init( - id: "did:example:123456789abcdefghi#didcomm-1", - type: "", - serviceEndpoint: AnyCodable( - arrayLiteral: [ - "uri":"http://example.com/path", - "accept":["didcomm/v2", "didcomm/aip2;env=rfc587"], - "routing_keys":["did:example:mediator1#key-x25519-1"] - ] as [String: Any] - ) - ) - ] + services: [bobServiceEndpoint] ) let didDocBobSpecRoutingTestVectors = DIDDocument( @@ -482,7 +530,7 @@ let didDocBobSpecRoutingTestVectors = DIDDocument( .stringValue("did:example:bob#key-x25519-2"), .stringValue("did:example:bob#key-x25519-3"), ], - services: [bobServiceMultipleMediators] + services: [bobMediatorMultipleMediators] ) let didDocBobSpecRoutingMediator1TestVectors = DIDDocument( diff --git a/Tests/DIDCommSwiftTests/TestData/Mock/DIDCharlieMockData.swift b/Tests/DIDCommSwiftTests/TestData/Mock/DIDCharlieMockData.swift index a786537..62f0657 100644 --- a/Tests/DIDCommSwiftTests/TestData/Mock/DIDCharlieMockData.swift +++ b/Tests/DIDCommSwiftTests/TestData/Mock/DIDCharlieMockData.swift @@ -84,6 +84,18 @@ let charlieAuthMethod25519 = DIDDocument.VerificationMethod( ) ) +let charlieServiceEndpoint1 = AnyCodable(dictionaryLiteral: + ("uri", "did:example:mediator2"), + ("accept", ["didcomm/v2", "didcomm/aip2;env=rfc587"]), + ("routing_keys", ["did:example:mediator1#key-x25519-1"]) +) + +let charlieServices1 = AnyCodable(dictionaryLiteral: + ("id", "did:example:123456789abcdefghi#didcomm-1"), + ("type", ""), + ("serviceEndpoint", [bobMediatorServiceEndpoint1]) +) + let didDocCharlie = DIDDocument( id: "did:example:charlie", verificationMethods: [ @@ -98,17 +110,5 @@ let didDocCharlie = DIDDocument( // .stringValue("did:example:charlie#key-x25519-2"), // .stringValue("did:example:charlie#key-x25519-3") ], - services: [ - .init( - id: "did:example:123456789abcdefghi#didcomm-1", - type: "", - serviceEndpoint: AnyCodable( - arrayLiteral: [ - "uri": "did:example:mediator2", - "accept": ["didcomm/v2", "didcomm/aip2;env=rfc587"], - "routing_keys": ["did:example:mediator1#key-x25519-1"] - ] as [String: Any] - ) - ) - ] + services: [charlieServices1] )