diff --git a/Example/Shared/ImportAccount.swift b/Example/Shared/ImportAccount.swift index 00e4c04e3..a4c65fed3 100644 --- a/Example/Shared/ImportAccount.swift +++ b/Example/Shared/ImportAccount.swift @@ -91,11 +91,11 @@ enum ImportAccount: Codable { } } - func onSign(message: String) -> SigningResult { + func onSign(message: String) -> CacaoSignature { let privateKey = Data(hex: privateKey) let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create() let signature = try! signer.sign(message: message, privateKey: privateKey, type: .eip191) - return .signed(signature) + return signature } static func new() -> ImportAccount { diff --git a/Example/WalletApp/ApplicationLayer/ConfigurationService.swift b/Example/WalletApp/ApplicationLayer/ConfigurationService.swift index d8cfd3afe..1fcfbd198 100644 --- a/Example/WalletApp/ApplicationLayer/ConfigurationService.swift +++ b/Example/WalletApp/ApplicationLayer/ConfigurationService.swift @@ -41,7 +41,9 @@ final class ConfigurationService { Task { do { - try await Notify.instance.register(account: importAccount.account, domain: "com.walletconnect", onSign: importAccount.onSign) + let params = try await Notify.instance.prepareRegistration(account: importAccount.account, domain: "com.walletconnect") + let signature = importAccount.onSign(message: params.message) + try await Notify.instance.register(params: params, signature: signature) } catch { DispatchQueue.main.async { let logMessage = LogMessage(message: "Push Server registration failed with: \(error.localizedDescription)") diff --git a/Sources/WalletConnectIdentity/IdentityClient.swift b/Sources/WalletConnectIdentity/IdentityClient.swift index a776adb09..d7a6e69a5 100644 --- a/Sources/WalletConnectIdentity/IdentityClient.swift +++ b/Sources/WalletConnectIdentity/IdentityClient.swift @@ -22,10 +22,20 @@ public final class IdentityClient { self.logger = logger } - public func register(account: Account, domain: String, statement: String, resources: [String], onSign: SigningCallback) async throws -> String { - let pubKey = try await identityService.registerIdentity(account: account, domain: domain, statement: statement, resources: resources, onSign: onSign) + public func prepareRegistration(account: Account, + domain: String, + statement: String, + resources: [String]) async throws -> IdentityRegistrationParams + { + let registration = try await identityService.prepareRegistration(account: account, domain: domain, statement: statement, resources: resources) + logger.debug("Did prepare registration for \(account)") + return registration + } + + public func register(params: IdentityRegistrationParams, signature: CacaoSignature) async throws { + let account = try params.account + try await identityService.registerIdentity(params: params, signature: signature) logger.debug("Did register an account: \(account)") - return pubKey } public func goPublic(account: Account) async throws -> AgreementPublicKey { diff --git a/Sources/WalletConnectIdentity/IdentityError.swift b/Sources/WalletConnectIdentity/IdentityError.swift deleted file mode 100644 index d3103601a..000000000 --- a/Sources/WalletConnectIdentity/IdentityError.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -enum IdentityError: Error { - case signatureRejected -} diff --git a/Sources/WalletConnectIdentity/IdentityRegistrationParams.swift b/Sources/WalletConnectIdentity/IdentityRegistrationParams.swift new file mode 100644 index 000000000..1089c2a34 --- /dev/null +++ b/Sources/WalletConnectIdentity/IdentityRegistrationParams.swift @@ -0,0 +1,11 @@ +import Foundation + +public struct IdentityRegistrationParams { + public let message: String + public let payload: CacaoPayload + public let privateIdentityKey: SigningPrivateKey + + public var account: Account { + get throws { try Account(DIDPKHString: payload.iss) } + } +} diff --git a/Sources/WalletConnectIdentity/IdentityService.swift b/Sources/WalletConnectIdentity/IdentityService.swift index 0a974c474..b2e85834b 100644 --- a/Sources/WalletConnectIdentity/IdentityService.swift +++ b/Sources/WalletConnectIdentity/IdentityService.swift @@ -25,23 +25,45 @@ actor IdentityService { self.messageFormatter = messageFormatter } - func registerIdentity(account: Account, + func prepareRegistration(account: Account, domain: String, statement: String, - resources: [String], - onSign: SigningCallback - ) async throws -> String { + resources: [String]) throws -> IdentityRegistrationParams { + + let identityKey = SigningPrivateKey() + + let payload = CacaoPayload( + iss: account.did, + domain: domain, + aud: identityKey.publicKey.did, + version: getVersion(), + nonce: getNonce(), + iat: iatProvader.iat, + nbf: nil, exp: nil, + statement: statement, + requestId: nil, + resources: resources + ) + + let message = try messageFormatter.formatMessage(from: payload) + + return IdentityRegistrationParams(message: message, payload: payload, privateIdentityKey: identityKey) + } + + // TODO: Verifications + func registerIdentity(params: IdentityRegistrationParams, signature: CacaoSignature) async throws { + let account = try params.account if let identityKey = try? storage.getIdentityKey(for: account) { - return identityKey.publicKey.hexRepresentation + return } - let identityKey = SigningPrivateKey() - let audience = identityKey.publicKey.did - let cacao = try await makeCacao(account: account, domain: domain, statement: statement, resources: resources, audience: audience, onSign: onSign) + let cacaoHeader = CacaoHeader(t: "eip4361") + let cacao = Cacao(h: cacaoHeader, p: params.payload, s: signature) + try await networkService.registerIdentity(cacao: cacao) + try storage.saveIdentityKey(params.privateIdentityKey, for: account) - return try storage.saveIdentityKey(identityKey, for: account).publicKey.hexRepresentation } func registerInvite(account: Account) async throws -> AgreementPublicKey { @@ -89,38 +111,6 @@ actor IdentityService { private extension IdentityService { - func makeCacao(account: Account, - domain: String, - statement: String, - resources: [String], - audience: String, - onSign: SigningCallback - ) async throws -> Cacao { - - let cacaoHeader = CacaoHeader(t: "eip4361") - let cacaoPayload = CacaoPayload( - iss: account.did, - domain: domain, - aud: audience, - version: getVersion(), - nonce: getNonce(), - iat: iatProvader.iat, - nbf: nil, exp: nil, - statement: statement, - requestId: nil, - resources: resources - ) - - let result = await onSign(try messageFormatter.formatMessage(from: cacaoPayload)) - - switch result { - case .signed(let cacaoSignature): - return Cacao(h: cacaoHeader, p: cacaoPayload, s: cacaoSignature) - case .rejected: - throw IdentityError.signatureRejected - } - } - func makeIDAuth(account: Account, issuer: DIDKey, claims: Claims.Type) throws -> String { let identityKey = try storage.getIdentityKey(for: account) diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift index 6a3ea77e5..41ef5d1d3 100644 --- a/Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift +++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift @@ -75,9 +75,13 @@ public class NotifyClient { self.subscriptionWatcher = subscriptionWatcher } - public func register(account: Account, domain: String, isLimited: Bool = false, onSign: @escaping SigningCallback) async throws { - try await identityService.register(account: account, domain: domain, isLimited: isLimited, onSign: onSign) - notifyAccountProvider.setAccount(account) + public func prepareRegistration(account: Account, domain: String, allApps: Bool = false) async throws -> IdentityRegistrationParams { + return try await identityService.prepareRegistration(account: account, domain: domain, allApps: allApps) + } + + public func register(params: IdentityRegistrationParams, signature: CacaoSignature) async throws { + try await identityService.register(params: params, signature: signature) + notifyAccountProvider.setAccount(try params.account) try await subscriptionWatcher.start() } diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyIdentityService.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyIdentityService.swift index 0ae95400b..a7e318760 100644 --- a/Sources/WalletConnectNotify/Client/Wallet/NotifyIdentityService.swift +++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyIdentityService.swift @@ -1,5 +1,6 @@ import Foundation +// TODO: Remove final class NotifyIdentityService { private let keyserverURL: URL @@ -12,13 +13,17 @@ final class NotifyIdentityService { self.logger = logger } - public func register(account: Account, domain: String, isLimited: Bool, onSign: @escaping SigningCallback) async throws { - let statement = makeStatement(isLimited: isLimited) - _ = try await identityClient.register(account: account, + public func prepareRegistration(account: Account, domain: String, allApps: Bool) async throws -> IdentityRegistrationParams { + return try await identityClient.prepareRegistration( + account: account, domain: domain, - statement: statement, - resources: [keyserverURL.absoluteString], - onSign: onSign) + statement: makeStatement(allApps: allApps), + resources: [keyserverURL.absoluteString] + ) + } + + public func register(params: IdentityRegistrationParams, signature: CacaoSignature) async throws { + try await identityClient.register(params: params, signature: signature) } public func unregister(account: Account) async throws { @@ -32,11 +37,11 @@ final class NotifyIdentityService { private extension NotifyIdentityService { - func makeStatement(isLimited: Bool) -> String { - switch isLimited { - case true: - return "I further authorize this app to send me notifications. Read more at https://walletconnect.com/notifications" + func makeStatement(allApps: Bool) -> String { + switch allApps { case false: + return "I further authorize this app to send me notifications. Read more at https://walletconnect.com/notifications" + case true: return "I further authorize this app to view and manage my notifications for ALL apps. Read more at https://walletconnect.com/notifications" } }