From fce5cf99bccd814d8c57ee9524894d332b37ace4 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 24 Aug 2022 12:24:48 +0200 Subject: [PATCH 1/4] add test message compromised failure --- .../AuthTests/AppRespondSubscriberTests.swift | 67 +++++++++++++++++++ .../Mocks/NetworkingInteractorMock.swift | 2 +- Tests/AuthTests/Stubs/AuthPayload.swift | 7 ++ Tests/AuthTests/Stubs/AuthRequestParams.swift | 16 +++++ ...ift => WalletRequestSubscriberTests.swift} | 2 +- Tests/TestingUtils/Mocks/AppMetadata.swift | 14 ++++ Tests/WalletConnectSignTests/Stub/Stubs.swift | 10 --- 7 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 Tests/AuthTests/AppRespondSubscriberTests.swift create mode 100644 Tests/AuthTests/Stubs/AuthRequestParams.swift rename Tests/AuthTests/{AuthRequstSubscriberTests.swift => WalletRequestSubscriberTests.swift} (97%) create mode 100644 Tests/TestingUtils/Mocks/AppMetadata.swift diff --git a/Tests/AuthTests/AppRespondSubscriberTests.swift b/Tests/AuthTests/AppRespondSubscriberTests.swift new file mode 100644 index 000000000..6bd0b4e43 --- /dev/null +++ b/Tests/AuthTests/AppRespondSubscriberTests.swift @@ -0,0 +1,67 @@ +import Foundation +import XCTest +@testable import Auth +import WalletConnectUtils +@testable import WalletConnectKMS +@testable import TestingUtils +import JSONRPC + +class AppRespondSubscriberTests: XCTestCase { + var networkingInteractor: NetworkingInteractorMock! + var sut: AppRespondSubscriber! + var messageFormatter: SIWEMessageFormatter! + var rpcHistory: RPCHistory! + let defaultTimeout: TimeInterval = 0.01 + let walletAccount = Account(chainIdentifier: "eip155:1", address: "0x724d0D2DaD3fbB0C168f947B87Fa5DBe36F1A8bf")! + let prvKey = Data(hex: "462c1dad6832d7d96ccf87bd6a686a4110e114aaaebd5512e552c0e3a87b480f") + var messageSigner: MessageSigner! + + override func setUp() { + networkingInteractor = NetworkingInteractorMock() + messageFormatter = SIWEMessageFormatter() + messageSigner = MessageSigner() + let historyStorage = CodableStore(defaults: RuntimeKeyValueStorage(), identifier: StorageDomainIdentifiers.jsonRpcHistory.rawValue) + rpcHistory = RPCHistory(keyValueStore: historyStorage) + sut = AppRespondSubscriber( + networkingInteractor: networkingInteractor, + logger: ConsoleLoggerMock(), + rpcHistory: rpcHistory, + signatureVerifier: messageSigner, + messageFormatter: messageFormatter) + } + + func testMessageCompromisedFailure() { + let messageExpectation = expectation(description: "receives response") + + // set history record for a request + let topic = "topic" + let requestId: RPCID = RPCID(1234) + let request = RPCRequest(method: "wc_authRequest", params: AuthRequestParams.stub(), id: requestId.right!) + try! rpcHistory.set(request, forTopic: topic, emmitedBy: .local) + + var messageId: RPCID! + var result: Result! + sut.onResponse = { id, r in + messageId = id + result = r + messageExpectation.fulfill() + } + + // subscribe on compromised cacao + let header = CacaoHeader(t: "eip4361") + let payload = CacaoPayload(params: AuthPayload.stub(nonce: "compromised nonce"), didpkh: DIDPKH(account: walletAccount)) + + let message = try! messageFormatter.formatMessage(from: payload) + let signature = try! messageSigner.sign(message: message, privateKey: prvKey) + let cacaoSignature = CacaoSignature(t: "eip191", s: signature) + + let cacao = Cacao(header: header, payload: payload, signature: cacaoSignature) + + let response = RPCResponse(id: requestId, result: cacao) + networkingInteractor.responsePublisherSubject.send(ResponseSubscriptionPayload(topic: topic, response: response)) + + wait(for: [messageExpectation], timeout: defaultTimeout) + XCTAssertEqual(result, .failure(AuthError.messageCompromised)) + XCTAssertEqual(messageId, requestId) + } +} diff --git a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift b/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift index a499ea4af..a3364de40 100644 --- a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift +++ b/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift @@ -9,7 +9,7 @@ struct NetworkingInteractorMock: NetworkInteracting { var responsePublisher: AnyPublisher { responsePublisherSubject.eraseToAnyPublisher() } - private let responsePublisherSubject = PassthroughSubject() + let responsePublisherSubject = PassthroughSubject() let requestPublisherSubject = PassthroughSubject() var requestPublisher: AnyPublisher { diff --git a/Tests/AuthTests/Stubs/AuthPayload.swift b/Tests/AuthTests/Stubs/AuthPayload.swift index c305aee03..84d659e9a 100644 --- a/Tests/AuthTests/Stubs/AuthPayload.swift +++ b/Tests/AuthTests/Stubs/AuthPayload.swift @@ -6,3 +6,10 @@ extension AuthPayload { AuthPayload(requestParams: requestParams, iat: "2021-09-30T16:25:24Z") } } + +extension AuthPayload { + static func stub(nonce: String) -> AuthPayload { + let issueAt = ISO8601DateFormatter().string(from: Date()) + return AuthPayload(requestParams: RequestParams.stub(nonce: nonce), iat: issueAt) + } +} diff --git a/Tests/AuthTests/Stubs/AuthRequestParams.swift b/Tests/AuthTests/Stubs/AuthRequestParams.swift new file mode 100644 index 000000000..e68e1b50e --- /dev/null +++ b/Tests/AuthTests/Stubs/AuthRequestParams.swift @@ -0,0 +1,16 @@ +@testable import Auth +import Foundation +import WalletConnectPairing + +extension AuthRequestParams { + static func stub(nonce: String = "32891756") -> AuthRequestParams { + let payload = AuthPayload.stub(nonce: nonce) + return AuthRequestParams(requester: Requester.stub(), payloadParams: payload) + } +} + +extension AuthRequestParams.Requester { + static func stub() -> AuthRequestParams.Requester { + AuthRequestParams.Requester(publicKey: "", metadata: AppMetadata.stub()) + } +} diff --git a/Tests/AuthTests/AuthRequstSubscriberTests.swift b/Tests/AuthTests/WalletRequestSubscriberTests.swift similarity index 97% rename from Tests/AuthTests/AuthRequstSubscriberTests.swift rename to Tests/AuthTests/WalletRequestSubscriberTests.swift index fc7c6ebbb..3ca0f2741 100644 --- a/Tests/AuthTests/AuthRequstSubscriberTests.swift +++ b/Tests/AuthTests/WalletRequestSubscriberTests.swift @@ -6,7 +6,7 @@ import WalletConnectUtils @testable import TestingUtils import JSONRPC -class AuthRequstSubscriberTests: XCTestCase { +class WalletRequestSubscriberTests: XCTestCase { var networkingInteractor: NetworkingInteractorMock! var sut: WalletRequestSubscriber! var messageFormatter: SIWEMessageFormatterMock! diff --git a/Tests/TestingUtils/Mocks/AppMetadata.swift b/Tests/TestingUtils/Mocks/AppMetadata.swift new file mode 100644 index 000000000..2f8d6a558 --- /dev/null +++ b/Tests/TestingUtils/Mocks/AppMetadata.swift @@ -0,0 +1,14 @@ + +import Foundation +import WalletConnectPairing + +public extension AppMetadata { + static func stub() -> AppMetadata { + AppMetadata( + name: "Wallet Connect", + description: "A protocol to connect blockchain wallets to dapps.", + url: "https://walletconnect.com/", + icons: [] + ) + } +} diff --git a/Tests/WalletConnectSignTests/Stub/Stubs.swift b/Tests/WalletConnectSignTests/Stub/Stubs.swift index 67c329247..7f80b8da9 100644 --- a/Tests/WalletConnectSignTests/Stub/Stubs.swift +++ b/Tests/WalletConnectSignTests/Stub/Stubs.swift @@ -5,16 +5,6 @@ import WalletConnectUtils import TestingUtils import WalletConnectPairing -extension AppMetadata { - static func stub() -> AppMetadata { - AppMetadata( - name: "Wallet Connect", - description: "A protocol to connect blockchain wallets to dapps.", - url: "https://walletconnect.com/", - icons: [] - ) - } -} extension Pairing { static func stub(expiryDate: Date = Date(timeIntervalSinceNow: 10000), topic: String = String.generateTopic()) -> Pairing { From ecc8f8a1a33f4c97c7a282969cdfba785f8b80c4 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 24 Aug 2022 15:36:30 +0200 Subject: [PATCH 2/4] fix unit tests --- .../Mocks/AppMetadata.swift | 0 .../WalletConnectSignTests/Mocks/AppMetadata.swift | 14 ++++++++++++++ 2 files changed, 14 insertions(+) rename Tests/{TestingUtils => AuthTests}/Mocks/AppMetadata.swift (100%) create mode 100644 Tests/WalletConnectSignTests/Mocks/AppMetadata.swift diff --git a/Tests/TestingUtils/Mocks/AppMetadata.swift b/Tests/AuthTests/Mocks/AppMetadata.swift similarity index 100% rename from Tests/TestingUtils/Mocks/AppMetadata.swift rename to Tests/AuthTests/Mocks/AppMetadata.swift diff --git a/Tests/WalletConnectSignTests/Mocks/AppMetadata.swift b/Tests/WalletConnectSignTests/Mocks/AppMetadata.swift new file mode 100644 index 000000000..2f8d6a558 --- /dev/null +++ b/Tests/WalletConnectSignTests/Mocks/AppMetadata.swift @@ -0,0 +1,14 @@ + +import Foundation +import WalletConnectPairing + +public extension AppMetadata { + static func stub() -> AppMetadata { + AppMetadata( + name: "Wallet Connect", + description: "A protocol to connect blockchain wallets to dapps.", + url: "https://walletconnect.com/", + icons: [] + ) + } +} From 1f7784f0f2cc3910b9f62478fdbb92f108679871 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 24 Aug 2022 19:57:32 +0200 Subject: [PATCH 3/4] Add invalidateIfNeeded function --- Sources/WalletConnectRelay/RelayClient.swift | 2 +- .../AutomaticSocketConnectionHandler.swift | 1 - .../SocketConnectionHandler/BackgroundTaskRegistering.swift | 5 ++--- Sources/WalletConnectSign/Sign/SignClientFactory.swift | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Sources/WalletConnectRelay/RelayClient.swift b/Sources/WalletConnectRelay/RelayClient.swift index 0c18c01d7..2c475b654 100644 --- a/Sources/WalletConnectRelay/RelayClient.swift +++ b/Sources/WalletConnectRelay/RelayClient.swift @@ -82,7 +82,7 @@ public final class RelayClient { keychainStorage: KeychainStorageProtocol = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk"), socketFactory: WebSocketFactory, socketConnectionType: SocketConnectionType = .automatic, - logger: ConsoleLogging = ConsoleLogger(loggingLevel: .off) + logger: ConsoleLogging = ConsoleLogger(loggingLevel: .debug) ) { let socketAuthenticator = SocketAuthenticator( clientIdStorage: ClientIdStorage(keychain: keychainStorage), diff --git a/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift b/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift index 5a5cec5f6..20eab6208 100644 --- a/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift +++ b/Sources/WalletConnectRelay/SocketConnectionHandler/AutomaticSocketConnectionHandler.swift @@ -36,7 +36,6 @@ class AutomaticSocketConnectionHandler: SocketConnectionHandler { } appStateObserver.onWillEnterForeground = { [unowned self] in - backgroundTaskRegistrar.invalidate() socket.connect() } } diff --git a/Sources/WalletConnectRelay/SocketConnectionHandler/BackgroundTaskRegistering.swift b/Sources/WalletConnectRelay/SocketConnectionHandler/BackgroundTaskRegistering.swift index 7b08c94a6..a652bef74 100644 --- a/Sources/WalletConnectRelay/SocketConnectionHandler/BackgroundTaskRegistering.swift +++ b/Sources/WalletConnectRelay/SocketConnectionHandler/BackgroundTaskRegistering.swift @@ -5,7 +5,6 @@ import UIKit protocol BackgroundTaskRegistering { func register(name: String, completion: @escaping () -> Void) - func invalidate() } class BackgroundTaskRegistrar: BackgroundTaskRegistering { @@ -15,7 +14,7 @@ class BackgroundTaskRegistrar: BackgroundTaskRegistering { func register(name: String, completion: @escaping () -> Void) { #if os(iOS) - backgroundTaskID = .invalid + invalidateIfNeeded() backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: name) { [unowned self] in UIApplication.shared.endBackgroundTask(backgroundTaskID) backgroundTaskID = .invalid @@ -24,7 +23,7 @@ class BackgroundTaskRegistrar: BackgroundTaskRegistering { #endif } - func invalidate() { + private func invalidateIfNeeded() { #if os(iOS) if backgroundTaskID != .invalid { UIApplication.shared.endBackgroundTask(backgroundTaskID) diff --git a/Sources/WalletConnectSign/Sign/SignClientFactory.swift b/Sources/WalletConnectSign/Sign/SignClientFactory.swift index 8ab60ee52..b5fb7a52c 100644 --- a/Sources/WalletConnectSign/Sign/SignClientFactory.swift +++ b/Sources/WalletConnectSign/Sign/SignClientFactory.swift @@ -16,7 +16,7 @@ public struct SignClientFactory { /// /// WalletConnect Client is not a singleton but once you create an instance, you should not deinitialize it. Usually only one instance of a client is required in the application. public static func create(metadata: AppMetadata, relayClient: RelayClient) -> SignClient { - let logger = ConsoleLogger(loggingLevel: .off) + let logger = ConsoleLogger(loggingLevel: .debug) let keyValueStorage = UserDefaults.standard let keychainStorage = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk") return SignClientFactory.create(metadata: metadata, logger: logger, keyValueStorage: keyValueStorage, keychainStorage: keychainStorage, relayClient: relayClient) From 344041c379e4b13bcd292684dc029ec77c6d3884 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 24 Aug 2022 20:02:14 +0200 Subject: [PATCH 4/4] update logging level --- Sources/WalletConnectRelay/RelayClient.swift | 2 +- Sources/WalletConnectSign/Sign/SignClientFactory.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WalletConnectRelay/RelayClient.swift b/Sources/WalletConnectRelay/RelayClient.swift index 2c475b654..0c18c01d7 100644 --- a/Sources/WalletConnectRelay/RelayClient.swift +++ b/Sources/WalletConnectRelay/RelayClient.swift @@ -82,7 +82,7 @@ public final class RelayClient { keychainStorage: KeychainStorageProtocol = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk"), socketFactory: WebSocketFactory, socketConnectionType: SocketConnectionType = .automatic, - logger: ConsoleLogging = ConsoleLogger(loggingLevel: .debug) + logger: ConsoleLogging = ConsoleLogger(loggingLevel: .off) ) { let socketAuthenticator = SocketAuthenticator( clientIdStorage: ClientIdStorage(keychain: keychainStorage), diff --git a/Sources/WalletConnectSign/Sign/SignClientFactory.swift b/Sources/WalletConnectSign/Sign/SignClientFactory.swift index b5fb7a52c..8ab60ee52 100644 --- a/Sources/WalletConnectSign/Sign/SignClientFactory.swift +++ b/Sources/WalletConnectSign/Sign/SignClientFactory.swift @@ -16,7 +16,7 @@ public struct SignClientFactory { /// /// WalletConnect Client is not a singleton but once you create an instance, you should not deinitialize it. Usually only one instance of a client is required in the application. public static func create(metadata: AppMetadata, relayClient: RelayClient) -> SignClient { - let logger = ConsoleLogger(loggingLevel: .debug) + let logger = ConsoleLogger(loggingLevel: .off) let keyValueStorage = UserDefaults.standard let keychainStorage = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk") return SignClientFactory.create(metadata: metadata, logger: logger, keyValueStorage: keyValueStorage, keychainStorage: keychainStorage, relayClient: relayClient)