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] Unregister method #1182

Merged
merged 13 commits into from
Oct 18, 2023
25 changes: 10 additions & 15 deletions Example/IntegrationTests/Push/NotifyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ final class NotifyTests: XCTestCase {

walletNotifyClientA.subscriptionsPublisher
.sink { [unowned self] subscriptions in
guard let subscription = subscriptions.first else {return}
guard let subscription = subscriptions.first else { return }
Task(priority: .high) {
try await walletNotifyClientA.deleteSubscription(topic: subscription.topic)
expectation.fulfill()
Expand All @@ -115,17 +115,15 @@ final class NotifyTests: XCTestCase {

let clientB = makeWalletClient(prefix: "👐🏼 Wallet B: ")
clientB.subscriptionsPublisher.sink { subscriptions in
guard let subscription = subscriptions.first else { return }
Task(priority: .high) {
if !subscriptions.isEmpty {
expectation.fulfill()
}
try await clientB.deleteSubscription(topic: subscription.topic)
expectation.fulfill()
}
}.store(in: &publishers)

try! await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try! await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)

sleep(1)
try! await clientB.register(account: account, domain: gmDappDomain, onSign: sign)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)
Expand All @@ -137,18 +135,15 @@ final class NotifyTests: XCTestCase {

let clientB = makeWalletClient(prefix: "👐🏼 Wallet B: ")
clientB.subscriptionsPublisher.sink { subscriptions in
guard let subscription = subscriptions.first else { return }
Task(priority: .high) {
if !subscriptions.isEmpty {
expectation.fulfill()
}
try await clientB.deleteSubscription(topic: subscription.topic)
expectation.fulfill()
}
}.store(in: &publishers)

try! await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try! await clientB.register(account: account, domain: gmDappDomain, onSign: sign)

sleep(1)

try! await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)
Expand All @@ -162,8 +157,8 @@ final class NotifyTests: XCTestCase {
var didUpdate = false
walletNotifyClientA.subscriptionsPublisher
.sink { [unowned self] subscriptions in
guard let subscription = subscriptions.first else {return}
let updatedScope = Set(subscription.scope.filter{ $0.value.enabled == true }.keys)
guard let subscription = subscriptions.first else { return }
let updatedScope = Set(subscription.scope.filter { $0.value.enabled == true }.keys)

if !didUpdate {
didUpdate = true
Expand Down Expand Up @@ -193,7 +188,7 @@ final class NotifyTests: XCTestCase {
var didNotify = false
walletNotifyClientA.subscriptionsPublisher
.sink { subscriptions in
guard let subscription = subscriptions.first else {return}
guard let subscription = subscriptions.first else { return }
let notifier = Publisher()
if !didNotify {
didNotify = true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Foundation
import WalletConnectNotify
import Combine

Expand All @@ -14,7 +15,7 @@ final class NotificationsInteractor {
}

func getSubscriptions() -> [NotifySubscription] {
let subs = Notify.instance.getActiveSubscriptions()
let subs = Notify.instance.getActiveSubscriptions(account: importAccount.account)
return subs
}

Expand All @@ -32,7 +33,32 @@ final class NotificationsInteractor {
}

func subscribe(domain: String) async throws {
try await Notify.instance.subscribe(appDomain: domain, account: importAccount.account)
return try await withCheckedThrowingContinuation { continuation in
var cancellable: AnyCancellable?
cancellable = subscriptionsPublisher
.setFailureType(to: Error.self)
.timeout(10, scheduler: RunLoop.main, customError: { Errors.subscribeTimeout })
flypaper0 marked this conversation as resolved.
Show resolved Hide resolved
.sink(receiveCompletion: { completion in
defer { cancellable?.cancel() }
switch completion {
case .failure(let error): continuation.resume(with: .failure(error))
case .finished: break
}
}, receiveValue: { subscriptions in
guard subscriptions.contains(where: { $0.metadata.url == domain }) else { return }
cancellable?.cancel()
continuation.resume(with: .success(()))
})

Task { [cancellable] in
do {
try await Notify.instance.subscribe(appDomain: domain, account: importAccount.account)
} catch {
cancellable?.cancel()
continuation.resume(throwing: error)
}
}
}
}

func unsubscribe(topic: String) async throws {
Expand All @@ -43,3 +69,17 @@ final class NotificationsInteractor {
return Notify.instance.getMessageHistory(topic: subscription.topic)
}
}

private extension NotificationsInteractor {

enum Errors: Error, LocalizedError {
case subscribeTimeout

var errorDescription: String? {
switch self {
case .subscribeTimeout:
return "Subscribe method timeout"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import Foundation
import WalletConnectNotify

final class SettingsInteractor {

func notifyUnregister(account: Account) async throws {
try await Notify.instance.unregister(account: account)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ final class SettingsPresenter: ObservableObject {
return deviceToken
}

func logoutPressed() {
func logoutPressed() async throws {
guard let account = accountStorage.importAccount?.account else { return }
try await interactor.notifyUnregister(account: account)
accountStorage.importAccount = nil
UserDefaults.standard.set(nil, forKey: "deviceToken")
router.presentWelcome()
await router.presentWelcome()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ final class SettingsRouter {
self.app = app
}

func presentWelcome() {
@MainActor func presentWelcome() async {
WelcomeModule.create(app: app).present()
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import SwiftUI
import AsyncButton

struct SettingsView: View {

Expand All @@ -19,8 +20,8 @@ struct SettingsView: View {
}

Section {
Button {
viewModel.logoutPressed()
AsyncButton {
try await viewModel.logoutPressed()
} label: {
Text("Log out")
.foregroundColor(.red)
Expand Down
5 changes: 2 additions & 3 deletions Sources/Chat/ChatClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,8 @@ public class ChatClient {

/// Unregisters a blockchain account with previously registered identity key
/// Must not unregister invite key but must stop listening for invites
/// - Parameter onSign: Callback for signing CAIP-122 message to verify blockchain account ownership
public func unregister(account: Account, onSign: @escaping SigningCallback) async throws {
try await identityClient.unregister(account: account, onSign: onSign)
public func unregister(account: Account) async throws {
try await identityClient.unregister(account: account)
}

/// Queries the keyserver with a blockchain account
Expand Down
4 changes: 2 additions & 2 deletions Sources/WalletConnectIdentity/IdentityClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public final class IdentityClient {
return inviteKey
}

public func unregister(account: Account, onSign: SigningCallback) async throws {
try await identityService.unregister(account: account, onSign: onSign)
public func unregister(account: Account) async throws {
try await identityService.unregister(account: account)
logger.debug("Did unregister an account: \(account)")
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/WalletConnectIdentity/IdentityService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ actor IdentityService {
return try storage.saveInviteKey(inviteKey, for: account)
}

func unregister(account: Account, onSign: SigningCallback) async throws {
func unregister(account: Account) async throws {
let identityKey = try storage.getIdentityKey(for: account)
let identityPublicKey = DIDKey(rawData: identityKey.publicKey.rawRepresentation)
let idAuth = try makeIDAuth(account: account, issuer: identityPublicKey, claims: UnregisterIdentityClaims.self)
Expand Down
11 changes: 11 additions & 0 deletions Sources/WalletConnectKMS/Crypto/KeyManagementService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@ public protocol KeyManagementServiceProtocol {
func setPublicKey(publicKey: AgreementPublicKey, for topic: String) throws
func setAgreementSecret(_ agreementSecret: AgreementKeys, topic: String) throws
func setSymmetricKey(_ symmetricKey: SymmetricKey, for topic: String) throws
func setTopic(_ topic: String, for key: String) throws
func getPrivateKey(for publicKey: AgreementPublicKey) throws -> AgreementPrivateKey?
func getAgreementSecret(for topic: String) -> AgreementKeys?
func getSymmetricKey(for topic: String) -> SymmetricKey?
func getSymmetricKeyRepresentable(for topic: String) -> Data?
func getPublicKey(for topic: String) -> AgreementPublicKey?
func getTopic(for key: String) -> String?
func deletePrivateKey(for publicKey: String)
func deleteAgreementSecret(for topic: String)
func deleteSymmetricKey(for topic: String)
func deletePublicKey(for topic: String)
func deleteAll() throws
func deleteTopic(for key: String)
func performKeyAgreement(selfPublicKey: AgreementPublicKey, peerPublicKey hexRepresentation: String) throws -> AgreementKeys
}

Expand Down Expand Up @@ -63,6 +66,14 @@ public class KeyManagementService: KeyManagementServiceProtocol {
try keychain.add(topic, forKey: key)
}

public func deleteTopic(for key: String) {
do {
try keychain.delete(key: key)
} catch {
print("Error deleting topic: \(error)")
}
}

public func getSymmetricKey(for topic: String) -> SymmetricKey? {
do {
return try keychain.read(key: topic) as SymmetricKey
Expand Down
10 changes: 10 additions & 0 deletions Sources/WalletConnectNotify/Client/Wallet/Extensions/Array.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Foundation

extension Array where Element: Hashable {

func difference(from other: [Element]) -> [Element] {
let thisSet = Set(self)
let otherSet = Set(other)
return Array(thisSet.symmetricDifference(otherSet))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Foundation

final class NotifyAccountProvider {
enum Errors: Error {
case currentAccountNotFound
}

private var currentAccount: Account?

func setAccount(_ account: Account) {
self.currentAccount = account
}

func logout() {
self.currentAccount = nil
}

func getCurrentAccount() throws -> Account {
guard let currentAccount else { throw Errors.currentAccountNotFound }
return currentAccount
}
}
Loading