Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Notify] Registration api update #1252

Merged
merged 4 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions Example/IntegrationTests/Push/NotifyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,17 @@ final class NotifyTests: XCTestCase {


private extension NotifyTests {
func sign(_ message: String) -> SigningResult {
func sign(_ message: String) -> CacaoSignature {
let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create(projectId: InputConfig.projectId)
return .signed(try! signer.sign(message: message, privateKey: privateKey, type: .eip191))
return try! signer.sign(message: message, privateKey: privateKey, type: .eip191)
}
}

private extension NotifyClient {

func register(account: Account, domain: String, isLimited: Bool = false, onSign: @escaping (String) -> CacaoSignature) async throws {
let params = try await prepareRegistration(account: account, domain: domain)
let signature = onSign(params.message)
try await register(params: params, signature: signature)
}
}
4 changes: 2 additions & 2 deletions Example/Shared/ImportAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)")
Expand Down
33 changes: 21 additions & 12 deletions Sources/Chat/ChatClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,25 +92,34 @@ public class ChatClient {
domain: String,
onSign: @escaping SigningCallback
) async throws -> String {
let publicKey = try await identityClient.register(

let params = try await identityClient.prepareRegistration(
account: account,
domain: domain,
statement: "statement",
resources: ["https://keys.walletconnect.com"],
onSign: onSign
resources: ["https://keys.walletconnect.com"]
)
if !syncRegisterService.isRegistered(account: account) {
try await chatStorage.initializeHistory(account: account)
try await syncRegisterService.register(account: account, onSign: onSign)
}

guard !isPrivate else {
return publicKey
}
switch await onSign(params.message) {
case .signed(let signature):
let publicKey = try await identityClient.register(params: params, signature: signature)

if !syncRegisterService.isRegistered(account: account) {
try await chatStorage.initializeHistory(account: account)
try await syncRegisterService.register(account: account, onSign: onSign)
}

try await goPublic(account: account)
guard !isPrivate else {
return publicKey
}

return publicKey
try await goPublic(account: account)

return publicKey

case .rejected:
fatalError("Not implemented")
}
flypaper0 marked this conversation as resolved.
Show resolved Hide resolved
}

/// Unregisters a blockchain account with previously registered identity key
Expand Down
16 changes: 14 additions & 2 deletions Sources/WalletConnectIdentity/IdentityClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +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
}

@discardableResult
public func register(params: IdentityRegistrationParams, signature: CacaoSignature) async throws -> String {
let account = try params.account
let pubKey = try await identityService.registerIdentity(params: params, signature: signature)
logger.debug("Did register an account: \(account)")
return pubKey
}
Expand Down
5 changes: 0 additions & 5 deletions Sources/WalletConnectIdentity/IdentityError.swift

This file was deleted.

11 changes: 11 additions & 0 deletions Sources/WalletConnectIdentity/IdentityRegistrationParams.swift
Original file line number Diff line number Diff line change
@@ -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) }
}
}
71 changes: 31 additions & 40 deletions Sources/WalletConnectIdentity/IdentityService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,46 @@ 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 -> String {
let account = try params.account

if let identityKey = try? storage.getIdentityKey(for: account) {
return identityKey.publicKey.hexRepresentation
}

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
return params.privateIdentityKey.publicKey.hexRepresentation
}

func registerInvite(account: Account) async throws -> AgreementPublicKey {
Expand Down Expand Up @@ -89,38 +112,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<Claims: IDAuthClaims>(account: Account, issuer: DIDKey, claims: Claims.Type) throws -> String {
let identityKey = try storage.getIdentityKey(for: account)

Expand Down
40 changes: 32 additions & 8 deletions Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ public class NotifyClient {

public let logger: ConsoleLogging

private let keyserverURL: URL
private let pushClient: PushClient
private let identityService: NotifyIdentityService
private let identityClient: IdentityClient
private let notifyStorage: NotifyStorage
private let notifyAccountProvider: NotifyAccountProvider
private let notifyMessageSubscriber: NotifyMessageSubscriber
Expand All @@ -38,8 +39,9 @@ public class NotifyClient {
private let subscriptionWatcher: SubscriptionWatcher

init(logger: ConsoleLogging,
keyserverURL: URL,
kms: KeyManagementServiceProtocol,
identityService: NotifyIdentityService,
identityClient: IdentityClient,
pushClient: PushClient,
notifyMessageSubscriber: NotifyMessageSubscriber,
notifyStorage: NotifyStorage,
Expand All @@ -57,8 +59,9 @@ public class NotifyClient {
subscriptionWatcher: SubscriptionWatcher
) {
self.logger = logger
self.keyserverURL = keyserverURL
self.pushClient = pushClient
self.identityService = identityService
self.identityClient = identityClient
self.notifyMessageSubscriber = notifyMessageSubscriber
self.notifyStorage = notifyStorage
self.deleteNotifySubscriptionRequester = deleteNotifySubscriptionRequester
Expand All @@ -75,14 +78,23 @@ 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 = true) async throws -> IdentityRegistrationParams {
return try await identityClient.prepareRegistration(
account: account,
domain: domain,
statement: makeStatement(allApps: allApps),
resources: [keyserverURL.absoluteString]
)
}

public func register(params: IdentityRegistrationParams, signature: CacaoSignature) async throws {
try await identityClient.register(params: params, signature: signature)
notifyAccountProvider.setAccount(try params.account)
try await subscriptionWatcher.start()
}

public func unregister(account: Account) async throws {
try await identityService.unregister(account: account)
try await identityClient.unregister(account: account)
notifyWatcherAgreementKeysProvider.removeAgreement(account: account)
try notifyStorage.clearDatabase(account: account)
notifyAccountProvider.logout()
Expand Down Expand Up @@ -122,7 +134,7 @@ public class NotifyClient {
}

public func isIdentityRegistered(account: Account) -> Bool {
return identityService.isIdentityRegistered(account: account)
return identityClient.isIdentityRegistered(account: account)
}

public func subscriptionsPublisher(account: Account) -> AnyPublisher<[NotifySubscription], Never> {
Expand All @@ -134,6 +146,18 @@ public class NotifyClient {
}
}

private extension NotifyClient {

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"
}
}
}

#if targetEnvironment(simulator)
extension NotifyClient {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,11 @@ public struct NotifyClientFactory {
let notifySubscriptionsChangedRequestSubscriber = NotifySubscriptionsChangedRequestSubscriber(keyserver: keyserverURL, networkingInteractor: networkInteractor, kms: kms, identityClient: identityClient, logger: logger, groupKeychainStorage: groupKeychainStorage, notifyStorage: notifyStorage, notifySubscriptionsBuilder: notifySubscriptionsBuilder)
let subscriptionWatcher = SubscriptionWatcher(notifyWatchSubscriptionsRequester: notifyWatchSubscriptionsRequester, logger: logger)

let identityService = NotifyIdentityService(keyserverURL: keyserverURL, identityClient: identityClient, logger: logger)

return NotifyClient(
logger: logger,
keyserverURL: keyserverURL,
kms: kms,
identityService: identityService,
identityClient: identityClient,
pushClient: pushClient,
notifyMessageSubscriber: notifyMessageSubscriber,
notifyStorage: notifyStorage,
Expand Down

This file was deleted.