From cd2b623c0286bba140c4387f4c2a806d6c96c9e8 Mon Sep 17 00:00:00 2001 From: goncalo-frade-iohk <87179681+goncalo-frade-iohk@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:41:25 +0000 Subject: [PATCH] feat!: move to swift based framework for didcomm, jose and peer did (#120) --- .../Sources/ApolloImpl+KeyRestoration.swift | 32 +- .../Apollo/Sources/Model/Ed25519Key.swift | 14 +- .../Apollo/Sources/Model/LinkSecret.swift | 1 + .../Model/Secp256k1Key+Exportable.swift | 16 +- .../Apollo/Sources/Model/Secp256k1Key.swift | 19 +- .../Apollo/Sources/Model/X25519Key.swift | 14 +- .../CreateEd25519KeyPairOperation.swift | 7 +- .../CreateX25519KeyPairOperation.swift | 7 +- .../Castor/Sources/CastorImpl+Public.swift | 18 - .../Castor/Sources/DID/PeerDID/PeerDID.swift | 65 ---- .../Castor/Sources/DID/PeerDID/Types.swift | 66 ---- .../Castor/Sources/Helpers/JWK+Helper.swift | 45 --- .../Operations/CreatePeerDIDOperation.swift | 187 +++------- .../Sources/Resolvers/PeerDIDResolver.swift | 326 +++++++++--------- .../Tests/EncumbasisEncodeDecodeTests.swift | 31 -- .../Castor/Tests/PeerDIDCreationTests.swift | 4 +- AtalaPrismSDK/Domain/Sources/BBs/Castor.swift | 23 -- AtalaPrismSDK/Domain/Sources/BBs/Pluto.swift | 9 + .../Domain/Sources/Models/DIDDocument.swift | 16 + .../Sources/Models/KeyManagement/Keys.swift | 2 + .../Models/KeyManagement/StorableKey.swift | 3 + .../Sources/Models/Message+Codable.swift | 32 +- .../Domain/Sources/Models/Message.swift | 4 +- .../Sources/Models/MessageAttachment.swift | 12 +- .../DIDCommDIDResolverWrapper.swift | 125 +++---- .../DIDCommSecretsResolverWrapper.swift | 166 +++------ .../PackEncryptedOperation.swift | 96 +----- .../DIDCommWrappers/UnpackOperation.swift | 93 +---- .../Helpers/DIDCommMessage+DomainParse.swift | 117 ++++--- .../Mercury/Sources/MercuryImpl+Public.swift | 2 +- .../Mercury/Sources/MercuryImpl.swift | 6 +- .../Domain/Providers/KeyProvider.swift | 8 + .../Sources/Domain/StorableKeyModel.swift | 1 + .../Sources/Helpers/Message+Codable.swift | 30 +- ...DDIDPrivateKeyDAO+DIDPrivateKeyStore.swift | 15 +- .../DAO/CDKeyDAO+KeyProvider.swift | 21 ++ .../DAO/CDKeyDAO+LinkSecretStore.swift | 10 +- .../PersistentStorage/DAO/CDKeyDAO.swift | 2 + .../DAO/CDMessageDAO+MessageProvider.swift | 2 +- .../Pluto/Sources/PlutoImpl+Public.swift | 8 + .../Pluto/Tests/Helper/PrivateKey+Test.swift | 2 + .../AnonCreds/AnoncredsCredentialStack.swift | 2 +- .../Sources/Models/JWT/JWTPresentation.swift | 105 ++++-- .../W3C/W3CVerifiableCredential+Codable.swift | 4 +- .../JWT/CreateJWTCredentialRequest.swift | 90 ++++- .../PolluxImpl+CredentialRequest.swift | 4 +- AtalaPrismSDK/Pollux/Tests/JWTTests.swift | 1 - .../Pollux/Tests/Mocks/MockPluto.swift | 10 +- .../Sources/PrismAgent+Credentials.swift | 2 +- .../PrismAgent+DIDHigherFucntions.swift | 8 +- .../PrismAgent/Sources/PrismAgent+Proof.swift | 3 +- .../PrismAgent/Sources/PrismAgent.swift | 38 +- .../Mediation/MediationKeysUpdateList.swift | 3 +- .../Mediation/MediationRequest.swift | 3 +- .../Protocols/Pickup/PickupRequest.swift | 3 +- .../Protocols/Pickup/PrickupReceived.swift | 3 +- Package.swift | 17 +- .../WalletDemo2/Main/Main2Router.swift | 45 +-- .../MediatorPage/MediatorPageView.swift | 2 +- .../DIDChat/DIDChat.xcodeproj/project.pbxproj | 4 +- .../ContactsView/ContactsViewModel.swift | 1 - .../Modules/MediatorView/MediatorView.swift | 2 +- .../MediatorView/MediatorViewModel.swift | 4 +- 63 files changed, 821 insertions(+), 1190 deletions(-) delete mode 100644 AtalaPrismSDK/Castor/Sources/DID/PeerDID/PeerDID.swift delete mode 100644 AtalaPrismSDK/Castor/Sources/DID/PeerDID/Types.swift delete mode 100644 AtalaPrismSDK/Castor/Sources/Helpers/JWK+Helper.swift delete mode 100644 AtalaPrismSDK/Castor/Tests/EncumbasisEncodeDecodeTests.swift create mode 100644 AtalaPrismSDK/Pluto/Sources/Domain/Providers/KeyProvider.swift create mode 100644 AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO+KeyProvider.swift diff --git a/AtalaPrismSDK/Apollo/Sources/ApolloImpl+KeyRestoration.swift b/AtalaPrismSDK/Apollo/Sources/ApolloImpl+KeyRestoration.swift index b8457565..9c1149f4 100644 --- a/AtalaPrismSDK/Apollo/Sources/ApolloImpl+KeyRestoration.swift +++ b/AtalaPrismSDK/Apollo/Sources/ApolloImpl+KeyRestoration.swift @@ -20,11 +20,22 @@ extension ApolloImpl: KeyRestoration { guard let index = key.index else { throw ApolloError.restoratonFailedNoIdentifierOrInvalid } - return Secp256k1PrivateKey(internalKey: .init(raw: key.storableData.toKotlinByteArray()), derivationPath: DerivationPath(index: index)) + return Secp256k1PrivateKey( + identifier: key.identifier, + internalKey: .init(raw: key.storableData.toKotlinByteArray()), derivationPath: DerivationPath(index: index) + ) case "x25519+priv": - return try CreateX25519KeyPairOperation(logger: Self.logger).compute(fromPrivateKey: key.storableData) + return try CreateX25519KeyPairOperation(logger: Self.logger) + .compute( + identifier: key.identifier, + fromPrivateKey: key.storableData + ) case "ed25519+priv": - return try CreateEd25519KeyPairOperation(logger: Self.logger).compute(fromPrivateKey: key.storableData) + return try CreateEd25519KeyPairOperation(logger: Self.logger) + .compute( + identifier: key.identifier, + fromPrivateKey: key.storableData + ) default: throw ApolloError.restoratonFailedNoIdentifierOrInvalid } @@ -34,11 +45,20 @@ extension ApolloImpl: KeyRestoration { public func restorePublicKey(_ key: StorableKey) throws -> PublicKey { switch key.restorationIdentifier { case "secp256k1+pub": - return Secp256k1PublicKey(internalKey: .init(raw: key.storableData.toKotlinByteArray())) + return Secp256k1PublicKey( + identifier: key.identifier, + internalKey: .init(raw: key.storableData.toKotlinByteArray()) + ) case "x25519+pub": - return X25519PublicKey(internalKey: .init(raw: key.storableData.toKotlinByteArray())) + return X25519PublicKey( + identifier: key.identifier, + internalKey: .init(raw: key.storableData.toKotlinByteArray()) + ) case "ed25519+pub": - return Ed25519PublicKey(internalKey: .init(raw: key.storableData.toKotlinByteArray())) + return Ed25519PublicKey( + identifier: key.identifier, + internalKey: .init(raw: key.storableData.toKotlinByteArray()) + ) default: throw ApolloError.restoratonFailedNoIdentifierOrInvalid } diff --git a/AtalaPrismSDK/Apollo/Sources/Model/Ed25519Key.swift b/AtalaPrismSDK/Apollo/Sources/Model/Ed25519Key.swift index 7905e143..290a0316 100644 --- a/AtalaPrismSDK/Apollo/Sources/Model/Ed25519Key.swift +++ b/AtalaPrismSDK/Apollo/Sources/Model/Ed25519Key.swift @@ -9,10 +9,15 @@ struct Ed25519PrivateKey: PrivateKey { let keySpecifications: [String : String] = [ "curve" : "Ed25519" ] + var identifier: String var size: Int { raw.count } var raw: Data { internalKey.raw.toData() } - init(internalKey: ApolloLibrary.KMMEdPrivateKey) { + init( + identifier: String = UUID().uuidString, + internalKey: ApolloLibrary.KMMEdPrivateKey + ) { + self.identifier = identifier self.internalKey = internalKey } @@ -53,10 +58,15 @@ struct Ed25519PublicKey: PublicKey { let keySpecifications: [String : String] = [ "curve" : "Ed25519" ] + var identifier: String var size: Int { raw.count } var raw: Data { internalKey.raw.toData() } - init(internalKey: ApolloLibrary.KMMEdPublicKey) { + init( + identifier: String = UUID().uuidString, + internalKey: ApolloLibrary.KMMEdPublicKey + ) { + self.identifier = identifier self.internalKey = internalKey } diff --git a/AtalaPrismSDK/Apollo/Sources/Model/LinkSecret.swift b/AtalaPrismSDK/Apollo/Sources/Model/LinkSecret.swift index 039dbbd9..fa91d108 100644 --- a/AtalaPrismSDK/Apollo/Sources/Model/LinkSecret.swift +++ b/AtalaPrismSDK/Apollo/Sources/Model/LinkSecret.swift @@ -6,6 +6,7 @@ struct LinkSecret: Key { let keyType = "LinkSecret" let keySpecifications = [String : String]() let raw: Data + var identifier = "linkSecret" var size: Int { raw.count } let anoncred: AnoncredsSwift.LinkSecret diff --git a/AtalaPrismSDK/Apollo/Sources/Model/Secp256k1Key+Exportable.swift b/AtalaPrismSDK/Apollo/Sources/Model/Secp256k1Key+Exportable.swift index 7794bae8..413d6f51 100644 --- a/AtalaPrismSDK/Apollo/Sources/Model/Secp256k1Key+Exportable.swift +++ b/AtalaPrismSDK/Apollo/Sources/Model/Secp256k1Key+Exportable.swift @@ -11,9 +11,9 @@ extension Secp256k1PrivateKey: ExportableKey { var jwk: JWK { JWK( - kty: "OKP", + kty: "EC", d: raw.base64UrlEncodedString(), - crv: getProperty(.curve)?.capitalized, + crv: getProperty(.curve)?.lowercased(), x: publicKey().getProperty(.curvePointX).flatMap { Data(fromBase64URL: $0)?.base64UrlEncodedString() }, y: publicKey().getProperty(.curvePointY).flatMap { Data(fromBase64URL: $0)?.base64UrlEncodedString() } ) @@ -21,10 +21,10 @@ extension Secp256k1PrivateKey: ExportableKey { func jwkWithKid(kid: String) -> JWK { JWK( - kty: "OKP", + kty: "EC", kid: kid, d: raw.base64UrlEncodedString(), - crv: getProperty(.curve)?.capitalized, + crv: getProperty(.curve)?.lowercased(), x: publicKey().getProperty(.curvePointX).flatMap { Data(fromBase64URL: $0)?.base64UrlEncodedString() }, y: publicKey().getProperty(.curvePointY).flatMap { Data(fromBase64URL: $0)?.base64UrlEncodedString() } ) @@ -41,8 +41,8 @@ extension Secp256k1PublicKey: ExportableKey { var jwk: JWK { JWK( - kty: "OKP", - crv: getProperty(.curve)?.capitalized, + kty: "EC", + crv: getProperty(.curve)?.lowercased(), x: getProperty(.curvePointX) .flatMap { Data(fromBase64URL: $0)?.base64UrlEncodedString() } ?? raw.base64UrlEncodedString(), y: getProperty(.curvePointY).flatMap { Data(fromBase64URL: $0)?.base64UrlEncodedString() } @@ -51,9 +51,9 @@ extension Secp256k1PublicKey: ExportableKey { func jwkWithKid(kid: String) -> JWK { JWK( - kty: "OKP", + kty: "EC", kid: kid, - crv: getProperty(.curve)?.capitalized, + crv: getProperty(.curve)?.lowercased(), x: getProperty(.curvePointX) .flatMap { Data(fromBase64URL: $0)?.base64UrlEncodedString() } ?? raw.base64UrlEncodedString(), y: getProperty(.curvePointY).flatMap { Data(fromBase64URL: $0)?.base64UrlEncodedString() } diff --git a/AtalaPrismSDK/Apollo/Sources/Model/Secp256k1Key.swift b/AtalaPrismSDK/Apollo/Sources/Model/Secp256k1Key.swift index 12ef644b..fd5cdf60 100644 --- a/AtalaPrismSDK/Apollo/Sources/Model/Secp256k1Key.swift +++ b/AtalaPrismSDK/Apollo/Sources/Model/Secp256k1Key.swift @@ -5,14 +5,19 @@ import Foundation struct Secp256k1PrivateKey: PrivateKey { private let internalKey: KMMECSecp256k1PrivateKey - let keyType: String = "EC" let keySpecifications: [String : String] let size: Int let raw: Data let derivationPath: Domain.DerivationPath - - init(internalKey: KMMECSecp256k1PrivateKey, derivationPath: Domain.DerivationPath) { + var identifier: String + + init( + identifier: String = UUID().uuidString, + internalKey: KMMECSecp256k1PrivateKey, + derivationPath: Domain.DerivationPath + ) { + self.identifier = identifier self.internalKey = internalKey self.derivationPath = derivationPath self.keySpecifications = [ @@ -60,13 +65,17 @@ extension Secp256k1PrivateKey: KeychainStorableKey { struct Secp256k1PublicKey: PublicKey { private let internalKey: ApolloLibrary.KMMECSecp256k1PublicKey - let keyType: String = "EC" let keySpecifications: [String : String] let size: Int let raw: Data + var identifier = UUID().uuidString - init(internalKey: ApolloLibrary.KMMECSecp256k1PublicKey) { + init( + identifier: String = UUID().uuidString, + internalKey: ApolloLibrary.KMMECSecp256k1PublicKey + ) { + self.identifier = identifier self.internalKey = internalKey var specs: [String: String] = [ KeyProperties.curve.rawValue: "secp256k1", diff --git a/AtalaPrismSDK/Apollo/Sources/Model/X25519Key.swift b/AtalaPrismSDK/Apollo/Sources/Model/X25519Key.swift index 063eb0b0..7595525d 100644 --- a/AtalaPrismSDK/Apollo/Sources/Model/X25519Key.swift +++ b/AtalaPrismSDK/Apollo/Sources/Model/X25519Key.swift @@ -8,10 +8,15 @@ struct X25519PrivateKey: PrivateKey { let keySpecifications: [String : String] = [ "curve" : "x25519" ] + var identifier:String var size: Int { raw.count } var raw: Data { internalKey.raw.toData() } - init(internalKey: ApolloLibrary.KMMX25519PrivateKey) { + init( + identifier: String = UUID().uuidString, + internalKey: ApolloLibrary.KMMX25519PrivateKey + ) { + self.identifier = identifier self.internalKey = internalKey } @@ -41,10 +46,15 @@ struct X25519PublicKey: PublicKey { let keySpecifications: [String : String] = [ "curve" : "x25519" ] + var identifier: String var size: Int { raw.count } var raw: Data { internalKey.raw.toData() } - init(internalKey: ApolloLibrary.KMMX25519PublicKey) { + init( + identifier: String = UUID().uuidString, + internalKey: ApolloLibrary.KMMX25519PublicKey + ) { + self.identifier = identifier self.internalKey = internalKey } diff --git a/AtalaPrismSDK/Apollo/Sources/Operations/CreateEd25519KeyPairOperation.swift b/AtalaPrismSDK/Apollo/Sources/Operations/CreateEd25519KeyPairOperation.swift index 6df5da18..96dca525 100644 --- a/AtalaPrismSDK/Apollo/Sources/Operations/CreateEd25519KeyPairOperation.swift +++ b/AtalaPrismSDK/Apollo/Sources/Operations/CreateEd25519KeyPairOperation.swift @@ -12,7 +12,10 @@ struct CreateEd25519KeyPairOperation { } - func compute(fromPrivateKey: Data) throws -> PrivateKey { - return Ed25519PrivateKey(internalKey: KMMEdPrivateKey(raw: fromPrivateKey.toKotlinByteArray())) + func compute(identifier: String = UUID().uuidString, fromPrivateKey: Data) throws -> PrivateKey { + return Ed25519PrivateKey( + identifier: identifier, + internalKey: KMMEdPrivateKey(raw: fromPrivateKey.toKotlinByteArray()) + ) } } diff --git a/AtalaPrismSDK/Apollo/Sources/Operations/CreateX25519KeyPairOperation.swift b/AtalaPrismSDK/Apollo/Sources/Operations/CreateX25519KeyPairOperation.swift index e8ad07b4..e77edc83 100644 --- a/AtalaPrismSDK/Apollo/Sources/Operations/CreateX25519KeyPairOperation.swift +++ b/AtalaPrismSDK/Apollo/Sources/Operations/CreateX25519KeyPairOperation.swift @@ -13,8 +13,11 @@ struct CreateX25519KeyPairOperation { } - func compute(fromPrivateKey: Data) throws -> PrivateKey { + func compute(identifier: String = UUID().uuidString, fromPrivateKey: Data) throws -> PrivateKey { let privateKey = KMMX25519PrivateKey(raw: fromPrivateKey.toKotlinByteArray()) - return X25519PrivateKey(internalKey: privateKey) + return X25519PrivateKey( + identifier: identifier, + internalKey: privateKey + ) } } diff --git a/AtalaPrismSDK/Castor/Sources/CastorImpl+Public.swift b/AtalaPrismSDK/Castor/Sources/CastorImpl+Public.swift index 4b985f8f..ee44e23b 100644 --- a/AtalaPrismSDK/Castor/Sources/CastorImpl+Public.swift +++ b/AtalaPrismSDK/Castor/Sources/CastorImpl+Public.swift @@ -129,22 +129,4 @@ extension CastorImpl: Castor { } return try await resolver.resolve(did: did) } - - /// getEcnumbasis generates a unique ECNUM basis string for a given DID and key pair. This function may throw an error if the DID or key pair are invalid. - /// - /// - Parameters: - /// - did: The DID associated with the key pair - /// - keyPair: The key pair to use for generating the ECNUM basis - /// - Returns: The ECNUM basis string - /// - Throws: An error if the DID or key pair are invalid - public func getEcnumbasis(did: DID, publicKey: PublicKey) throws -> String { - logger.debug(message: "Getting ecnumbasis", metadata: [ - .maskedMetadataByLevel(key: "DID", value: did.string, level: .debug) - ]) - return try CreatePeerDIDOperation( - autenticationPublicKey: publicKey, - agreementPublicKey: publicKey, - services: [] - ).computeEcnumbasis(did: did, publicKey: publicKey) - } } diff --git a/AtalaPrismSDK/Castor/Sources/DID/PeerDID/PeerDID.swift b/AtalaPrismSDK/Castor/Sources/DID/PeerDID/PeerDID.swift deleted file mode 100644 index be7b92af..00000000 --- a/AtalaPrismSDK/Castor/Sources/DID/PeerDID/PeerDID.swift +++ /dev/null @@ -1,65 +0,0 @@ -import Domain -import Foundation -import Multibase - -struct PeerDID { - struct Service: Codable { - enum CodingKeys: String, CodingKey { - case type = "t" - case serviceEndpoint = "s" - case routingKeys = "r" - case accept = "a" - } - - let type: String - let serviceEndpoint: String - let routingKeys: [String] - let accept: [String] - - init( - type: String, - serviceEndpoint: String, - routingKeys: [String], - accept: [String] - ) { - self.type = type - self.serviceEndpoint = serviceEndpoint - self.routingKeys = routingKeys - self.accept = accept - } - - func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode( - type.replacingOccurrences(of: "DIDCommMessaging", with: "dm"), - forKey: .type - ) - try container.encode(serviceEndpoint, forKey: .serviceEndpoint) - try container.encode(routingKeys, forKey: .routingKeys) - try container.encode(accept, forKey: .accept) - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let type = try container.decode(String.self, forKey: .type) - self.type = type == "dm" ? "DIDCommMessaging" : type - self.serviceEndpoint = try container.decode(String.self, forKey: .serviceEndpoint) - self.routingKeys = try container.decodeIfPresent([String].self, forKey: .routingKeys) ?? [] - self.accept = try container.decodeIfPresent([String].self, forKey: .accept) ?? [] - } - } - - init(did: DID) throws { - let regex = """ -(([01](z)([1-9a-km-zA-HJ-NP-Z]{46,47}))|(2((\\.[AEVID](z)([1-9a-km-zA-HJ-NP-Z]{46,47}))+(\\.(S)[0-9a-zA-Z=]*)?)))$ -""" - guard - did.schema == "did", - did.method == "peer", - did.methodId.range(of: regex, options: .regularExpression) != nil - else { throw CastorError.methodIdIsDoesNotSatisfyRegex(regex: regex) } - self.did = did - } - - let did: DID -} diff --git a/AtalaPrismSDK/Castor/Sources/DID/PeerDID/Types.swift b/AtalaPrismSDK/Castor/Sources/DID/PeerDID/Types.swift deleted file mode 100644 index 59716fed..00000000 --- a/AtalaPrismSDK/Castor/Sources/DID/PeerDID/Types.swift +++ /dev/null @@ -1,66 +0,0 @@ -import Foundation - -enum VerificationMaterialFormatPeerDID { - case jwk -} - -protocol VerificationMethodTypePeerDID { - var value: String { get } -} - -enum VerificationMethodTypeAgreement: String, VerificationMethodTypePeerDID { - case jsonWebKey2020 = "JsonWebKey2020" - case x25519KeyAgreementKey2019 = "X25519KeyAgreementKey2019" - case x25519KeyAgreementKey2020 = "X25519KeyAgreementKey2020" - - var value: String { self.rawValue } -} - -enum VerificationMethodTypeAuthentication: String, VerificationMethodTypePeerDID { - case jsonWebKey2020 = "JsonWebKey2020" - case ed25519KeyAgreementKey2018 = "Ed25519VerificationKey2018" - case ed25519KeyAgreementKey2020 = "Ed25519VerificationKey2020" - - var value: String { self.rawValue } -} - -extension VerificationMethodTypePeerDID { - var agreement: VerificationMethodTypeAgreement? { - self as? VerificationMethodTypeAgreement - } - var authentication: VerificationMethodTypeAuthentication? { - self as? VerificationMethodTypeAuthentication - } -} - -protocol VerificationMaterialPeerDID { - var keyType: VerificationMethodTypePeerDID { get } - var value: String { get } -} - -extension VerificationMaterialPeerDID { - var agreement: VerificationMaterialAgreement? { - self as? VerificationMaterialAgreement - } - var authentication: VerificationMaterialAuthentication? { - self as? VerificationMaterialAuthentication - } -} - -struct VerificationMaterialAgreement: VerificationMaterialPeerDID { - let format: VerificationMaterialFormatPeerDID - let value: String - let type: VerificationMethodTypeAgreement - - var keyType: VerificationMethodTypePeerDID { type } -} - -struct VerificationMaterialAuthentication: VerificationMaterialPeerDID { - let format: VerificationMaterialFormatPeerDID - let value: String - let type: VerificationMethodTypeAuthentication - - var keyType: VerificationMethodTypePeerDID { type } -} - -typealias JSON = String diff --git a/AtalaPrismSDK/Castor/Sources/Helpers/JWK+Helper.swift b/AtalaPrismSDK/Castor/Sources/Helpers/JWK+Helper.swift deleted file mode 100644 index 5451427c..00000000 --- a/AtalaPrismSDK/Castor/Sources/Helpers/JWK+Helper.swift +++ /dev/null @@ -1,45 +0,0 @@ -import Core -import Domain -import Foundation - -struct JWKHelper { - func fromJWK(material: VerificationMaterialAgreement) throws -> Data? { - guard - let jsonDic = try convertToDictionary(string: material.value), - let crv = jsonDic["crv"], - let xKey = jsonDic["x"], - crv == "X25519" - else { throw CastorError.invalidJWKError } - - return Data(base64URLEncoded: xKey) - } - - func fromJWK(material: VerificationMaterialAuthentication) throws -> Data? { - guard - let jsonDic = try convertToDictionary(string: material.value), - let crv = jsonDic["crv"], - let xKey = jsonDic["x"], - crv == "Ed25519" - else { throw CastorError.invalidJWKError } - - return Data(base64URLEncoded: xKey) - } - - func toJWK(publicKey: Data, material: VerificationMethodTypePeerDID) throws -> String? { - let xKeyString = publicKey.base64UrlEncodedString() - let crv: String - switch material { - case let agreement as VerificationMethodTypeAgreement where agreement == .jsonWebKey2020: - crv = "X25519" - case let authentication as VerificationMethodTypeAuthentication where authentication == .jsonWebKey2020: - crv = "Ed25519" - default: - throw CastorError.invalidJWKError - } - return try convertToJsonString(dic: [ - "kty" : "OKP", - "crv" : crv, - "x" : xKeyString - ]) - } -} diff --git a/AtalaPrismSDK/Castor/Sources/Operations/CreatePeerDIDOperation.swift b/AtalaPrismSDK/Castor/Sources/Operations/CreatePeerDIDOperation.swift index ae50b369..d4b2773c 100644 --- a/AtalaPrismSDK/Castor/Sources/Operations/CreatePeerDIDOperation.swift +++ b/AtalaPrismSDK/Castor/Sources/Operations/CreatePeerDIDOperation.swift @@ -1,172 +1,63 @@ import Core +import DIDCore import Domain import Foundation import Multibase +import PeerDID struct CreatePeerDIDOperation { - enum Numalgo2Prefix: String { - case authentication = "V" - case keyAgreement = "E" - case service = "S" - } - - struct OctetPublicKey: Codable { - enum CodingKeys: String, CodingKey { - case kty - case crv - case key = "x" - } - - let kty = "OKP" - let crv: String - let key: String - } - private let method: DIDMethod = "peer" let autenticationPublicKey: PublicKey let agreementPublicKey: PublicKey - let services: [DIDDocument.Service] - - func compute() throws -> DID { - return try createPeerDID( - encryptionKeys: [try keyAgreementFromPublicKey(publicKey: agreementPublicKey)], - signingKeys: [try authenticationFromPublicKey(publicKey: autenticationPublicKey)], - services: services - ).did - } - - func computeEcnumbasis(did: DID, publicKey: PublicKey) throws -> String { - guard - let curve = publicKey.getProperty(.curve)?.lowercased() - else { throw ApolloError.missingKeyParameters(missing: [KeyProperties.curve.rawValue]) } - switch curve { - case KnownKeyCurves.x25519.rawValue: - let material = try keyAgreementFromPublicKey(publicKey: agreementPublicKey) - let multibaseEcnumbasis = try createMultibaseEncnumbasis(material: material) - return String(multibaseEcnumbasis.dropFirst()) - case KnownKeyCurves.ed25519.rawValue: - let material = try authenticationFromPublicKey(publicKey: autenticationPublicKey) - let multibaseEcnumbasis = try createMultibaseEncnumbasis(material: material) - return String(multibaseEcnumbasis.dropFirst()) - default: - throw CastorError.keyCurveNotSupported(curve: curve) - } - } - - private func createPeerDID( - encryptionKeys: [VerificationMaterialAgreement], - signingKeys: [VerificationMaterialAuthentication], - services: [DIDDocument.Service] - ) throws -> PeerDID { - let encodedEncryptionKeysStr = try encryptionKeys - .map { try createMultibaseEncnumbasis(material: $0) } - .map { - ".\(Numalgo2Prefix.keyAgreement.rawValue)\($0)" + let services: [Domain.DIDDocument.Service] + + func compute() throws -> Domain.DID { + let did = try PeerDIDHelper.createAlgo2( + authenticationKeys: [authenticationFromPublicKey(publicKey: autenticationPublicKey)], + agreementKeys: [keyAgreementFromPublicKey(publicKey: agreementPublicKey)], + services: services.flatMap { service in + service.serviceEndpoint.map { + DIDCore.DIDDocument.Service( + id: service.id, + type: service.type.first ?? "", + serviceEndpoint: AnyCodable( + dictionaryLiteral: + ("uri", $0.uri), + ("accept", $0.accept), + ("routing_keys", $0.routingKeys) + ) + ) + } } - .joined() - let encodedSigningKeysStr = try signingKeys - .map { try createMultibaseEncnumbasis(material: $0) } - .map { - ".\(Numalgo2Prefix.authentication.rawValue)\($0)" - } - .joined() - let encodedService = try encodeService(services: services) - - return try PeerDID(did: .init( - method: "peer", - methodId: "2" - + encodedEncryptionKeysStr - + encodedSigningKeysStr - + "." - + Numalgo2Prefix.service.rawValue - + encodedService - )) + ) + return try .init(string: did.string) } - private func keyAgreementFromPublicKey(publicKey: PublicKey) throws -> VerificationMaterialAgreement { + private func keyAgreementFromPublicKey(publicKey: PublicKey) throws -> PeerDIDVerificationMaterial { guard - let exportable = publicKey.exporting, - publicKey.getProperty(.curve)?.lowercased() == KnownKeyCurves.x25519.rawValue, - let jwkString = String(data: try JSONEncoder.didComm().encode(exportable.jwk), encoding: .utf8) + publicKey.getProperty(.curve)?.lowercased() == KnownKeyCurves.x25519.rawValue else { throw CastorError.invalidPublicKeyCoding(didMethod: "peer", curve: KnownKeyCurves.x25519.rawValue) } - return .init( + return try .init( format: .jwk, - value: jwkString, - type: .jsonWebKey2020 + key: publicKey.raw, + type: .agreement(.jsonWebKey2020) ) } - private func authenticationFromPublicKey(publicKey: PublicKey) throws -> VerificationMaterialAuthentication { + private func authenticationFromPublicKey(publicKey: PublicKey) throws -> PeerDIDVerificationMaterial { guard - let exportable = publicKey.exporting, - publicKey.getProperty(.curve)?.lowercased() == KnownKeyCurves.ed25519.rawValue, - let jwkString = String(data: try JSONEncoder.didComm().encode(exportable.jwk), encoding: .utf8) - else { throw CastorError.invalidPublicKeyCoding(didMethod: "peer", curve: KnownKeyCurves.ed25519.rawValue) } - return .init( - format: .jwk, - value: jwkString, - type: .jsonWebKey2020 - ) - } - - private func toBase58Multibase(value: Data) -> String { - value.asString(base: .base58btc, withMultibasePrefix: true) - } - - private func createMultibaseEncnumbasis(material: VerificationMaterialAgreement) throws -> String { - let decodedKey: Data? - switch material.format { - case .jwk: - decodedKey = try JWKHelper().fromJWK(material: material) - } - guard let decodedKey else { throw CastorError.invalidJWKError } - try validateRawKeyLength(key: decodedKey) - let multiCodec = Multicodec(value: decodedKey, keyType: .agreement).value - return toBase58Multibase(value: multiCodec) - } - - private func createMultibaseEncnumbasis(material: VerificationMaterialAuthentication) throws -> String { - let decodedKey: Data? - switch material.format { - case .jwk: - decodedKey = try JWKHelper().fromJWK(material: material) - } - guard let decodedKey else { throw CastorError.invalidJWKError } - try validateRawKeyLength(key: decodedKey) - let multiCodec = Multicodec(value: decodedKey, keyType: .authenticate).value - return toBase58Multibase(value: multiCodec) - } - - private func encodeService(services: [DIDDocument.Service]) throws -> String { - let peerDidServices: [PeerDID.Service] = services.map { service in - guard - let type = service.type.first, - let endpoint = service.serviceEndpoint.first - else { return nil } - return PeerDID.Service( - type: type, - serviceEndpoint: endpoint.uri, - routingKeys: endpoint.routingKeys, - accept: endpoint.accept + publicKey.getProperty(.curve)?.lowercased() == KnownKeyCurves.ed25519.rawValue + else { + throw CastorError.invalidPublicKeyCoding( + didMethod: "peer", + curve: KnownKeyCurves.ed25519.rawValue ) - }.compactMap { $0 } - let encoder = JSONEncoder.didComm() - if - peerDidServices.count == 1, - let peerDidService = peerDidServices.first - { - return try encoder.encode(peerDidService).base64UrlEncodedString() - } else { - return try encoder.encode(peerDidServices).base64UrlEncodedString() } - } - private func validateRawKeyLength(key: Data) throws { - guard key.count == 32 else { - throw UnknownError.somethingWentWrongError( - customMessage: "Invalid secp256k1 key size of 32 bytes", - underlyingErrors: nil - ) - } + return try .init( + format: .jwk, + key: publicKey.raw, + type: .authentication(.jsonWebKey2020) + ) } } diff --git a/AtalaPrismSDK/Castor/Sources/Resolvers/PeerDIDResolver.swift b/AtalaPrismSDK/Castor/Sources/Resolvers/PeerDIDResolver.swift index a3268e42..b871e9a9 100644 --- a/AtalaPrismSDK/Castor/Sources/Resolvers/PeerDIDResolver.swift +++ b/AtalaPrismSDK/Castor/Sources/Resolvers/PeerDIDResolver.swift @@ -1,204 +1,186 @@ -import Core +import DIDCore import Domain import Foundation -import Multibase +import PeerDID struct PeerDIDResolver: DIDResolverDomain { var method = "peer" - func resolve(did: DID) async throws -> DIDDocument { - guard - did.method == "peer", - did.methodId.prefix(1) == "2" - else { throw CastorError.notPossibleToResolveDID( - did: did.string, - reason: "Method or method id are invalid" - )} - - return try buildDIDDocumentAlgo2(did: did, format: .jwk) + func resolve(did: Domain.DID) async throws -> Domain.DIDDocument { + try PeerDIDHelper.resolve(peerDIDStr: did.string).toDomain() } +} - private func buildDIDDocumentAlgo2( - did: DID, - format: VerificationMaterialFormatPeerDID - ) throws -> DIDDocument { - let composition = did.methodId.components(separatedBy: ".").dropFirst() - var authenticationMethods = [DIDDocument.VerificationMethod]() - var keyAgreementMethods = [DIDDocument.VerificationMethod]() - var services = [DIDDocument.Service]() - try composition.forEach { - switch $0.prefix(1) { - case CreatePeerDIDOperation.Numalgo2Prefix.authentication.rawValue: - let decoded = try decodeMultibaseEncnumbasisAuth( - did: did, - multibase: String($0.dropFirst()), - format: .jwk - ) - authenticationMethods.append(try getVerificationMethod(did: did, decodedEncumbasis: decoded)) - case CreatePeerDIDOperation.Numalgo2Prefix.keyAgreement.rawValue: - let decoded = try decodeMultibaseEncnumbasisAgreement( - did: did, - multibase: String($0.dropFirst()), - format: .jwk - ) - keyAgreementMethods.append(try getVerificationMethod(did: did, decodedEncumbasis: decoded)) - case CreatePeerDIDOperation.Numalgo2Prefix.service.rawValue: - services.append(contentsOf: try decodeService( - did: did, - encodedString: String($0.dropFirst()) - )) - default: - break - } +extension DIDCore.DIDDocument { + + init(from: Domain.DIDDocument) throws { + let verificationMethods = try from.verificationMethods.map { + try DIDCore.DIDDocument.VerificationMethod(from: $0) } + let verificationMethodsIds = verificationMethods.map(\.id) - return DIDDocument( - id: did, - coreProperties: [ - DIDDocument.VerificationMethods( - values: authenticationMethods + keyAgreementMethods - ), - DIDDocument.Authentication( - urls: authenticationMethods.map { $0.id.string }, - verificationMethods: [] - ), - DIDDocument.KeyAgreement( - urls: keyAgreementMethods.map { $0.id.string }, - verificationMethods: [] - ), - DIDDocument.Services(values: services) - ] - ) - } + let authenticationMethods = try from.authenticate + .filter { + verificationMethodsIds.contains($0.id.string) + } + .map { + try DIDCore.DIDDocument.VerificationMethod(from: $0) + } + let authenticationIds = from.authenticate.map(\.id.string) - func decodeMultibaseEncnumbasisAuth( - did: DID, - multibase: String, - format: VerificationMaterialFormatPeerDID - ) throws -> (String, VerificationMaterialAuthentication) { - let (decoded, verMaterial) = try decodeMultibaseEncnumbasis( - multibase: multibase, - format: format, defaultCodec: .ed25519 - ) - guard let material = verMaterial.authentication else { - throw CastorError.notPossibleToResolveDID( - did: did.string, - reason: "Could not decode authentication multibase" - ) + let keyAgreementMethods = try from.keyAgreement + .filter { + verificationMethodsIds.contains($0.id.string) + } + .map { + try DIDCore.DIDDocument.VerificationMethod(from: $0) + } + + let keyAgreementIds = from.keyAgreement.map(\.id.string) + + let services = from.services.flatMap { service in + service.serviceEndpoint.map { + DIDCore.DIDDocument.Service( + id: service.id, + type: service.type.first ?? "", + serviceEndpoint: AnyCodable( + dictionaryLiteral: + ("uri", $0.uri), + ("accept", $0.accept), + ("routing_keys", $0.routingKeys) + ) + ) + } } - return (decoded, material) - } - private func decodeMultibaseEncnumbasisAgreement( - did: DID, - multibase: String, - format: VerificationMaterialFormatPeerDID - ) throws -> (String, VerificationMaterialAgreement) { - let (decoded, verMaterial) = try decodeMultibaseEncnumbasis( - multibase: multibase, - format: format, defaultCodec: .x25519 + self.init( + id: from.id.string, + verificationMethods: verificationMethods + authenticationMethods + keyAgreementMethods, + authentication: authenticationIds.map { .stringValue($0) }, + assertionMethod: nil, + capabilityDelegation: nil, + keyAgreement: keyAgreementIds.map { .stringValue($0) }, + services: services ) - guard let material = verMaterial.agreement else { - throw CastorError.notPossibleToResolveDID( - did: did.string, - reason: "Could not decode key agreement multibase" - )} - - return (decoded, material) } - private func decodeMultibaseEncnumbasis( - multibase: String, - format: VerificationMaterialFormatPeerDID, - defaultCodec: Multicodec.Codec - ) throws -> (String, VerificationMaterialPeerDID) { - let (encnum, encnumData) = try fromBase58Multibase(multibase: multibase) - let (codec, decodedEncnum) = try Multicodec(value: encnumData).decode() - try validateRawKeyLength(key: decodedEncnum) - switch format { - case .jwk: - switch codec { - case .x25519: - guard let jwkJsonString = try JWKHelper().toJWK( - publicKey: decodedEncnum, - material: VerificationMethodTypeAgreement.jsonWebKey2020 - ) else { throw CastorError.invalidJWKError } - - return (encnum, VerificationMaterialAgreement( - format: format, - value: jwkJsonString, - type: .jsonWebKey2020 - )) - case .ed25519: - guard let jwkJsonString = try JWKHelper().toJWK( - publicKey: decodedEncnum, - material: VerificationMethodTypeAuthentication.jsonWebKey2020 - ) else { throw CastorError.invalidJWKError } - - return (encnum, VerificationMaterialAuthentication( - format: format, - value: jwkJsonString, - type: .jsonWebKey2020 - )) + func toDomain() throws -> Domain.DIDDocument { + let authenticationUrls = self.verificationMethods + .filter { + guard let type = KnownVerificationMaterialType(rawValue: $0.type) else { + return false + } + switch type { + case .authentication: + return true + default: + return false + } } + .map { $0.id } + + let keyAgreementUrls = self.verificationMethods + .filter { + guard let type = KnownVerificationMaterialType(rawValue: $0.type) else { + return false + } + switch type { + case .agreement: + return true + default: + return false + } + } + .map { $0.id } + + let verificationMethods = try self.verificationMethods.map { + try $0.toDomain() } - } - private func fromBase58Multibase(multibase: String) throws -> (String, Data) { - let multibaseDecoding = try BaseEncoding.decode(multibase) - return (String(multibase.dropFirst()), multibaseDecoding.data) - } + let services = try self.services?.map { + guard + let endpoint = $0.serviceEndpoint.value as? [String: Any], + let uri = endpoint["uri"] as? String + else { + throw CastorError.notPossibleToResolveDID(did: $0.id, reason: "Invalid service") + } + return Domain.DIDDocument.Service( + id: $0.id, + type: [$0.type], + serviceEndpoint: [ + .init( + uri: uri, + accept: endpoint["accept"] as? [String] ?? [], + routingKeys: endpoint["routing_keys"] as? [String] ?? [] + ) + ] + ) + } ?? [Domain.DIDDocument.Service]() - private func getVerificationMethod( - did: DID, - decodedEncumbasis: (String, VerificationMaterialPeerDID) - ) throws -> DIDDocument.VerificationMethod { - var jsonDic = try convertToDictionary(string: decodedEncumbasis.1.value) - jsonDic?["kid"] = did.string + "#" + decodedEncumbasis.0 - return .init( - id: .init(did: did, fragment: decodedEncumbasis.0), - controller: did, - type: decodedEncumbasis.1.keyType.value, - publicKeyJwk: jsonDic + return Domain.DIDDocument( + id: try DID(string: self.id), + coreProperties: [ + Domain.DIDDocument.Authentication( + urls: authenticationUrls, + verificationMethods: [] + ), + Domain.DIDDocument.KeyAgreement( + urls: keyAgreementUrls, + verificationMethods: [] + ), + Domain.DIDDocument.VerificationMethods(values: verificationMethods), + Domain.DIDDocument.Services(values: services) + ] ) } +} - private func decodeService(did: DID, encodedString: String) throws -> [DIDDocument.Service] { - guard let jsonData = Data(fromBase64URL: encodedString) else { - throw CastorError.notPossibleToResolveDID( - did: did.string, - reason: "Could not parse Service JSON" +extension DIDCore.DIDDocument.VerificationMethod { + + init(from: Domain.DIDDocument.VerificationMethod) throws { + if let publicKeyMultibase = from.publicKeyMultibase { + self.init( + id: from.id.string, + controller: from.controller.string, + type: from.type, + material: .init( + format: .multibase, + value: try publicKeyMultibase.tryData(using: .utf8) + ) ) - } - let services = try jsonDecoderForServicePeerDIDService(jsonData: jsonData) - return services.enumerated().map { - DIDDocument.Service( - id: did.string + $0.element.type.lowercased() + "-\($0.offset)", - type: [$0.element.type], - serviceEndpoint: [.init( - uri: $0.element.serviceEndpoint, - accept: $0.element.accept, - routingKeys: $0.element.routingKeys - )] + } else if let publicKeyJwk = from.publicKeyJwk { + self.init( + id: from.id.string, + controller: from.controller.string, + type: from.type, + material: .init( + format: .jwk, + value: try JSONSerialization.data(withJSONObject: publicKeyJwk) + ) ) + } else { + throw PeerDIDError.invalidMaterialType("") } } - private func jsonDecoderForServicePeerDIDService(jsonData: Data) throws -> [PeerDID.Service] { - do { - return try JSONDecoder().decode([PeerDID.Service].self, from: jsonData) - } catch { - let decoded = try JSONDecoder().decode(PeerDID.Service.self, from: jsonData) - return [decoded] - } - } - - private func validateRawKeyLength(key: Data) throws { - guard key.count == 32 else { - throw UnknownError.somethingWentWrongError( - customMessage: "Invalid secp256k1 key size of 32 bytes", - underlyingErrors: nil + func toDomain() throws -> Domain.DIDDocument.VerificationMethod { + switch material.format { + case .jwk: + return Domain.DIDDocument.VerificationMethod( + id: try DIDUrl(string: id), + controller: try DID(string: controller), + type: type, + publicKeyJwk: try JSONSerialization.jsonObject(with: material.value) as? [String: String] + ) + case .multibase: + return Domain.DIDDocument.VerificationMethod( + id: try DIDUrl(string: id), + controller: try DID(string: controller), + type: type, + publicKeyMultibase: String(data: material.value, encoding: .utf8) ) + default: + throw CastorError.notPossibleToResolveDID(did: id, reason: "Invalid did peer") } } } diff --git a/AtalaPrismSDK/Castor/Tests/EncumbasisEncodeDecodeTests.swift b/AtalaPrismSDK/Castor/Tests/EncumbasisEncodeDecodeTests.swift deleted file mode 100644 index 4e920c3d..00000000 --- a/AtalaPrismSDK/Castor/Tests/EncumbasisEncodeDecodeTests.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Core -import Domain -@testable import Castor -import XCTest - -final class EncumbasisEncodeDecodeTests: XCTestCase { - func testDecodeEcnumbasis() throws { - let valueDic = [ - "crv" : "Ed25519", - "kty" : "OKP", - "x" : "owBhCbktDjkfS6PdQddT0D3yjSitaSysP3YimJ_YgmA" - ] - let valueJson = try convertToJsonString(dic: valueDic)! - let ecnumBasis = "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V" - let result = VerificationMaterialAuthentication( - format: .jwk, - value: valueJson, - type: .jsonWebKey2020 - ) - - let ecnumbasisResult = try PeerDIDResolver().decodeMultibaseEncnumbasisAuth( - did: DID(method: "test", methodId: "test1"), - multibase: ecnumBasis, - format: .jwk - ) - - XCTAssertEqual(result.type, ecnumbasisResult.1.type) - XCTAssertEqual(result.value, ecnumbasisResult.1.value) - XCTAssertEqual(result.format, ecnumbasisResult.1.format) - } -} diff --git a/AtalaPrismSDK/Castor/Tests/PeerDIDCreationTests.swift b/AtalaPrismSDK/Castor/Tests/PeerDIDCreationTests.swift index 39634fbb..d7f90bb3 100644 --- a/AtalaPrismSDK/Castor/Tests/PeerDIDCreationTests.swift +++ b/AtalaPrismSDK/Castor/Tests/PeerDIDCreationTests.swift @@ -5,7 +5,7 @@ import XCTest final class PeerDIDCreationTests: XCTestCase { func testPeerDIDCreation() throws { - let validPeerDID = "did:peer:2.Ez6LSoHkfN1Y4nK9RCjx7vopWsLrMGNFNgTNZgoCNQrTzmb1n.Vz6MknRZmapV7uYZQuZez9n9N3tQotjRN18UGS68Vcfo6gR4h.SeyJhIjpbXSwiciI6WyJkaWQ6ZXhhbXBsZTpzb21lbWVkaWF0b3Ijc29tZWtleSJdLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInQiOiJkbSJ9" + let validPeerDID = "did:peer:2.Ez6LSoHkfN1Y4nK9RCjx7vopWsLrMGNFNgTNZgoCNQrTzmb1n.Vz6MknRZmapV7uYZQuZez9n9N3tQotjRN18UGS68Vcfo6gR4h.SeyJzIjp7ImEiOltdLCJyIjpbImRpZDpleGFtcGxlOnNvbWVtZWRpYXRvciNzb21la2V5Il0sInVyaSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vZW5kcG9pbnQifSwidCI6ImRtIn0" let apollo = ApolloImpl() let castor = CastorImpl(apollo: apollo) let keyAgreementPrivateKey = try apollo.createPrivateKey(parameters: [ @@ -35,7 +35,6 @@ final class PeerDIDCreationTests: XCTestCase { services: [service] ) - print(did.string) XCTAssertEqual(did.string, validPeerDID) } @@ -59,6 +58,5 @@ final class PeerDIDCreationTests: XCTestCase { let apollo = ApolloImpl() let castor = CastorImpl(apollo: apollo) let document = try await castor.resolveDID(did: mypeerDID) - print(document) } } diff --git a/AtalaPrismSDK/Domain/Sources/BBs/Castor.swift b/AtalaPrismSDK/Domain/Sources/BBs/Castor.swift index 889b3432..4ed4ce33 100644 --- a/AtalaPrismSDK/Domain/Sources/BBs/Castor.swift +++ b/AtalaPrismSDK/Domain/Sources/BBs/Castor.swift @@ -21,20 +21,6 @@ public protocol Castor { services: [DIDDocument.Service] ) throws -> DID -// /// createPeerDID creates a DID for a peer (a device or server that acts as a DID subject) using given key agreement and authentication key pairs and a list of services. This function may throw an error if the key pairs or services are invalid. -// /// -// /// - Parameters: -// /// - keyAgreementKeyPair: The key pair used for key agreement (establishing secure communication between peers) -// /// - authenticationKeyPair: The key pair used for authentication (verifying the identity of a peer) -// /// - services: The list of services offered by the peer -// /// - Returns: The DID of the peer -// /// - Throws: An error if the key pairs or services are invalid -// func createPeerDID( -// keyAgreementKeyPair: KeyPair, -// authenticationKeyPair: KeyPair, -// services: [DIDDocument.Service] -// ) throws -> DID - /// createPeerDID creates a DID for a peer (a device or server that acts as a DID subject) using given key agreement and authentication key pairs and a list of services. This function may throw an error if the key pairs or services are invalid. /// /// - Parameters: @@ -83,15 +69,6 @@ public protocol Castor { challenge: Data, signature: Data ) async throws -> Bool - - /// getEcnumbasis generates a unique ECNUM basis string for a given DID and key pair. This function may throw an error if the DID or key pair are invalid. - /// - /// - Parameters: - /// - did: The DID associated with the key pair - /// - keyPair: The key pair to use for generating the ECNUM basis - /// - Returns: The ECNUM basis string - /// - Throws: An error if the DID or key pair are invalid - func getEcnumbasis(did: DID, publicKey: PublicKey) throws -> String } extension Castor { diff --git a/AtalaPrismSDK/Domain/Sources/BBs/Pluto.swift b/AtalaPrismSDK/Domain/Sources/BBs/Pluto.swift index afc5c15f..7b48cd3d 100644 --- a/AtalaPrismSDK/Domain/Sources/BBs/Pluto.swift +++ b/AtalaPrismSDK/Domain/Sources/BBs/Pluto.swift @@ -151,6 +151,15 @@ public protocol Pluto { /// - Returns: A publisher that emits an array of DID pairs. func getAllDidPairs() -> AnyPublisher<[DIDPair], Error> + /// Returns all stored Keys. + /// - Returns: A publisher that emits an array of StorableKey. + func getAllKeys() -> AnyPublisher<[StorableKey], Error> + + /// Returns the key with the given id. + /// - Parameter id: The key id. + /// - Returns: A publisher that emits an key if it exists. + func getKeyById(id: String) -> AnyPublisher + /// Returns the stored DID pair that includes a given DID. /// - Parameter otherDID: The DID to search for. /// - Returns: A publisher that emits an optional DID pair that includes the given DID. diff --git a/AtalaPrismSDK/Domain/Sources/Models/DIDDocument.swift b/AtalaPrismSDK/Domain/Sources/Models/DIDDocument.swift index 07880625..a6fd24c2 100644 --- a/AtalaPrismSDK/Domain/Sources/Models/DIDDocument.swift +++ b/AtalaPrismSDK/Domain/Sources/Models/DIDDocument.swift @@ -248,6 +248,22 @@ public struct DIDDocument { return authenticateProperty.verificationMethods } + public var keyAgreement: [VerificationMethod] { + guard + let property = coreProperties + .first(where: { $0 as? KeyAgreement != nil }) + .map({ $0 as? KeyAgreement }), + let keyAgreementProperty = property + else { return [] } + + guard keyAgreementProperty.urls.isEmpty else { + return keyAgreementProperty.urls.compactMap { uri in + verificationMethods.first { $0.id.string == uri } + } + keyAgreementProperty.verificationMethods + } + return keyAgreementProperty.verificationMethods + } + public var verificationMethods: [VerificationMethod] { guard let property = coreProperties diff --git a/AtalaPrismSDK/Domain/Sources/Models/KeyManagement/Keys.swift b/AtalaPrismSDK/Domain/Sources/Models/KeyManagement/Keys.swift index b3830dac..91baaf69 100644 --- a/AtalaPrismSDK/Domain/Sources/Models/KeyManagement/Keys.swift +++ b/AtalaPrismSDK/Domain/Sources/Models/KeyManagement/Keys.swift @@ -3,6 +3,8 @@ import Foundation /// The Key protocol defines a cryptographic key with essential properties. /// Each key has a type (e.g., "RSA", "ECC"), a set of specifications, a size, and a raw data representation. public protocol Key { + /// The key identifier + var identifier: String { get set } /// The type of the key (e.g., "RSA", "ECC") var keyType: String { get } diff --git a/AtalaPrismSDK/Domain/Sources/Models/KeyManagement/StorableKey.swift b/AtalaPrismSDK/Domain/Sources/Models/KeyManagement/StorableKey.swift index fb8e9ba6..e89456e0 100644 --- a/AtalaPrismSDK/Domain/Sources/Models/KeyManagement/StorableKey.swift +++ b/AtalaPrismSDK/Domain/Sources/Models/KeyManagement/StorableKey.swift @@ -2,6 +2,9 @@ import Foundation /// The `StorableKey` protocol defines a cryptographic key that can be stored persistently. public protocol StorableKey { + /// The key identifier + var identifier: String { get set } + /// An identifier used for restoring the key. var restorationIdentifier: String { get } diff --git a/AtalaPrismSDK/Domain/Sources/Models/Message+Codable.swift b/AtalaPrismSDK/Domain/Sources/Models/Message+Codable.swift index b738781d..0569eaed 100644 --- a/AtalaPrismSDK/Domain/Sources/Models/Message+Codable.swift +++ b/AtalaPrismSDK/Domain/Sources/Models/Message+Codable.swift @@ -38,17 +38,17 @@ extension Message: Codable { let container = try decoder.container(keyedBy: CodingKeys.self) let id = try container.decode(String.self, forKey: .id) let piuri = try container.decode(String.self, forKey: .piuri) - let body = try container.decode(Data.self, forKey: .body) - let extraHeaders = try container.decode([String: String].self, forKey: .extraHeaders) - let createdTime = try container.decode(Date.self, forKey: .createdTime) - let expiresTimePlus = try container.decode(Date.self, forKey: .expiresTimePlus) - let attachments = try container.decode([AttachmentDescriptor].self, forKey: .attachments) - let ack = try container.decode([String].self, forKey: .ack) - let from = try? container.decode(String.self, forKey: .from) - let to = try? container.decode(String.self, forKey: .to) - let fromPrior = try? container.decode(String.self, forKey: .fromPrior) - let thid = try? container.decode(String.self, forKey: .thid) - let pthid = try? container.decode(String.self, forKey: .pthid) + let body = try container.decodeIfPresent(Data.self, forKey: .body) + let extraHeaders = try container.decodeIfPresent([String: String].self, forKey: .extraHeaders) + let createdTime = try container.decodeIfPresent(Date.self, forKey: .createdTime) + let expiresTimePlus = try container.decodeIfPresent(Date.self, forKey: .expiresTimePlus) + let attachments = try container.decodeIfPresent([AttachmentDescriptor].self, forKey: .attachments) + let ack = try container.decodeIfPresent([String].self, forKey: .ack) + let from = try? container.decodeIfPresent(String.self, forKey: .from) + let to = try? container.decodeIfPresent(String.self, forKey: .to) + let fromPrior = try? container.decodeIfPresent(String.self, forKey: .fromPrior) + let thid = try? container.decodeIfPresent(String.self, forKey: .thid) + let pthid = try? container.decodeIfPresent(String.self, forKey: .pthid) self.init( id: id, @@ -56,14 +56,14 @@ extension Message: Codable { from: try from.map { try DID(string: $0) }, to: try to.map { try DID(string: $0) }, fromPrior: fromPrior, - body: body, - extraHeaders: extraHeaders, - createdTime: createdTime, + body: body ?? Data(), + extraHeaders: extraHeaders ?? [:], + createdTime: createdTime ?? Date(), expiresTimePlus: expiresTimePlus, - attachments: attachments, + attachments: attachments ?? [], thid: thid, pthid: pthid, - ack: ack + ack: ack ?? [] ) } } diff --git a/AtalaPrismSDK/Domain/Sources/Models/Message.swift b/AtalaPrismSDK/Domain/Sources/Models/Message.swift index d0c0c0cc..8c848950 100644 --- a/AtalaPrismSDK/Domain/Sources/Models/Message.swift +++ b/AtalaPrismSDK/Domain/Sources/Models/Message.swift @@ -33,7 +33,7 @@ public struct Message: Identifiable, Hashable { public let createdTime: Date /// The time at which the message will expire. - public let expiresTimePlus: Date + public let expiresTimePlus: Date? /// Descriptors for any attachments included in the message. public let attachments: [AttachmentDescriptor] @@ -75,7 +75,7 @@ public struct Message: Identifiable, Hashable { body: Data, extraHeaders: [String : String] = [:], createdTime: Date = Date(), - expiresTimePlus: Date = Date(), + expiresTimePlus: Date? = nil, attachments: [AttachmentDescriptor] = [], thid: String? = nil, pthid: String? = nil, diff --git a/AtalaPrismSDK/Domain/Sources/Models/MessageAttachment.swift b/AtalaPrismSDK/Domain/Sources/Models/MessageAttachment.swift index af4483b9..cd61d309 100644 --- a/AtalaPrismSDK/Domain/Sources/Models/MessageAttachment.swift +++ b/AtalaPrismSDK/Domain/Sources/Models/MessageAttachment.swift @@ -190,12 +190,12 @@ extension AttachmentDescriptor: Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let id = try container.decode(String.self, forKey: .id) - let mediaType = try? container.decode(String.self, forKey: .mediaType) - let filename = try? container.decode([String].self, forKey: .filename) - let format = try? container.decode(String.self, forKey: .format) - let lastmodTime = try? container.decode(Date.self, forKey: .lastmodTime) - let byteCount = try? container.decode(Int.self, forKey: .byteCount) - let description = try? container.decode(String.self, forKey: .description) + let mediaType = try? container.decodeIfPresent(String.self, forKey: .mediaType) + let filename = try? container.decodeIfPresent([String].self, forKey: .filename) + let format = try? container.decodeIfPresent(String.self, forKey: .format) + let lastmodTime = try? container.decodeIfPresent(Date.self, forKey: .lastmodTime) + let byteCount = try? container.decodeIfPresent(Int.self, forKey: .byteCount) + let description = try? container.decodeIfPresent(String.self, forKey: .description) let data: AttachmentData? if let attchData = try? container.decode(AttachmentBase64.self, forKey: .data) { data = attchData diff --git a/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/DIDCommDIDResolverWrapper.swift b/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/DIDCommDIDResolverWrapper.swift index 5ebfde81..086d1b24 100644 --- a/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/DIDCommDIDResolverWrapper.swift +++ b/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/DIDCommDIDResolverWrapper.swift @@ -1,13 +1,14 @@ import Combine import Core -import DIDCommxSwift +import DIDCommSwift +import DIDCore import Domain import Foundation class DIDCommDIDResolverWrapper { let logger: PrismLogger let castor: Castor - var publisher = PassthroughSubject() + var publisher = PassthroughSubject() var cancellables = [AnyCancellable]() init(castor: Castor, logger: PrismLogger) { @@ -23,99 +24,67 @@ class DIDCommDIDResolverWrapper { } } -extension DIDCommDIDResolverWrapper: DidResolver { - func resolve(did: String, cb: OnDidResolverResult) -> ErrorCode { - publisher - .first() - .sink { [weak self] in - switch $0 { - case .finished: - break - case let .failure(error): - self?.logger.error(message: "Error trying to resolve DID", metadata: [ - .publicMetadata(key: "Error", value: error.localizedDescription) - ]) - try? cb.error( - err: ErrorKind.DidNotResolved(message: error.localizedDescription), - msg: error.localizedDescription - ) - } - } receiveValue: { [weak self] in - do { - self?.logger.debug(message: "Success resolving DID", metadata: [ - .maskedMetadataByLevel(key: "DID", value: did, level: .debug) - ]) - try cb.success(result: try DidDoc(from: $0)) - } catch { - self?.logger.error(message: "Error trying to resolve DID", metadata: [ - .publicMetadata(key: "Error", value: error.localizedDescription) - ]) - try? cb.error( - err: ErrorKind.DidNotResolved(message: error.localizedDescription), - msg: error.localizedDescription - ) - } - } - .store(in: &cancellables) - resolve(did: did) - return .success +extension DIDCommDIDResolverWrapper: DIDResolver { + func resolve(did: DIDCore.DID) async throws -> DIDCore.DIDDocument { + let document = try await castor.resolveDID(did: DID(string: did.description)) + return try .init(from: document) } } -extension DidDoc { - init(from: DIDDocument) throws { - let did = from.id.string +extension DIDCore.DIDDocument { + init(from: Domain.DIDDocument) throws { var authentications = [String]() var keyAgreements = [String]() let verificationMethods: [VerificationMethod] = try from.verificationMethods.compactMap { - guard - let jsonKeys = try $0.publicKeyJwk?.convertToJsonString(), - let crv = $0.publicKeyJwk?["crv"] - else { return nil } - switch crv { - case "X25519": + switch KnownVerificationMaterialType(rawValue: $0.type) { + case .agreement: keyAgreements.append($0.id.string) - case "Ed25519": + case .authentication: authentications.append($0.id.string) default: - break + return nil } - return VerificationMethod( - id: $0.id.string, - type: .jsonWebKey2020, - controller: $0.controller.string, - verificationMaterial: .jwk(value: jsonKeys) - ) - } - let services = from.services.compactMap { service in - if service.type.contains("DIDCommMessaging") { - return service.serviceEndpoint.first.map { - Service( - id: service.id, - kind: .didCommMessaging( - value: .init( - serviceEndpoint: $0.uri, - accept: $0.accept, - routingKeys: $0.routingKeys - ) - ) - ) - } + if + let jsonKeys = try $0.publicKeyJwk?.convertToJsonString() + { + return .init( + id: $0.id.string, + controller: $0.controller.string, + type: $0.type, + material: try .fromJWK(jwk: JSONDecoder().decode(JWK.self, from: jsonKeys.tryToData())) + ) + } else if let multibase = $0.publicKeyMultibase { + return .init( + id: $0.id.string, + controller: $0.controller.string, + type: $0.type, + material: .init(format: .multibase, value: try multibase.tryToData()) + ) } else { - return service.serviceEndpoint.first.map { - Service( - id: service.id, - kind: .other(value: $0.uri) + return nil + } + } + + let services = from.services.flatMap { service in + service.serviceEndpoint.map { + return Service( + id: service.id, + type: service.type.first ?? "", + serviceEndpoint: AnyCodable( + dictionaryLiteral: + ("uri", $0.uri), + ("accept", $0.accept), + ("routing_keys", $0.routingKeys) ) - } + ) } } self.init( - did: did, - keyAgreements: keyAgreements, - authentications: authentications, + id: from.id.string, verificationMethods: verificationMethods, + authentication: authentications.map { .stringValue($0) }, + keyAgreement: keyAgreements.map { .stringValue($0) }, services: services ) } diff --git a/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/DIDCommSecretsResolverWrapper.swift b/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/DIDCommSecretsResolverWrapper.swift index b48e9f10..e8104f70 100644 --- a/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/DIDCommSecretsResolverWrapper.swift +++ b/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/DIDCommSecretsResolverWrapper.swift @@ -1,6 +1,7 @@ import Combine import Core -import DIDCommxSwift +import DIDCommSwift +import DIDCore import Domain import Foundation @@ -22,135 +23,78 @@ class DIDCommSecretsResolverWrapper { } fileprivate func getListOfAllSecrets() async throws -> [Domain.Secret] { -// try await pluto -// .getAllPeerDIDs() -// .first() -// .tryMap { -// try $0.map { did, privateKeys, _ in -// try self.parsePrivateKeys(did: did, privateKeys: privateKeys) -// } -// } -// .map { $0.compactMap { $0 }.flatMap { $0 } } try await secretsStream .first() .await() } - - private func parsePrivateKeys( - did: DID, - privateKeys: [PrivateKey] - ) throws -> [Domain.Secret] { - return try privateKeys - .map { $0 as? (PrivateKey & ExportableKey) } - .compactMap { $0 } - .map { privateKey in - let ecnumbasis = try castor.getEcnumbasis(did: did, publicKey: privateKey.publicKey()) - return (did, privateKey, ecnumbasis) - } - .map { did, privateKey, ecnumbasis in - try parseToSecret(did: did, privateKey: privateKey, ecnumbasis: ecnumbasis) - } - } - - private func parseToSecret(did: DID, privateKey: PrivateKey & ExportableKey, ecnumbasis: String) throws -> Domain.Secret { - let id = did.string + "#" + ecnumbasis - let jwk = privateKey.jwk - guard - let dataJson = try? JSONEncoder().encode(jwk), - let stringJson = String(data: dataJson, encoding: .utf8) - else { - throw CommonError.invalidCoding(message: "Could not encode privateKey.jwk") - } - return .init( - id: id, - type: .jsonWebKey2020, - secretMaterial: .jwk(value: stringJson) - ) - } } -extension DIDCommSecretsResolverWrapper: SecretsResolver { - func getSecret( - secretid: String, - cb: OnGetSecretResult - ) -> ErrorCode { - Task { - do { - // Fix: Fixes a bug currently happening on didcomm library that is adding a / before the fragment sign - let secretidsaux = secretid.replacingOccurrences(of: "/#", with: "#") - let secret = try await getListOfAllSecrets() - .first { $0.id == secretidsaux } - // Fix: Fixes a bug currently happening on didcomm library that is adding a / before the fragment sign -// .map { -// Domain.Secret( -// id: secretid, -// type: $0.type, -// secretMaterial: $0.secretMaterial -// ) -// } - try cb.success(result: secret.map { DIDCommxSwift.Secret(from: $0) }) - } catch let error { - let mercuryError = MercuryError.didcommError( - msg: "Could not find secret \(secretid)", - underlyingErrors: [error] - ) - logger.error(error: mercuryError) - } +extension DIDCommSecretsResolverWrapper: DIDCommSwift.SecretResolver { + func findKey(kid: String) async throws -> DIDCommSwift.Secret? { + guard + let secret = try? await getListOfAllSecrets() + .first(where: { + $0.id == kid + }) + else { + let error = MercuryError.didcommError( + msg: "Could not find secret \(kid)", + underlyingErrors: nil + ) + logger.error(error: error) + throw error } - return .success + return try .init(from: secret) + } - - func findSecrets( - secretids: [String], - cb: OnFindSecretsResult - ) -> ErrorCode { - Task { - do { - // Fixes a bug currently happening on didcomm library that is adding a / before the fragment sign - let secretidsaux = secretids.map { $0.replacingOccurrences(of: "/#", with: "#") } - let secrets = try await getListOfAllSecrets() - .filter { secretidsaux.contains($0.id) } - .map { $0.id } - let secretsSet = Set(secretidsaux) - let resultsSet = Set(secrets) - let missingSecrets = secretsSet.subtracting(resultsSet) - if !missingSecrets.isEmpty { - logger.error(message: -""" -Could not find secrets the following secrets: \(missingSecrets.joined(separator: ", ")) -""" - ) - } - try cb.success(result: secretids) - } catch { - let mercuryError = MercuryError.didcommError( - msg: "Could not find secrets \(secretids.joined(separator: "\n"))", - underlyingErrors: [error] - ) - logger.error(error: mercuryError) - } + func findKeys(kids: Set) async throws -> Set { + let secretidsaux = kids.map { $0.replacingOccurrences(of: "/#", with: "#") } + let secrets = try await getListOfAllSecrets() + .filter { secretidsaux.contains($0.id) } + .map { $0.id } + let secretsSet = Set(secretidsaux) + let resultsSet = Set(secrets) + let missingSecrets = secretsSet.subtracting(resultsSet) + if !missingSecrets.isEmpty { + let mercuryError = MercuryError.didcommError( + msg: "Could not find secrets \(missingSecrets.joined(separator: "\n"))", + underlyingErrors: nil + ) + logger.error(error: mercuryError) } - return .success + return kids } } -extension DIDCommxSwift.Secret { - init(from: Domain.Secret) { - let type: SecretType - let material: SecretMaterial - switch from.type { - case .jsonWebKey2020: - type = .jsonWebKey2020 +extension DIDCommSwift.Secret { + init(from: Domain.Secret) throws { + let type: KnownVerificationMaterialType + let material: VerificationMaterial + let jwkData: Data + switch from.secretMaterial { + case .jwk(let value): + jwkData = try value.tryToData() + } + + let jwk = try JSONDecoder().decode(DIDCore.JWK.self, from: jwkData) + + switch (from.type, jwk.crv?.lowercased()) { + case (.jsonWebKey2020, "x25519"): + type = .agreement(.jsonWebKey2020) + case (.jsonWebKey2020, "ed25519"): + type = .authentication(.jsonWebKey2020) + default: + type = .authentication(.jsonWebKey2020) } switch from.secretMaterial { case let .jwk(value): - material = .jwk(value: value) + material = try .fromJWK(jwk: jwk) } self.init( - id: from.id, + kid: from.id, type: type, - secretMaterial: material + verificationMaterial: material ) } } diff --git a/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/PackEncryptedOperation.swift b/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/PackEncryptedOperation.swift index 07925b66..91a76acb 100644 --- a/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/PackEncryptedOperation.swift +++ b/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/PackEncryptedOperation.swift @@ -1,17 +1,17 @@ import Combine import Core -import DIDCommxSwift +import DIDCommSwift import Domain import Foundation -final class PackEncryptedOperation: OnPackEncryptedResult { - private let didcomm: DIDCommProtocol +final class PackEncryptedOperation { + private let didcomm: DIDComm private let logger: PrismLogger private let message: Domain.Message private var published = CurrentValueSubject(nil) private var cancellable: AnyCancellable? - init(didcomm: DIDCommProtocol, message: Domain.Message, logger: PrismLogger) { + init(didcomm: DIDComm, message: Domain.Message, logger: PrismLogger) { self.didcomm = didcomm self.logger = logger self.message = message @@ -20,86 +20,12 @@ final class PackEncryptedOperation: OnPackEncryptedResult { func packEncrypted() async throws -> String { guard let fromDID = message.from else { throw MercuryError.noSenderDIDSetError } guard let toDID = message.to else { throw MercuryError.noRecipientDIDSetError } - - let result: String = try await withCheckedThrowingContinuation { [weak self] continuation in - guard let self else { return } - self.cancellable = self.published - .drop(while: { $0 == nil }) - .first() - .sink(receiveCompletion: { [weak self] in - switch $0 { - case .finished: - break - case let .failure(error): - self?.logger.error( - message: "Could not pack message", - metadata: [ - .publicMetadata(key: "Error", value: error.localizedDescription) - ] - ) - continuation.resume(throwing: error) - } - }, receiveValue: { - guard let result = $0 else { return } - continuation.resume(returning: result) - }) - do { - logger.debug(message: "Packing message \(message.piuri)", metadata: [ - .maskedMetadataByLevel(key: "Sender", value: fromDID.string, level: .debug), - .maskedMetadataByLevel(key: "Receiver", value: toDID.string, level: .debug) - ]) - let status = didcomm.packEncrypted( - msg: try DIDCommxSwift.Message(domain: message, mediaType: .contentTypePlain), - to: toDID.string, - from: fromDID.string, - signBy: nil, - options: .init( - protectSender: false, - forward: false, - forwardHeaders: nil, - messagingService: nil, - encAlgAuth: .a256cbcHs512Ecdh1puA256kw, - encAlgAnon: .xc20pEcdhEsA256kw - ), - cb: self - ) - switch status { - case.success: - break - case .error: - continuation.resume(throwing: MercuryError.didcommError( - msg: "Unknown error on initializing pack encrypted function" - )) - } - } catch { - continuation.resume(throwing: MercuryError.didcommError( - msg: "Error on parsing Domain message to DIDComm library model: \(error.localizedDescription)" - )) - } - } - return result - } - - func success(result: String, metadata: PackEncryptedMetadata) { - published.send(result) - published.send(completion: .finished) - } - - func error(err: DIDCommxSwift.ErrorKind, msg: String) { - let error = MercuryError.didcommError( - msg: """ -Error on trying to pack encrypted a message of type \(message.piuri): \(msg) -""" - ) - logger.error( - message: "Packing message failed with error", - metadata: [ - .publicMetadata( - key: "Error", - value: error.errorDescription ?? "" - ) - ] - ) - published.send(completion: .failure(error)) + + return try await didcomm.packEncrypted(params: .init( + message: .init(domain: message, mediaType: .contentTypeEncrypted), + to: [toDID.string], + from: fromDID.string, + encAlgAuth: .a256CBCHS512 + )).packedMessage } } diff --git a/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/UnpackOperation.swift b/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/UnpackOperation.swift index 5fa78939..cfc7612d 100644 --- a/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/UnpackOperation.swift +++ b/AtalaPrismSDK/Mercury/Sources/DIDCommWrappers/UnpackOperation.swift @@ -1,104 +1,25 @@ import Combine import Core -import DIDCommxSwift +import DIDCommSwift import Domain import Foundation -final class UnpackOperation: OnUnpackResult { - private let didcomm: DIDCommProtocol +final class UnpackOperation { + private let didcomm: DIDComm private let castor: Castor private let logger: PrismLogger private var published = CurrentValueSubject(nil) private var cancellable: AnyCancellable? - init(didcomm: DIDCommProtocol, castor: Castor, logger: PrismLogger) { + init(didcomm: DIDComm, castor: Castor, logger: PrismLogger) { self.didcomm = didcomm self.castor = castor self.logger = logger } func unpackEncrypted(messageString: String) async throws -> Domain.Message { - let status = didcomm.unpack( - msg: messageString, - options: .init(expectDecryptByAllKeys: false, unwrapReWrappingForward: false), - cb: self - ) - - switch status { - case.success: - return try await withCheckedThrowingContinuation { [weak self] continuation in - guard let self else { return } - self.cancellable = self.published - .drop(while: { $0 == nil }) - .first() - .sink(receiveCompletion: { [weak self] in - switch $0 { - case .finished: - break - case let .failure(error): - self?.logger.error( - message: "Could not unpack message", - metadata: [ - .publicMetadata(key: "Error", value: error.localizedDescription) - ] - ) - continuation.resume(throwing: error) - } - }, receiveValue: { - guard let result = $0 else { return } - continuation.resume(returning: result) - }) - } - case .error: - throw MercuryError.didcommError( - msg: "Unknown error on initializing unpack message function" - ) - } - } - - func success(result: DIDCommxSwift.Message, metadata: DIDCommxSwift.UnpackMetadata) { - do { - let message: Domain.Message = try result.toDomain(castor: castor) - published.send(message) - } catch let error as LocalizedError { - logger.error( - message: "Could not unpack message", - metadata: [ - .publicMetadata(key: "Error", value: error.localizedDescription) - ] - ) - published.send(completion: .failure(MercuryError.didcommError( - msg: -""" -Error on parsing DIDComm library model message to Domain message : \(error.errorDescription ?? "") -""" - ))) - } catch { - published.send(completion: .failure(MercuryError.didcommError( - msg: -""" -Error on parsing DIDComm library model message to Domain message : \(error.localizedDescription) -""" - ))) - } - } - - func error(err: DIDCommxSwift.ErrorKind, msg: String) { - let error = MercuryError.didcommError( - msg: -""" -Error on trying to unpack a message: \(msg) -""" - ) - logger.error( - message: "Unpack message failed with error", - metadata: [ - .publicMetadata( - key: "Error", - value: error.errorDescription ?? "" - ) - ] - ) - published.send(completion: .failure(error)) + return try await didcomm.unpack(params: .init( + packedMessage: messageString + )).message.toDomain(castor: castor) } } diff --git a/AtalaPrismSDK/Mercury/Sources/Helpers/DIDCommMessage+DomainParse.swift b/AtalaPrismSDK/Mercury/Sources/Helpers/DIDCommMessage+DomainParse.swift index 4a960695..fdafc48c 100644 --- a/AtalaPrismSDK/Mercury/Sources/Helpers/DIDCommMessage+DomainParse.swift +++ b/AtalaPrismSDK/Mercury/Sources/Helpers/DIDCommMessage+DomainParse.swift @@ -1,112 +1,129 @@ import Core -import DIDCommxSwift +import DIDCommSwift import Domain import Foundation -extension DIDCommxSwift.Message { +extension DIDCommSwift.Message { init(domain: Domain.Message, mediaType: MediaType) throws { - let jsonString = String(data: domain.body, encoding: .utf8) ?? "{}" let from = domain.from?.string - let to = domain.to?.string self.init( id: domain.id, - typ: mediaType.rawValue, + body: try domain.body.isEmpty ? "{}".tryToData() : domain.body, type: domain.piuri, - body: jsonString.isEmpty ? "{}" : jsonString, - from: domain.from?.string, + typ: .plainText, + from: from, to: domain.to.map { [$0.string] }, + createdTime: domain.createdTime, + expiresTime: domain.expiresTimePlus, + fromPrior: domain.fromPrior.flatMap { + try? JSONDecoder().decode(FromPrior.self, from: $0.tryToData()) + }, + fromPriorJwt: nil, + attachments: try domain.attachments.map { try .init(domain: $0) }, + pleaseAck: nil, + ack: domain.ack.first, thid: domain.thid, pthid: domain.pthid, - extraHeaders: domain.extraHeaders, - createdTime: domain.createdTime.millisecondsSince1970, - expiresTime: domain.expiresTimePlus.millisecondsSince1970, - fromPrior: domain.fromPrior, - attachments: try domain.attachments.map { - try Attachment(domain: $0) - } + customHeaders: domain.extraHeaders ) } func toDomain(castor: Castor) throws -> Domain.Message { - guard let data = self.body.data(using: .utf8) else { - throw MercuryError.messageInvalidBodyDataError - } - let message = Domain.Message( + Domain.Message( id: self.id, piuri: self.type, - from: try self.from.map { try DID(string: $0) }, - to: try self.to?.first.map { try DID(string: $0) }, - fromPrior: self.fromPrior, - body: data, - extraHeaders: self.extraHeaders, - createdTime: self.createdTime - .map { Date(milliseconds: $0) } ?? Date(), - expiresTimePlus: self.expiresTime - .map { Date(milliseconds: $0) } ?? Date(), + from: try self.from.map { try Domain.DID(string: $0) }, + to: try self.to?.first.map { try Domain.DID(string: $0) }, + fromPrior: try self.fromPrior.map { try JSONEncoder.didComm().encode($0) }?.tryToString(), + body: self.body ?? Data(), + extraHeaders: self.customHeaders ?? [:], + createdTime: self.createdTime ?? Date(), + expiresTimePlus: self.expiresTime ?? Date(), attachments: try self.attachments?.map { try $0.toDomain() } ?? [], thid: self.thid, pthid: self.pthid, - ack: [] + ack: self.ack.map { [$0] } ?? [] ) - return message } } -extension DIDCommxSwift.Attachment { +extension DIDCommSwift.Attachment { init(domain: Domain.AttachmentDescriptor) throws { self.init( - data: try .init(domain: domain.data), id: domain.id, + data: try domain.data.toDIDComm(), description: domain.description, - filename: domain.filename?.joined(separator: "/"), + filename: domain.filename?.first, mediaType: domain.mediaType, format: domain.format, - lastmodTime: domain.lastmodTime.map { UInt64($0.timeIntervalSince1970) }, - byteCount: domain.byteCount.map { UInt64($0) } + lastModTime: domain.lastmodTime, + byteCount: domain.byteCount ) } func toDomain() throws -> Domain.AttachmentDescriptor { - guard let id = self.id else { throw MercuryError.messageAttachmentWithoutIDError } return .init( id: id, mediaType: self.mediaType, data: try self.data.toDomain(), filename: self.filename?.components(separatedBy: "/"), format: self.format, - lastmodTime: self.lastmodTime.map { Date(timeIntervalSince1970: TimeInterval($0)) }, + lastmodTime: self.lastModTime, byteCount: self.byteCount.map { Int($0) }, description: self.description ) } } -extension DIDCommxSwift.AttachmentData { - init(domain: Domain.AttachmentData) throws { - if let base64Data = domain as? AttachmentBase64 { - self = .base64(value: .init(base64: base64Data.base64, jws: nil)) - } else if let linkData = domain as? AttachmentLinkData { - self = .links(value: .init(links: linkData.links, hash: linkData.hash, jws: nil)) - } else if let jsonData = domain as? AttachmentJsonData { - self = .json(value: .init(json: String(data: jsonData.data, encoding: .utf8)!, jws: nil)) - } else if let jwsData = domain as? AttachmentJwsData { - self = .base64(value: .init(base64: jwsData.base64, jws: jwsData.jws.signature)) +extension Domain.AttachmentData { + func toDIDComm() throws -> DIDCommSwift.AttachmentData { + if let base64Data = self as? AttachmentBase64 { + return Base64AttachmentData( + hash: nil, + jws: nil, + base64: base64Data.base64 + ) + } else if let linkData = self as? AttachmentLinkData { + return LinksAttachmentData( + hash: linkData.hash, + jws: nil, + links: linkData.links + ) + } else if let jsonData = self as? AttachmentJsonData { + return try JsonAttachmentData( + hash: nil, + jws: nil, + json: jsonData.data.tryToString() + ) + } else if let jwsData = self as? AttachmentJwsData { + return Base64AttachmentData( + hash: nil, + jws: jwsData.base64, + base64: jwsData.jws.signature + ) } else { throw MercuryError.unknownAttachmentDataTypeError } } +} +extension DIDCommSwift.AttachmentData { func toDomain() throws -> Domain.AttachmentData { switch self { - case let .base64(value): + case let value as Base64AttachmentData: return AttachmentBase64(base64: value.base64) - case let .links(value): - return AttachmentLinkData(links: value.links, hash: value.hash) - case let .json(value): + case let value as LinksAttachmentData: + guard let hash = value.hash else { + throw MercuryError.unknownAttachmentDataTypeError + } + return AttachmentLinkData(links: value.links, hash: hash) + case let value as JsonAttachmentData: guard let jsonData = value.json.data(using: .utf8) else { throw MercuryError.unknownAttachmentDataTypeError } return AttachmentJsonData(data: jsonData) + default: + throw MercuryError.unknownAttachmentDataTypeError } } } diff --git a/AtalaPrismSDK/Mercury/Sources/MercuryImpl+Public.swift b/AtalaPrismSDK/Mercury/Sources/MercuryImpl+Public.swift index d54c3a6c..889338e7 100644 --- a/AtalaPrismSDK/Mercury/Sources/MercuryImpl+Public.swift +++ b/AtalaPrismSDK/Mercury/Sources/MercuryImpl+Public.swift @@ -1,5 +1,5 @@ import Core -import DIDCommxSwift +import DIDCommSwift import Domain import Foundation diff --git a/AtalaPrismSDK/Mercury/Sources/MercuryImpl.swift b/AtalaPrismSDK/Mercury/Sources/MercuryImpl.swift index 9f44cee4..3db2afca 100644 --- a/AtalaPrismSDK/Mercury/Sources/MercuryImpl.swift +++ b/AtalaPrismSDK/Mercury/Sources/MercuryImpl.swift @@ -1,6 +1,6 @@ import Combine import Core -import DIDCommxSwift +import DIDCommSwift import Domain import Foundation @@ -23,14 +23,14 @@ public struct MercuryImpl { self.castor = castor } - func getDidcomm() -> DidComm { + func getDidcomm() -> DIDComm { let didResolver = DIDCommDIDResolverWrapper(castor: castor, logger: logger) let secretsResolver = DIDCommSecretsResolverWrapper( secretsStream: secretsStream, castor: castor, logger: logger ) - return DidComm( + return DIDComm( didResolver: didResolver, secretResolver: secretsResolver ) diff --git a/AtalaPrismSDK/Pluto/Sources/Domain/Providers/KeyProvider.swift b/AtalaPrismSDK/Pluto/Sources/Domain/Providers/KeyProvider.swift new file mode 100644 index 00000000..fa95e10d --- /dev/null +++ b/AtalaPrismSDK/Pluto/Sources/Domain/Providers/KeyProvider.swift @@ -0,0 +1,8 @@ +import Combine +import Domain +import Foundation + +protocol KeyProvider { + func getAll() -> AnyPublisher<[StorableKey], Error> + func getKeyById(id: String) -> AnyPublisher +} diff --git a/AtalaPrismSDK/Pluto/Sources/Domain/StorableKeyModel.swift b/AtalaPrismSDK/Pluto/Sources/Domain/StorableKeyModel.swift index 4a0b44c6..439d9079 100644 --- a/AtalaPrismSDK/Pluto/Sources/Domain/StorableKeyModel.swift +++ b/AtalaPrismSDK/Pluto/Sources/Domain/StorableKeyModel.swift @@ -2,6 +2,7 @@ import Domain import Foundation struct StorableKeyModel: StorableKey { + var identifier: String let restorationIdentifier: String let storableData: Data let index: Int? diff --git a/AtalaPrismSDK/Pluto/Sources/Helpers/Message+Codable.swift b/AtalaPrismSDK/Pluto/Sources/Helpers/Message+Codable.swift index 39a1bfdb..b235852b 100644 --- a/AtalaPrismSDK/Pluto/Sources/Helpers/Message+Codable.swift +++ b/AtalaPrismSDK/Pluto/Sources/Helpers/Message+Codable.swift @@ -48,17 +48,17 @@ struct CodableMessage: Codable { let id = try container.decode(String.self, forKey: .id) let piuri = try container.decode(String.self, forKey: .piuri) let body = try container.decode(Data.self, forKey: .body) - let extraHeaders = try container.decode([String: String].self, forKey: .extraHeaders) - let createdTime = try container.decode(Date.self, forKey: .createdTime) - let expiresTimePlus = try container.decode(Date.self, forKey: .expiresTimePlus) - let attachments = try container.decode([AttachmentDescriptor].self, forKey: .attachments) - let ack = try container.decode([String].self, forKey: .ack) - let from = try? container.decode(CodableDID.self, forKey: .from).did - let to = try? container.decode(CodableDID.self, forKey: .to).did - let fromPrior = try? container.decode(String.self, forKey: .fromPrior) - let thid = try? container.decode(String.self, forKey: .thid) - let pthid = try? container.decode(String.self, forKey: .pthid) - let directionRaw = try? container.decode(String.self, forKey: .direction) + let extraHeaders = try container.decodeIfPresent([String: String].self, forKey: .extraHeaders) + let createdTime = try container.decodeIfPresent(Date.self, forKey: .createdTime) + let expiresTimePlus = try container.decodeIfPresent(Date.self, forKey: .expiresTimePlus) + let attachments = try container.decodeIfPresent([AttachmentDescriptor].self, forKey: .attachments) + let ack = try container.decodeIfPresent([String].self, forKey: .ack) + let from = try? container.decodeIfPresent(CodableDID.self, forKey: .from)?.did + let to = try? container.decodeIfPresent(CodableDID.self, forKey: .to)?.did + let fromPrior = try? container.decodeIfPresent(String.self, forKey: .fromPrior) + let thid = try? container.decodeIfPresent(String.self, forKey: .thid) + let pthid = try? container.decodeIfPresent(String.self, forKey: .pthid) + let directionRaw = try container.decodeIfPresent(String.self, forKey: .direction) let direction = directionRaw.flatMap { Message.Direction(rawValue: $0) } self.init(message: .init( @@ -68,13 +68,13 @@ struct CodableMessage: Codable { to: to, fromPrior: fromPrior, body: body, - extraHeaders: extraHeaders, - createdTime: createdTime, + extraHeaders: extraHeaders ?? [:], + createdTime: createdTime ?? Date(), expiresTimePlus: expiresTimePlus, - attachments: attachments, + attachments: attachments ?? [], thid: thid, pthid: pthid, - ack: ack, + ack: ack ?? [], direction: direction ?? .sent )) } diff --git a/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDDIDPrivateKeyDAO+DIDPrivateKeyStore.swift b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDDIDPrivateKeyDAO+DIDPrivateKeyStore.swift index 9fc4a8d4..ee670bf9 100644 --- a/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDDIDPrivateKeyDAO+DIDPrivateKeyStore.swift +++ b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDDIDPrivateKeyDAO+DIDPrivateKeyStore.swift @@ -10,19 +10,18 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyStore { let keys = try privateKeys.map { switch $0 { case let keychainKey as KeychainStorableKey: - let identifier = computeStorableKeyIdentifier(keychainKey, did: did.string) try storeKeychainKey( did: did, keychainKey: keychainKey, service: self.keyDao.keychainDao.keychainService, - account: identifier, + account: keychainKey.identifier, keychain: self.keyDao.keychainDao.keychain ) let cdkey = CDKeychainKey(entity: CDKeychainKey.entity(), insertInto: context) cdkey.parseFromStorableKey( keychainKey, did: cdobj, - identifier: identifier, + identifier: keychainKey.identifier, service: self.keyDao.keychainDao.keychainService ) return cdkey as CDKey @@ -31,7 +30,7 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyStore { cdkey.parseFromStorableKey( $0, did: cdobj, - identifier: computeStorableKeyIdentifier($0, did: did.string) + identifier: $0.identifier ) return cdkey as CDKey } @@ -64,14 +63,6 @@ private func storeKeychainKey( ) } -private func computeStorableKeyIdentifier(_ key: StorableKey, did: String) -> String { - var returnData = Data() - returnData += did.data(using: .utf8) ?? Data() - returnData += key.restorationIdentifier.data(using: .utf8) ?? Data() - returnData += key.storableData.base64EncodedData() - return SHA256.hash(data: returnData).string -} - private extension CDDIDPrivateKey { func parseFrom(did: DID, alias: String?) { self.alias = alias diff --git a/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO+KeyProvider.swift b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO+KeyProvider.swift new file mode 100644 index 00000000..5ae5c4a2 --- /dev/null +++ b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO+KeyProvider.swift @@ -0,0 +1,21 @@ +import Combine +import Foundation +import Domain + +extension CDKeyDAO: KeyProvider { + func getAll() -> AnyPublisher<[StorableKey], Error> { + fetchController(context: readContext) + .tryMap { + try $0.map { try $0.parseToStorableKey(keychain: self.keychainDao.keychain) } + } + .eraseToAnyPublisher() + } + + func getKeyById(id: String) -> AnyPublisher { + fetchByIDsPublisher(id, context: readContext) + .tryMap { + try $0?.parseToStorableKey(keychain: self.keychainDao.keychain) + } + .eraseToAnyPublisher() + } +} diff --git a/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO+LinkSecretStore.swift b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO+LinkSecretStore.swift index c27bcccf..546e43ae 100644 --- a/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO+LinkSecretStore.swift +++ b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO+LinkSecretStore.swift @@ -6,26 +6,26 @@ extension CDKeyDAO: LinkSecretStore { func addLinkSecret(_ linkSecret: StorableKey) -> AnyPublisher { switch linkSecret { case let keychainKey as KeychainStorableKey: - return keychainDao.updateOrCreate("linkSecret", context: writeContext) { cdobj, context in + return keychainDao.updateOrCreate(linkSecret.identifier, context: writeContext) { cdobj, context in try storeKeychainKey( keychainKey: keychainKey, service: self.keychainDao.keychainService, - account: "linkSecret", + account: linkSecret.identifier, keychain: self.keychainDao.keychain ) cdobj.parseFromStorableKey( keychainKey, - identifier: "linkSecret", + identifier: linkSecret.identifier, service: self.keychainDao.keychainService ) } .map { _ in } .eraseToAnyPublisher() default: - return databaseDAO.updateOrCreate("linkSecret", context: writeContext) { cdobj, context in + return databaseDAO.updateOrCreate(linkSecret.identifier, context: writeContext) { cdobj, context in cdobj.parseFromStorableKey( linkSecret, - identifier: "linkSecret" + identifier: linkSecret.identifier ) } .map { _ in } diff --git a/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO.swift b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO.swift index 81ca0b66..509e8aa1 100644 --- a/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO.swift +++ b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO.swift @@ -51,12 +51,14 @@ extension CDKey { ) return StorableKeyModel( + identifier: keychainKey.identifier, restorationIdentifier: keychainKey.restorationIdentifier, storableData: keyData, index: keychainKey.index?.intValue ) case let databaseKey as CDDatabaseKey: return StorableKeyModel( + identifier: databaseKey.identifier, restorationIdentifier: databaseKey.restorationIdentifier, storableData: databaseKey.storableData, index: databaseKey.index?.intValue diff --git a/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageProvider.swift b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageProvider.swift index 3801de96..3258730f 100644 --- a/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageProvider.swift +++ b/AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageProvider.swift @@ -84,6 +84,6 @@ extension CDMessageDAO: MessageProvider { private extension CDMessage { func toDomain() throws -> Message { - return try JSONDecoder().decode(CodableMessage.self, from: dataJson).message + try JSONDecoder().decode(CodableMessage.self, from: dataJson).message } } diff --git a/AtalaPrismSDK/Pluto/Sources/PlutoImpl+Public.swift b/AtalaPrismSDK/Pluto/Sources/PlutoImpl+Public.swift index 4f4c550c..1c67b254 100644 --- a/AtalaPrismSDK/Pluto/Sources/PlutoImpl+Public.swift +++ b/AtalaPrismSDK/Pluto/Sources/PlutoImpl+Public.swift @@ -112,6 +112,14 @@ extension PlutoImpl: Pluto { pairDIDDao.getAll() } + public func getAllKeys() -> AnyPublisher<[StorableKey], Error> { + keyDao.getAll() + } + + public func getKeyById(id: String) -> AnyPublisher { + keyDao.getKeyById(id: id) + } + public func getPair(otherDID: DID) -> AnyPublisher { pairDIDDao.getPair(otherDID: otherDID) } diff --git a/AtalaPrismSDK/Pluto/Tests/Helper/PrivateKey+Test.swift b/AtalaPrismSDK/Pluto/Tests/Helper/PrivateKey+Test.swift index e70971df..d98d28c8 100644 --- a/AtalaPrismSDK/Pluto/Tests/Helper/PrivateKey+Test.swift +++ b/AtalaPrismSDK/Pluto/Tests/Helper/PrivateKey+Test.swift @@ -6,6 +6,7 @@ struct MockPrivateKey: PrivateKey, StorableKey, Equatable { let keySpecifications: [String : String] let size = 0 let raw: Data + var identifier = "TestMockPrivKey" var index: Int? = 0 let restorationIdentifier = "MockPrivate" @@ -39,6 +40,7 @@ struct MockPublicKey: PublicKey, Equatable { let keySpecifications = [String : String]() let size = 0 let raw: Data + var identifier = "TestMockPubKey" init(str: String = "TestPublic") { self.raw = str.data(using: .utf8)! diff --git a/AtalaPrismSDK/Pollux/Sources/Models/AnonCreds/AnoncredsCredentialStack.swift b/AtalaPrismSDK/Pollux/Sources/Models/AnonCreds/AnoncredsCredentialStack.swift index 414309e1..b13bad32 100644 --- a/AtalaPrismSDK/Pollux/Sources/Models/AnonCreds/AnoncredsCredentialStack.swift +++ b/AtalaPrismSDK/Pollux/Sources/Models/AnonCreds/AnoncredsCredentialStack.swift @@ -16,7 +16,7 @@ extension AnoncredsCredentialStack: Domain.Credential { assert(false, "This should never happen") return "" } - return jsonData.sha256.hex + return jsonData.sha256().hex } var issuer: String { diff --git a/AtalaPrismSDK/Pollux/Sources/Models/JWT/JWTPresentation.swift b/AtalaPrismSDK/Pollux/Sources/Models/JWT/JWTPresentation.swift index e5781424..93c052c2 100644 --- a/AtalaPrismSDK/Pollux/Sources/Models/JWT/JWTPresentation.swift +++ b/AtalaPrismSDK/Pollux/Sources/Models/JWT/JWTPresentation.swift @@ -1,9 +1,10 @@ import Domain import Foundation -import SwiftJWT - -struct VerifiablePresentationPayload: Claims { +import JSONWebSignature +import JSONWebToken +struct VerifiablePresentationPayload: JWTRegisteredFieldsClaims { + struct VerifiablePresentation: Codable { enum CodingKeys: String, CodingKey { case context = "@context" @@ -16,10 +17,17 @@ struct VerifiablePresentationPayload: Claims { let verifiableCredential: [String] } - let iss: String - let aud: String + let issuer: String? + let subject: String? + let audience: [String]? + let expirationTime: Date? + let notBeforeTime: Date? + let issuedAt: Date? + let jwtID: String? let nonce: String let vp: [VerifiablePresentation] + + func validateExtraClaims() throws {} } struct JWTPresentation { @@ -67,23 +75,53 @@ struct JWTPresentation { let domain = findValue(forKey: "domain", in: jsonObject), let challenge = findValue(forKey: "challenge", in: jsonObject) else { throw PolluxError.offerDoesntProvideEnoughInformation } - - let jwt = JWT(claims: ClaimsProofPresentationJWT( - iss: did.string, - aud: domain, - nonce: challenge, - vp: .init( - context: .init(["https://www.w3.org/2018/presentations/v1"]), - type: .init(["VerifiablePresentation"]), - verifiableCredential: [credential.jwtString] + + let keyJWK = exportableKey.jwk + + let jwt = try JWT.signed( + payload: ClaimsProofPresentationJWT( + issuer: did.string, + subject: nil, + audience: [domain], + expirationTime: nil, + notBeforeTime: nil, + issuedAt: nil, + jwtID: nil, + nonce: challenge, + vp: .init( + context: .init(["https://www.w3.org/2018/presentations/v1"]), + type: .init(["VerifiablePresentation"]), + verifiableCredential: [credential.jwtString] + ) + ), + protectedHeader: DefaultJWSHeaderImpl(algorithm: .ES256K), + key: .init( + keyType: .init(rawValue: keyJWK.kty)!, + keyID: keyJWK.kid, + x: keyJWK.x.flatMap { Data(fromBase64URL: $0) }, + y: keyJWK.y.flatMap { Data(fromBase64URL: $0) }, + d: keyJWK.d.flatMap { Data(fromBase64URL: $0) } ) - )) - let jwtString = try JWTEncoder(jwtSigner: .es256k(privateKey: pemData)).encodeToString(jwt) - return jwtString + ) + + // We need to do for now this process so the signatures of secp256k1 Bitcoin can be verified by Bouncy castle + let jwtString = jwt.jwtString + var components = jwtString.components(separatedBy: ".") + guard + let signature = components.last, + let signatureData = Data(fromBase64URL: signature) + else { + return jwtString + } + + let (r, s) = extractRS(from: signatureData) + let fipsSignature = (Data(r.reversed()) + Data(s.reversed())).base64UrlEncodedString() + _ = components.removeLast() + return (components + [fipsSignature]).joined(separator: ".") } } -private struct ClaimsProofPresentationJWT: Claims { +private struct ClaimsProofPresentationJWT: JWTRegisteredFieldsClaims { struct VerifiablePresentation: Codable { enum CodingKeys: String, CodingKey { case context = "@context" @@ -96,8 +134,35 @@ private struct ClaimsProofPresentationJWT: Claims { let verifiableCredential: [String] } - let iss: String - let aud: String + let issuer: String? + let subject: String? + let audience: [String]? + let expirationTime: Date? + let notBeforeTime: Date? + let issuedAt: Date? + let jwtID: String? let nonce: String let vp: VerifiablePresentation + + func validateExtraClaims() throws {} + + enum CodingKeys: String, CodingKey { + case issuer = "iss" + case subject = "sub" + case audience = "aud" + case expirationTime = "exp" + case notBeforeTime = "nbf" + case issuedAt = "iat" + case jwtID = "jti" + case nonce + case vp + } +} + +private func extractRS(from signature: Data) -> (r: Data, s: Data) { + let rIndex = signature.startIndex + let sIndex = signature.index(rIndex, offsetBy: 32) + let r = signature[rIndex.. String { + static func create(didStr: String, key: ExportableKey, offerData: Data) throws -> String { let jsonObject = try JSONSerialization.jsonObject(with: offerData) guard let domain = findValue(forKey: "domain", in: jsonObject), let challenge = findValue(forKey: "challenge", in: jsonObject) else { throw PolluxError.offerDoesntProvideEnoughInformation } - let jwt = JWT(claims: ClaimsRequestSignatureJWT( - iss: didStr, - aud: domain, - nonce: challenge, - vp: .init(context: .init([ - "https://www.w3.org/2018/presentations/v1" - ]), type: .init([ - "VerifiablePresentation" - ])) - )) + let keyJWK = key.jwk - return try JWTEncoder(jwtSigner: .es256k(privateKey: pem)).encodeToString(jwt) + let jwt = try JWT.signed( + payload: ClaimsRequestSignatureJWT( + issuer: didStr, + subject: nil, + audience: [domain], + expirationTime: nil, + notBeforeTime: nil, + issuedAt: nil, + jwtID: nil, + nonce: challenge, + vp: .init(context: .init([ + "https://www.w3.org/2018/presentations/v1" + ]), type: .init([ + "VerifiablePresentation" + ])) + ), + protectedHeader: DefaultJWSHeaderImpl(algorithm: .ES256K), + key: .init( + keyType: .init(rawValue: keyJWK.kty)!, + keyID: keyJWK.kid, + x: keyJWK.x.flatMap { Data(fromBase64URL: $0) }, + y: keyJWK.y.flatMap { Data(fromBase64URL: $0) }, + d: keyJWK.d.flatMap { Data(fromBase64URL: $0) } + ) + ) + + // We need to do for now this process so the signatures of secp256k1 Bitcoin can be verified by Bouncy castle + let jwtString = jwt.jwtString + var components = jwtString.components(separatedBy: ".") + guard + let signature = components.last, + let signatureData = Data(fromBase64URL: signature) + else { + return jwtString + } + + let (r, s) = extractRS(from: signatureData) + let fipsSignature = (Data(r.reversed()) + Data(s.reversed())).base64UrlEncodedString() + _ = components.removeLast() + return (components + [fipsSignature]).joined(separator: ".") } } -struct ClaimsRequestSignatureJWT: Claims { +struct ClaimsRequestSignatureJWT: JWTRegisteredFieldsClaims { struct VerifiablePresentation: Codable { enum CodingKeys: String, CodingKey { case context = "@context" @@ -44,10 +75,29 @@ struct ClaimsRequestSignatureJWT: Claims { let type: Set } - let iss: String - let aud: String + let issuer: String? + let subject: String? + let audience: [String]? + let expirationTime: Date? + let notBeforeTime: Date? + let issuedAt: Date? + let jwtID: String? let nonce: String let vp: VerifiablePresentation + + func validateExtraClaims() throws {} + + enum CodingKeys: String, CodingKey { + case issuer = "iss" + case subject = "sub" + case audience = "aud" + case expirationTime = "exp" + case notBeforeTime = "nbf" + case issuedAt = "iat" + case jwtID = "jti" + case nonce + case vp + } } @@ -71,3 +121,11 @@ func findValue(forKey key: String, in json: Any) -> String? { } return nil } + +private func extractRS(from signature: Data) -> (r: Data, s: Data) { + let rIndex = signature.startIndex + let sIndex = signature.index(rIndex, offsetBy: 32) + let r = signature[rIndex.. AnyPublisher<[Domain.StorableKey]?, Error> { Just(nil).tryMap { $0 }.eraseToAnyPublisher() } - + + func getAllKeys() -> AnyPublisher<[StorableKey], Error> { + Just([]).tryMap { $0 }.eraseToAnyPublisher() + } + + func getKeyById(id: String) -> AnyPublisher { + Just(nil).tryMap { $0 }.eraseToAnyPublisher() + } + func getAllDidPairs() -> AnyPublisher<[Domain.DIDPair], Error> { Just([]).tryMap { $0 }.eraseToAnyPublisher() } diff --git a/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Credentials.swift b/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Credentials.swift index 3346efc2..c65fa6fc 100644 --- a/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Credentials.swift +++ b/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Credentials.swift @@ -2,7 +2,7 @@ import Core import Combine import Domain import Foundation -import SwiftJWT +import JSONWebToken // MARK: Verifiable credentials functionalities public extension PrismAgent { diff --git a/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+DIDHigherFucntions.swift b/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+DIDHigherFucntions.swift index 49fa0c2d..980efd5b 100644 --- a/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+DIDHigherFucntions.swift +++ b/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+DIDHigherFucntions.swift @@ -133,12 +133,12 @@ Could not find key in storage please use Castor instead and provide the private alias: String? = "", updateMediator: Bool ) async throws -> DID { - let keyAgreementPrivateKey = try apollo.createPrivateKey(parameters: [ + var keyAgreementPrivateKey = try apollo.createPrivateKey(parameters: [ KeyProperties.type.rawValue: "EC", KeyProperties.curve.rawValue: KnownKeyCurves.x25519.rawValue ]) - let authenticationPrivateKey = try apollo.createPrivateKey(parameters: [ + var authenticationPrivateKey = try apollo.createPrivateKey(parameters: [ KeyProperties.type.rawValue: "EC", KeyProperties.curve.rawValue: KnownKeyCurves.ed25519.rawValue ]) @@ -161,6 +161,10 @@ Could not find key in storage please use Castor instead and provide the private services: withServices ) + let didDocument = try await castor.resolveDID(did: newDID) + didDocument.authenticate.first.map { authenticationPrivateKey.identifier = $0.id.string } + didDocument.keyAgreement.first.map { keyAgreementPrivateKey.identifier = $0.id.string } + logger.debug(message: "Created new Peer DID", metadata: [ .maskedMetadataByLevel(key: "DID", value: newDID.string, level: .debug) ]) diff --git a/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Proof.swift b/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Proof.swift index adc2ce6d..e2db1860 100644 --- a/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Proof.swift +++ b/AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Proof.swift @@ -2,7 +2,7 @@ import Core import Combine import Domain import Foundation -import SwiftJWT +import JSONWebToken // MARK: Credentials proof functionalities public extension PrismAgent { @@ -85,7 +85,6 @@ public extension PrismAgent { comment: request.body.comment ), attachments: [.init( - mediaType: "prism/jwt", data: AttachmentBase64(base64: base64String) )], thid: request.thid, diff --git a/AtalaPrismSDK/PrismAgent/Sources/PrismAgent.swift b/AtalaPrismSDK/PrismAgent/Sources/PrismAgent.swift index 02571fd6..9d440af5 100644 --- a/AtalaPrismSDK/PrismAgent/Sources/PrismAgent.swift +++ b/AtalaPrismSDK/PrismAgent/Sources/PrismAgent.swift @@ -219,49 +219,41 @@ private func createSecretsStream( pluto: Pluto, castor: Castor ) -> AnyPublisher<[Secret], Error> { - pluto.getAllPeerDIDs() + pluto.getAllKeys() .first() - .flatMap { array in + .flatMap { keys in Future { - try await array.asyncMap { did, privateKeys, _ in - let privateKeys = try await privateKeys.asyncMap { - try await keyRestoration.restorePrivateKey($0) - } - return try parsePrivateKeys( - did: did, - privateKeys: privateKeys, - castor: castor - ) - } + let privateKeys = await keys.asyncMap { + try? await keyRestoration.restorePrivateKey($0) + }.compactMap { $0 } + return try parsePrivateKeys( + privateKeys: privateKeys, + castor: castor + ) } } - .map { $0.compactMap { $0 }.flatMap { $0 } } .eraseToAnyPublisher() } private func parsePrivateKeys( - did: DID, privateKeys: [PrivateKey], castor: Castor ) throws -> [Domain.Secret] { return try privateKeys - .map { $0 as? (PrivateKey & ExportableKey) } + .map { $0 as? (PrivateKey & ExportableKey & StorableKey) } .compactMap { $0 } .map { privateKey in - let ecnumbasis = try castor.getEcnumbasis(did: did, publicKey: privateKey.publicKey()) - return (did, privateKey, ecnumbasis) + return privateKey } - .map { did, privateKey, ecnumbasis in + .map { privateKey in try parseToSecret( - did: did, privateKey: privateKey, - ecnumbasis: ecnumbasis + identifier: privateKey.identifier ) } } -private func parseToSecret(did: DID, privateKey: PrivateKey & ExportableKey, ecnumbasis: String) throws -> Domain.Secret { - let id = did.string + "#" + ecnumbasis +private func parseToSecret(privateKey: PrivateKey & ExportableKey, identifier: String) throws -> Domain.Secret { let jwk = privateKey.jwk guard let dataJson = try? JSONEncoder().encode(jwk), @@ -270,7 +262,7 @@ private func parseToSecret(did: DID, privateKey: PrivateKey & ExportableKey, ecn throw CommonError.invalidCoding(message: "Could not encode privateKey.jwk") } return .init( - id: id, + id: identifier, type: .jsonWebKey2020, secretMaterial: .jwk(value: stringJson) ) diff --git a/AtalaPrismSDK/PrismAgent/Sources/Protocols/Mediation/MediationKeysUpdateList.swift b/AtalaPrismSDK/PrismAgent/Sources/Protocols/Mediation/MediationKeysUpdateList.swift index f0a626e9..f004d916 100644 --- a/AtalaPrismSDK/PrismAgent/Sources/Protocols/Mediation/MediationKeysUpdateList.swift +++ b/AtalaPrismSDK/PrismAgent/Sources/Protocols/Mediation/MediationKeysUpdateList.swift @@ -39,7 +39,8 @@ struct MediationKeysUpdateList { piuri: type, from: from, to: to, - body: try JSONEncoder.didComm().encode(body) + body: try JSONEncoder.didComm().encode(body), + extraHeaders: ["return_route":"all"] ) } } diff --git a/AtalaPrismSDK/PrismAgent/Sources/Protocols/Mediation/MediationRequest.swift b/AtalaPrismSDK/PrismAgent/Sources/Protocols/Mediation/MediationRequest.swift index 0ee4594a..b7ca7454 100644 --- a/AtalaPrismSDK/PrismAgent/Sources/Protocols/Mediation/MediationRequest.swift +++ b/AtalaPrismSDK/PrismAgent/Sources/Protocols/Mediation/MediationRequest.swift @@ -23,7 +23,8 @@ struct MediationRequest { piuri: type, from: from, to: to, - body: Data() + body: Data(), + extraHeaders: ["return_route":"all"] ) } } diff --git a/AtalaPrismSDK/PrismAgent/Sources/Protocols/Pickup/PickupRequest.swift b/AtalaPrismSDK/PrismAgent/Sources/Protocols/Pickup/PickupRequest.swift index 936323ec..71d87e10 100644 --- a/AtalaPrismSDK/PrismAgent/Sources/Protocols/Pickup/PickupRequest.swift +++ b/AtalaPrismSDK/PrismAgent/Sources/Protocols/Pickup/PickupRequest.swift @@ -26,7 +26,8 @@ struct PickUpRequest { piuri: ProtocolTypes.pickupRequest.rawValue, from: from, to: to, - body: body + body: body, + extraHeaders: ["return_route":"all"] ) } } diff --git a/AtalaPrismSDK/PrismAgent/Sources/Protocols/Pickup/PrickupReceived.swift b/AtalaPrismSDK/PrismAgent/Sources/Protocols/Pickup/PrickupReceived.swift index e3962557..83f87dd9 100644 --- a/AtalaPrismSDK/PrismAgent/Sources/Protocols/Pickup/PrickupReceived.swift +++ b/AtalaPrismSDK/PrismAgent/Sources/Protocols/Pickup/PrickupReceived.swift @@ -21,7 +21,8 @@ struct PickUpReceived { piuri: ProtocolTypes.pickupReceived.rawValue, from: from, to: to, - body: body + body: body, + extraHeaders: ["return_route":"all"] ) } } diff --git a/Package.swift b/Package.swift index 536ea64a..23b9d772 100644 --- a/Package.swift +++ b/Package.swift @@ -56,10 +56,9 @@ let package = Package( from: "1.4.4" ), .package(url: "git@github.com:apple/swift-protobuf.git", from: "1.7.0"), - .package(url: "git@github.com:input-output-hk/atala-prism-didcomm-swift.git", from: "0.3.6"), - .package(url: "git@github.com:swift-libp2p/swift-multibase.git", from: "0.0.1"), - .package(url: "git@github.com:GigaBitcoin/secp256k1.swift.git", exact: "0.10.0"), - .package(url: "git@github.com:goncalo-frade-iohk/Swift-JWT.git", from: "4.1.3"), + .package(url: "https://github.com/beatt83/didcomm-swift.git", from: "0.1.1"), + .package(url: "https://github.com/beatt83/jose-swift.git", from: "1.2.1"), + .package(url: "https://github.com/beatt83/peerdid-swift.git", from: "2.0.2"), .package(url: "https://github.com/input-output-hk/anoncreds-rs.git", exact: "0.4.1"), .package(url: "https://github.com/input-output-hk/atala-prism-apollo.git", exact: "1.2.10"), ], @@ -91,7 +90,6 @@ let package = Package( dependencies: [ "Domain", "Core", - .product(name: "secp256k1", package: "secp256k1.swift"), .product(name: "AnoncredsSwift", package: "anoncreds-rs"), .product(name: "ApolloLibrary", package: "atala-prism-apollo") ], @@ -102,7 +100,7 @@ let package = Package( dependencies: [ "Domain", "Core", - .product(name: "Multibase", package: "swift-multibase"), + .product(name: "PeerDID", package: "peerdid-swift"), .product(name: "SwiftProtobuf", package: "swift-protobuf") ], path: "AtalaPrismSDK/Castor/Sources" @@ -117,7 +115,7 @@ let package = Package( dependencies: [ "Domain", "Core", - .product(name: "SwiftJWT", package: "Swift-JWT"), + "jose-swift", .product(name: "AnoncredsSwift", package: "anoncreds-rs") ], path: "AtalaPrismSDK/Pollux/Sources" @@ -132,7 +130,7 @@ let package = Package( dependencies: [ "Domain", "Core", - .product(name: "DIDCommxSwift", package: "atala-prism-didcomm-swift") + "didcomm-swift" ], path: "AtalaPrismSDK/Mercury/Sources" ), @@ -165,8 +163,7 @@ let package = Package( dependencies: [ "Domain", "Builders", - "Core", - .product(name: "SwiftJWT", package: "Swift-JWT") + "Core" ], path: "AtalaPrismSDK/PrismAgent/Sources" ), diff --git a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Main/Main2Router.swift b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Main/Main2Router.swift index b0677028..d97ddf06 100644 --- a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Main/Main2Router.swift +++ b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Main/Main2Router.swift @@ -91,56 +91,41 @@ private func createSecretsStream( pluto: Pluto, castor: Castor ) -> AnyPublisher<[Secret], Error> { - pluto.getAllPeerDIDs() + pluto.getAllKeys() .first() - .flatMap { array in + .flatMap { keys in Future { - try await array.asyncMap { did, privateKeys, _ in - let privateKeys = try await privateKeys.asyncMap { - try await keyRestoration.restorePrivateKey($0) - } - let secrets = try parsePrivateKeys( - did: did, - privateKeys: privateKeys, - castor: castor - ) - - return secrets - } + let privateKeys = await keys.asyncMap { + try? await keyRestoration.restorePrivateKey($0) + }.compactMap { $0 } + return try parsePrivateKeys( + privateKeys: privateKeys, + castor: castor + ) } } - .map { - $0.compactMap { - $0 - }.flatMap { - $0 - } } .eraseToAnyPublisher() } private func parsePrivateKeys( - did: DID, privateKeys: [PrivateKey], castor: Castor ) throws -> [Domain.Secret] { return try privateKeys - .map { $0 as? (PrivateKey & ExportableKey) } + .map { $0 as? (PrivateKey & ExportableKey & StorableKey) } .compactMap { $0 } .map { privateKey in - let ecnumbasis = try castor.getEcnumbasis(did: did, publicKey: privateKey.publicKey()) - return (did, privateKey, ecnumbasis) + return privateKey } - .map { did, privateKey, ecnumbasis in + .map { privateKey in try parseToSecret( - did: did, privateKey: privateKey, - ecnumbasis: ecnumbasis + identifier: privateKey.identifier ) } } -private func parseToSecret(did: DID, privateKey: PrivateKey & ExportableKey, ecnumbasis: String) throws -> Domain.Secret { - let id = did.string + "#" + ecnumbasis +private func parseToSecret(privateKey: PrivateKey & ExportableKey, identifier: String) throws -> Domain.Secret { let jwk = privateKey.jwk guard let dataJson = try? JSONEncoder().encode(jwk), @@ -149,7 +134,7 @@ private func parseToSecret(did: DID, privateKey: PrivateKey & ExportableKey, ecn throw CommonError.invalidCoding(message: "Could not encode privateKey.jwk") } return .init( - id: id, + id: identifier, type: .jsonWebKey2020, secretMaterial: .jwk(value: stringJson) ) diff --git a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Mediator/MediatorPage/MediatorPageView.swift b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Mediator/MediatorPage/MediatorPageView.swift index 6290dd2d..b6f8b076 100644 --- a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Mediator/MediatorPage/MediatorPageView.swift +++ b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/WalletDemo2/Mediator/MediatorPage/MediatorPageView.swift @@ -12,7 +12,7 @@ protocol MediatorPageViewModel: ObservableObject { struct MediatorPageView: View { @StateObject var viewModel: ViewModel - @State var didInput = "did:peer:2.Ez6LSms555YhFthn1WV8ciDBpZm86hK9tp83WojJUmxPGk1hZ.Vz6MkmdBjMyB4TS5UbbQw54szm8yvMMf1ftGV2sQVYAxaeWhE.SeyJpZCI6Im5ldy1pZCIsInQiOiJkbSIsInMiOiJodHRwczovL21lZGlhdG9yLnJvb3RzaWQuY2xvdWQiLCJhIjpbImRpZGNvbW0vdjIiXX0" + @State var didInput = "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHBzOi8vc2l0LXByaXNtLW1lZGlhdG9yLmF0YWxhcHJpc20uaW8iLCJhIjpbImRpZGNvbW0vdjIiXX19.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzczovL3NpdC1wcmlzbS1tZWRpYXRvci5hdGFsYXByaXNtLmlvL3dzIiwiYSI6WyJkaWRjb21tL3YyIl19fQ" var body: some View { NavigationStack { diff --git a/Sample/DIDChat/DIDChat.xcodeproj/project.pbxproj b/Sample/DIDChat/DIDChat.xcodeproj/project.pbxproj index 1472b080..3e6aa42f 100644 --- a/Sample/DIDChat/DIDChat.xcodeproj/project.pbxproj +++ b/Sample/DIDChat/DIDChat.xcodeproj/project.pbxproj @@ -404,7 +404,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"DIDChat/Preview Content\""; - DEVELOPMENT_TEAM = 89TW38X994; + DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -442,7 +442,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"DIDChat/Preview Content\""; - DEVELOPMENT_TEAM = 89TW38X994; + DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; diff --git a/Sample/DIDChat/DIDChat/Modules/ContactsView/ContactsViewModel.swift b/Sample/DIDChat/DIDChat/Modules/ContactsView/ContactsViewModel.swift index c57c957f..29f32e4d 100644 --- a/Sample/DIDChat/DIDChat/Modules/ContactsView/ContactsViewModel.swift +++ b/Sample/DIDChat/DIDChat/Modules/ContactsView/ContactsViewModel.swift @@ -64,7 +64,6 @@ class ContactsViewModelImpl: ContactsViewModel { guard let self else { return } do { let holderDID = try await self.agent.createNewPeerDID(alias: alias, updateMediator: true) - print(holderDID.string) await MainActor.run { self.createdPeerDID = holderDID.string self.createdPeerDIDAlias = alias diff --git a/Sample/DIDChat/DIDChat/Modules/MediatorView/MediatorView.swift b/Sample/DIDChat/DIDChat/Modules/MediatorView/MediatorView.swift index 78ec7c78..20920f4d 100644 --- a/Sample/DIDChat/DIDChat/Modules/MediatorView/MediatorView.swift +++ b/Sample/DIDChat/DIDChat/Modules/MediatorView/MediatorView.swift @@ -22,7 +22,7 @@ protocol MediatorRouter { struct MediatorView: View { @StateObject var viewModel: ViewModel - @State var mediatorDID: String = "did:peer:2.Ez6LSms555YhFthn1WV8ciDBpZm86hK9tp83WojJUmxPGk1hZ.Vz6MkmdBjMyB4TS5UbbQw54szm8yvMMf1ftGV2sQVYAxaeWhE.SeyJpZCI6Im5ldy1pZCIsInQiOiJkbSIsInMiOiJodHRwczovL21lZGlhdG9yLnJvb3RzaWQuY2xvdWQiLCJhIjpbImRpZGNvbW0vdjIiXX0" + @State var mediatorDID: String = "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHBzOi8vc2l0LXByaXNtLW1lZGlhdG9yLmF0YWxhcHJpc20uaW8iLCJhIjpbImRpZGNvbW0vdjIiXX19.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzczovL3NpdC1wcmlzbS1tZWRpYXRvci5hdGFsYXByaXNtLmlvL3dzIiwiYSI6WyJkaWRjb21tL3YyIl19fQ" @State var router: Router var body: some View { diff --git a/Sample/DIDChat/DIDChat/Modules/MediatorView/MediatorViewModel.swift b/Sample/DIDChat/DIDChat/Modules/MediatorView/MediatorViewModel.swift index 0acd34c4..959f5dec 100644 --- a/Sample/DIDChat/DIDChat/Modules/MediatorView/MediatorViewModel.swift +++ b/Sample/DIDChat/DIDChat/Modules/MediatorView/MediatorViewModel.swift @@ -36,7 +36,9 @@ class MediatorViewModelImpl: MediatorViewModel { await MainActor.run { [weak self] in self?.routeToContactsList = true } - } catch {} + } catch { + print(error) + } } }