From 68ffab82843d8e95dd87a688d3e7e9ed50969cc0 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 3 Aug 2022 14:12:48 +0200 Subject: [PATCH 01/20] Add Auth Respond Subscriber --- .../Services/App/AuthRespondSubscriber.swift | 40 +++++++++++++++++++ .../Auth/Services/Common/CacaoFormatter.swift | 1 + .../Common/CacaoSignatureVerifier.swift | 16 ++++++++ .../Common/NetworkingInteractor.swift | 6 +++ Sources/Auth/Types/Cacao/Cacao.swift | 2 +- .../Mocks/NetworkingInteractorMock.swift | 2 + 6 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 Sources/Auth/Services/App/AuthRespondSubscriber.swift create mode 100644 Sources/Auth/Services/Common/CacaoSignatureVerifier.swift diff --git a/Sources/Auth/Services/App/AuthRespondSubscriber.swift b/Sources/Auth/Services/App/AuthRespondSubscriber.swift new file mode 100644 index 000000000..e3379f771 --- /dev/null +++ b/Sources/Auth/Services/App/AuthRespondSubscriber.swift @@ -0,0 +1,40 @@ +import Combine +import Foundation +import WalletConnectUtils +import JSONRPC + +class AuthRespondSubscriber { + private let networkingInteractor: NetworkInteracting + private let logger: ConsoleLogging + private let rpcHistory: RPCHistory + private var publishers = [AnyCancellable]() + var onResponse: ((_ id: RPCID, _ cacao: Cacao)->Void)? + + init(networkingInteractor: NetworkInteracting, + logger: ConsoleLogging, + rpcHistory: RPCHistory) { + self.networkingInteractor = networkingInteractor + self.logger = logger + self.rpcHistory = rpcHistory + subscribeForResponse() + } + + private func subscribeForResponse() { + networkingInteractor.responsePublisher.sink { [unowned self] response in + guard let request = rpcHistory.get(recordId: response.id!)?.request, + request.method == "wc_authRequest" else { return } + + guard let cacao = try? response.result?.get(Cacao.self) else { + logger.debug("Malformed auth response params") + return + } + do { + try CacaoSignatureVerifier().verifySignature(cacao) + onResponse?(response.id!, cacao) + } catch { + logger.debug("Received response with invalid signature") + } + }.store(in: &publishers) + } +} + diff --git a/Sources/Auth/Services/Common/CacaoFormatter.swift b/Sources/Auth/Services/Common/CacaoFormatter.swift index 7daf6b3d1..43ddb9058 100644 --- a/Sources/Auth/Services/Common/CacaoFormatter.swift +++ b/Sources/Auth/Services/Common/CacaoFormatter.swift @@ -1,4 +1,5 @@ import Foundation +import WalletConnectUtils protocol CacaoFormatting { func format(_ request: AuthRequestParams, _ signature: CacaoSignature, _ issuer: Account) -> Cacao diff --git a/Sources/Auth/Services/Common/CacaoSignatureVerifier.swift b/Sources/Auth/Services/Common/CacaoSignatureVerifier.swift new file mode 100644 index 000000000..76a6911c8 --- /dev/null +++ b/Sources/Auth/Services/Common/CacaoSignatureVerifier.swift @@ -0,0 +1,16 @@ +import Foundation + +protocol CacaoSignatureVerifying { + func verifySignature(_ cacao: Cacao) throws +} + +class CacaoSignatureVerifier: CacaoSignatureVerifying { + enum Errors: Error { + case signatureInvalid + } + + func verifySignature(_ cacao: Cacao) throws { + fatalError("not implemented") + } +} + diff --git a/Sources/Auth/Services/Common/NetworkingInteractor.swift b/Sources/Auth/Services/Common/NetworkingInteractor.swift index c81420b26..d81e8ccfb 100644 --- a/Sources/Auth/Services/Common/NetworkingInteractor.swift +++ b/Sources/Auth/Services/Common/NetworkingInteractor.swift @@ -7,6 +7,8 @@ import JSONRPC protocol NetworkInteracting { var requestPublisher: AnyPublisher {get} + var responsePublisher: AnyPublisher {get} + func subscribe(topic: String) async throws func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws @@ -25,6 +27,10 @@ class NetworkingInteractor: NetworkInteracting { var requestPublisher: AnyPublisher { requestPublisherSubject.eraseToAnyPublisher() } + var responsePublisher: AnyPublisher { + responsePublisherSubject.eraseToAnyPublisher() + } + private let responsePublisherSubject = PassthroughSubject() private let requestPublisherSubject = PassthroughSubject() init(relayClient: RelayClient, diff --git a/Sources/Auth/Types/Cacao/Cacao.swift b/Sources/Auth/Types/Cacao/Cacao.swift index 95a2d59c5..80e7ce8b0 100644 --- a/Sources/Auth/Types/Cacao/Cacao.swift +++ b/Sources/Auth/Types/Cacao/Cacao.swift @@ -1,6 +1,6 @@ import Foundation -struct Cacao: Codable, Equatable { +public struct Cacao: Codable, Equatable { let header: CacaoHeader let payload: CacaoPayload let signature: CacaoSignature diff --git a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift b/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift index 32e8abe85..d7c546725 100644 --- a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift +++ b/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift @@ -5,6 +5,8 @@ import JSONRPC import WalletConnectKMS struct NetworkingInteractorMock: NetworkInteracting { + var responsePublisher: AnyPublisher + let requestPublisherSubject = PassthroughSubject() var requestPublisher: AnyPublisher { From 70042a5db5ce08b9bb2c7070f23db78c1fc8392e Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 4 Aug 2022 09:04:18 +0200 Subject: [PATCH 02/20] Update AuthRespondSubscriber --- .../Auth/Services/App/AuthRespondSubscriber.swift | 11 +++++------ .../Auth/Services/Common/NetworkingInteractor.swift | 13 +++++++++---- Sources/Auth/Types/RequestSubscriptionPayload.swift | 4 ++-- .../Auth/Types/ResponseSubscriptionPayload.swift | 7 +++++++ .../AuthTests/Mocks/NetworkingInteractorMock.swift | 9 ++++++++- .../Stubs/RequestSubscriptionPayload.swift | 2 +- 6 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 Sources/Auth/Types/ResponseSubscriptionPayload.swift diff --git a/Sources/Auth/Services/App/AuthRespondSubscriber.swift b/Sources/Auth/Services/App/AuthRespondSubscriber.swift index e3379f771..ad8dcb7ed 100644 --- a/Sources/Auth/Services/App/AuthRespondSubscriber.swift +++ b/Sources/Auth/Services/App/AuthRespondSubscriber.swift @@ -20,21 +20,20 @@ class AuthRespondSubscriber { } private func subscribeForResponse() { - networkingInteractor.responsePublisher.sink { [unowned self] response in - guard let request = rpcHistory.get(recordId: response.id!)?.request, + networkingInteractor.responsePublisher.sink { [unowned self] subscriptionPayload in + guard let request = rpcHistory.get(recordId: subscriptionPayload.request.id!)?.request, request.method == "wc_authRequest" else { return } - - guard let cacao = try? response.result?.get(Cacao.self) else { + networkingInteractor.unsubscribe(topic: subscriptionPayload.topic) + guard let cacao = try? subscriptionPayload.request.result?.get(Cacao.self) else { logger.debug("Malformed auth response params") return } do { try CacaoSignatureVerifier().verifySignature(cacao) - onResponse?(response.id!, cacao) + onResponse?(subscriptionPayload.request.id!, cacao) } catch { logger.debug("Received response with invalid signature") } }.store(in: &publishers) } } - diff --git a/Sources/Auth/Services/Common/NetworkingInteractor.swift b/Sources/Auth/Services/Common/NetworkingInteractor.swift index d81e8ccfb..eb035ea26 100644 --- a/Sources/Auth/Services/Common/NetworkingInteractor.swift +++ b/Sources/Auth/Services/Common/NetworkingInteractor.swift @@ -7,9 +7,10 @@ import JSONRPC protocol NetworkInteracting { var requestPublisher: AnyPublisher {get} - var responsePublisher: AnyPublisher {get} + var responsePublisher: AnyPublisher {get} func subscribe(topic: String) async throws + func unsubscribe(topic: String) func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws } @@ -27,11 +28,11 @@ class NetworkingInteractor: NetworkInteracting { var requestPublisher: AnyPublisher { requestPublisherSubject.eraseToAnyPublisher() } - var responsePublisher: AnyPublisher { + private let requestPublisherSubject = PassthroughSubject() + var responsePublisher: AnyPublisher { responsePublisherSubject.eraseToAnyPublisher() } - private let responsePublisherSubject = PassthroughSubject() - private let requestPublisherSubject = PassthroughSubject() + private let responsePublisherSubject = PassthroughSubject() init(relayClient: RelayClient, serializer: Serializing, @@ -45,6 +46,10 @@ class NetworkingInteractor: NetworkInteracting { try await relayClient.subscribe(topic: topic) } + func unsubscribe(topic: String) { + fatalError("not implemented") + } + func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { try rpcHistory.set(request, forTopic: topic, emmitedBy: .local) let message = try! serializer.serialize(topic: topic, encodable: request, envelopeType: envelopeType) diff --git a/Sources/Auth/Types/RequestSubscriptionPayload.swift b/Sources/Auth/Types/RequestSubscriptionPayload.swift index b7865d715..00a5cdcb4 100644 --- a/Sources/Auth/Types/RequestSubscriptionPayload.swift +++ b/Sources/Auth/Types/RequestSubscriptionPayload.swift @@ -1,7 +1,7 @@ import Foundation import JSONRPC -struct RequestSubscriptionPayload: Codable { - let id: Int64 +struct RequestSubscriptionPayload: Codable, Equatable { + let topic: String let request: RPCRequest } diff --git a/Sources/Auth/Types/ResponseSubscriptionPayload.swift b/Sources/Auth/Types/ResponseSubscriptionPayload.swift new file mode 100644 index 000000000..94c77ff86 --- /dev/null +++ b/Sources/Auth/Types/ResponseSubscriptionPayload.swift @@ -0,0 +1,7 @@ +import Foundation +import JSONRPC + +struct ResponseSubscriptionPayload: Codable, Equatable { + let topic: String + let request: RPCResponse +} diff --git a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift b/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift index d7c546725..2ccd19b84 100644 --- a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift +++ b/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift @@ -5,8 +5,11 @@ import JSONRPC import WalletConnectKMS struct NetworkingInteractorMock: NetworkInteracting { - var responsePublisher: AnyPublisher + var responsePublisher: AnyPublisher { + responsePublisherSubject.eraseToAnyPublisher() + } + private let responsePublisherSubject = PassthroughSubject() let requestPublisherSubject = PassthroughSubject() var requestPublisher: AnyPublisher { @@ -17,6 +20,10 @@ struct NetworkingInteractorMock: NetworkInteracting { } + func unsubscribe(topic: String) { + + } + func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { } diff --git a/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift b/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift index 0423623ec..87ddb00a5 100644 --- a/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift +++ b/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift @@ -10,6 +10,6 @@ extension RequestSubscriptionPayload { let payload = AuthPayload(requestParams: RequestParams.stub(), iat: issueAt) let params = AuthRequestParams(requester: requester, payloadParams: payload) let request = RPCRequest(method: "wc_authRequest", params: params, id: id) - return RequestSubscriptionPayload(id: 123, request: request) + return RequestSubscriptionPayload(topic: "123", request: request) } } From 0051b90152bff10a8a8fa561f4431edbacba2a03 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 4 Aug 2022 09:10:09 +0200 Subject: [PATCH 03/20] run lint --- Sources/Auth/Services/App/AuthRespondSubscriber.swift | 2 +- Sources/Auth/Services/Common/CacaoSignatureVerifier.swift | 1 - Sources/Auth/Services/Common/NetworkingInteractor.swift | 3 +-- Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Sources/Auth/Services/App/AuthRespondSubscriber.swift b/Sources/Auth/Services/App/AuthRespondSubscriber.swift index ad8dcb7ed..a6f1f8b57 100644 --- a/Sources/Auth/Services/App/AuthRespondSubscriber.swift +++ b/Sources/Auth/Services/App/AuthRespondSubscriber.swift @@ -8,7 +8,7 @@ class AuthRespondSubscriber { private let logger: ConsoleLogging private let rpcHistory: RPCHistory private var publishers = [AnyCancellable]() - var onResponse: ((_ id: RPCID, _ cacao: Cacao)->Void)? + var onResponse: ((_ id: RPCID, _ cacao: Cacao) -> Void)? init(networkingInteractor: NetworkInteracting, logger: ConsoleLogging, diff --git a/Sources/Auth/Services/Common/CacaoSignatureVerifier.swift b/Sources/Auth/Services/Common/CacaoSignatureVerifier.swift index 76a6911c8..64f70488b 100644 --- a/Sources/Auth/Services/Common/CacaoSignatureVerifier.swift +++ b/Sources/Auth/Services/Common/CacaoSignatureVerifier.swift @@ -13,4 +13,3 @@ class CacaoSignatureVerifier: CacaoSignatureVerifying { fatalError("not implemented") } } - diff --git a/Sources/Auth/Services/Common/NetworkingInteractor.swift b/Sources/Auth/Services/Common/NetworkingInteractor.swift index eb035ea26..fd480db62 100644 --- a/Sources/Auth/Services/Common/NetworkingInteractor.swift +++ b/Sources/Auth/Services/Common/NetworkingInteractor.swift @@ -8,9 +8,8 @@ import JSONRPC protocol NetworkInteracting { var requestPublisher: AnyPublisher {get} var responsePublisher: AnyPublisher {get} - func subscribe(topic: String) async throws - func unsubscribe(topic: String) + func unsubscribe(topic: String) func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws } diff --git a/Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift b/Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift index 07469153d..c78b66385 100644 --- a/Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift +++ b/Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift @@ -7,7 +7,7 @@ class AuthRequestSubscriber { private let logger: ConsoleLogging private var publishers = [AnyCancellable]() private let messageFormatter: SIWEMessageFormatting - var onRequest: ((_ id: Int64, _ message: String)->Void)? + var onRequest: ((_ id: Int64, _ message: String) -> Void)? init(networkingInteractor: NetworkInteracting, logger: ConsoleLogging, From cf8cdc9fe9acb8543e497a24f0ef95f2c0a479fb Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 5 Aug 2022 08:26:26 +0200 Subject: [PATCH 04/20] Add siwe message --- .../Common/SIWEMessageFormatter.swift | 52 +++++++++++++++++++ Sources/Auth/Types/AuthPayload.swift | 4 +- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift index edf489f74..3fecf6ffd 100644 --- a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift +++ b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift @@ -9,3 +9,55 @@ struct SIWEMessageFormatter: SIWEMessageFormatting { fatalError("not implemented") } } + +struct SIWEMessage: Equatable { + let domain: String + let uri: String //aud + let address: String + let version: String + let nonce: String + let chainId: String + let type: String + let iat: String + let nbf: String? + let exp: String? + let statement: String? + let requestId: String? + let resources: String? + + var formatted: String { + return """ + \(domain) wants you to sign in with your Ethereum account:\n + \(address)\n + + \(statementLine) + URI: \(uri)\n + Version: \(version)\n + Chain ID: \(chainId)\n + Nonce: \(nonce)\n + Issued At: \(iat)\n + \(expLine) + Not Before: ${not-before} + Request ID: ${request-id} + Resources: + - ${resources[0]} + - ${resources[1]} + ... + - ${resources[n]} + """ + } + + var expLine: String { + if let exp = exp { + return "Expiration Time: \(exp)\n" + } + return "" + } + + var statementLine: String { + if let statement = statement { + return "\(statement)\n" + } + return "" + } +} diff --git a/Sources/Auth/Types/AuthPayload.swift b/Sources/Auth/Types/AuthPayload.swift index b281c19d0..ae4e27eed 100644 --- a/Sources/Auth/Types/AuthPayload.swift +++ b/Sources/Auth/Types/AuthPayload.swift @@ -1,12 +1,12 @@ import Foundation struct AuthPayload: Codable, Equatable { - let type: String - let chainId: String let domain: String let aud: String let version: String let nonce: String + let chainId: String + let type: String let iat: String let nbf: String? let exp: String? From b8da4f1236e7bb84af6365e9e33edd3f25f97bbf Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 5 Aug 2022 10:33:30 +0200 Subject: [PATCH 05/20] update siwe message --- .../Common/SIWEMessageFormatter.swift | 64 ++++++++++++++----- Sources/Auth/Types/AuthPayload.swift | 4 +- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift index 3fecf6ffd..0e625ebd2 100644 --- a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift +++ b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift @@ -1,12 +1,24 @@ import Foundation +import WalletConnectUtils protocol SIWEMessageFormatting { - func formatMessage(from request: AuthRequestParams) throws -> String + func formatMessage(from authPayload: AuthPayload, address: String) throws -> String } struct SIWEMessageFormatter: SIWEMessageFormatting { - func formatMessage(from request: AuthRequestParams) throws -> String { - fatalError("not implemented") + func formatMessage(from authPayload: AuthPayload, address: String) throws -> String { + SIWEMessage(domain: authPayload.domain, + uri: authPayload.aud, + address: address, + version: authPayload.version, + nonce: authPayload.nonce, + chainId: authPayload.chainId, + iat: authPayload.iat, + nbf: authPayload.nbf, + exp: authPayload.exp, + statement: authPayload.statement, + requestId: authPayload.requestId, + resources: authPayload.resources).formatted } } @@ -14,16 +26,15 @@ struct SIWEMessage: Equatable { let domain: String let uri: String //aud let address: String - let version: String + let version: Int let nonce: String let chainId: String - let type: String let iat: String let nbf: String? let exp: String? let statement: String? let requestId: String? - let resources: String? + let resources: [String]? var formatted: String { return """ @@ -35,29 +46,50 @@ struct SIWEMessage: Equatable { Version: \(version)\n Chain ID: \(chainId)\n Nonce: \(nonce)\n - Issued At: \(iat)\n + Issued At: \(iat) \(expLine) - Not Before: ${not-before} - Request ID: ${request-id} - Resources: - - ${resources[0]} - - ${resources[1]} - ... - - ${resources[n]} + \(nbfLine) + \(requestIdLine) + \(resourcesSection) """ } var expLine: String { if let exp = exp { - return "Expiration Time: \(exp)\n" + return "\nExpiration Time: \(exp)" } return "" } var statementLine: String { if let statement = statement { - return "\(statement)\n" + return "\n\(statement)" } return "" } + + var nbfLine: String { + if let nbf = nbf { + return "\nNot Before: \(nbf)" + } + return "" + } + + var requestIdLine: String { + if let requestId = requestId { + return "\nRequest ID: \(requestId)" + } + return "" + } + + var resourcesSection: String { + var section = "" + if let resources = resources { + section = "\nResources:" + resources.forEach { + section.append("\n- \($0)") + } + } + return section + } } diff --git a/Sources/Auth/Types/AuthPayload.swift b/Sources/Auth/Types/AuthPayload.swift index ae4e27eed..72cac98b1 100644 --- a/Sources/Auth/Types/AuthPayload.swift +++ b/Sources/Auth/Types/AuthPayload.swift @@ -3,7 +3,7 @@ import Foundation struct AuthPayload: Codable, Equatable { let domain: String let aud: String - let version: String + let version: Int let nonce: String let chainId: String let type: String @@ -12,7 +12,7 @@ struct AuthPayload: Codable, Equatable { let exp: String? let statement: String? let requestId: String? - let resources: String? + let resources: [String]? init(requestParams: RequestParams, iat: String) { self.type = "eip4361" From 3ca3f6aa8558f7bf20b755e1883fadb657d67704 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 5 Aug 2022 10:54:15 +0200 Subject: [PATCH 06/20] Add siwe formatter test --- .../Common/SIWEMessageFormatter.swift | 4 +-- .../Wallet/AuthRequestSubscriber.swift | 7 ++-- Sources/Auth/Types/AuthPayload.swift | 2 +- Sources/Auth/Types/RequestParams.swift | 2 +- .../AuthTests/AuthRequstSubscriberTests.swift | 2 +- .../Mocks/SIWEMessageFormatterMock.swift | 2 +- .../AuthTests/SIWEMessageFormatterTests.swift | 34 +++++++++++++++++++ Tests/AuthTests/Stubs/AuthPayload.swift | 8 +++++ Tests/AuthTests/Stubs/RequestParams.swift | 10 +++++- .../Stubs/RequestSubscriptionPayload.swift | 2 +- 10 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 Tests/AuthTests/SIWEMessageFormatterTests.swift create mode 100644 Tests/AuthTests/Stubs/AuthPayload.swift diff --git a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift index 0e625ebd2..a5ce65da6 100644 --- a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift +++ b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift @@ -2,11 +2,11 @@ import Foundation import WalletConnectUtils protocol SIWEMessageFormatting { - func formatMessage(from authPayload: AuthPayload, address: String) throws -> String + func formatMessage(from authPayload: AuthPayload, address: String) -> String } struct SIWEMessageFormatter: SIWEMessageFormatting { - func formatMessage(from authPayload: AuthPayload, address: String) throws -> String { + func formatMessage(from authPayload: AuthPayload, address: String) -> String { SIWEMessage(domain: authPayload.domain, uri: authPayload.aud, address: address, diff --git a/Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift b/Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift index d65a56bae..a2a5f9b29 100644 --- a/Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift +++ b/Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift @@ -6,15 +6,18 @@ import JSONRPC class AuthRequestSubscriber { private let networkingInteractor: NetworkInteracting private let logger: ConsoleLogging + private let address: String private var publishers = [AnyCancellable]() private let messageFormatter: SIWEMessageFormatting var onRequest: ((_ id: RPCID, _ message: String)->())? init(networkingInteractor: NetworkInteracting, logger: ConsoleLogging, - messageFormatter: SIWEMessageFormatting) { + messageFormatter: SIWEMessageFormatting, + address: String) { self.networkingInteractor = networkingInteractor self.logger = logger + self.address = address self.messageFormatter = messageFormatter subscribeForRequest() } @@ -27,7 +30,7 @@ class AuthRequestSubscriber { return } do { - let message = try messageFormatter.formatMessage(from: authRequestParams) + let message = try messageFormatter.formatMessage(from: authRequestParams.payloadParams, address: address) guard let requestId = subscriptionPayload.request.id else { return } onRequest?(requestId, message) } catch { diff --git a/Sources/Auth/Types/AuthPayload.swift b/Sources/Auth/Types/AuthPayload.swift index 72cac98b1..35a4b2338 100644 --- a/Sources/Auth/Types/AuthPayload.swift +++ b/Sources/Auth/Types/AuthPayload.swift @@ -19,7 +19,7 @@ struct AuthPayload: Codable, Equatable { self.chainId = requestParams.chainId self.domain = requestParams.domain self.aud = requestParams.aud - self.version = "1" + self.version = 1 self.nonce = requestParams.nonce self.iat = iat self.nbf = requestParams.nbf diff --git a/Sources/Auth/Types/RequestParams.swift b/Sources/Auth/Types/RequestParams.swift index 7a6082f52..24e7afab9 100644 --- a/Sources/Auth/Types/RequestParams.swift +++ b/Sources/Auth/Types/RequestParams.swift @@ -9,5 +9,5 @@ struct RequestParams { let exp: String? let statement: String? let requestId: String? - let resources: String? + let resources: [String]? } diff --git a/Tests/AuthTests/AuthRequstSubscriberTests.swift b/Tests/AuthTests/AuthRequstSubscriberTests.swift index c457d9246..990a9cb4f 100644 --- a/Tests/AuthTests/AuthRequstSubscriberTests.swift +++ b/Tests/AuthTests/AuthRequstSubscriberTests.swift @@ -17,7 +17,7 @@ class AuthRequstSubscriberTests: XCTestCase { messageFormatter = SIWEMessageFormatterMock() sut = AuthRequestSubscriber(networkingInteractor: networkingInteractor, logger: ConsoleLoggerMock(), - messageFormatter: messageFormatter) + messageFormatter: messageFormatter, address: "") } func testSubscribeRequest() { diff --git a/Tests/AuthTests/Mocks/SIWEMessageFormatterMock.swift b/Tests/AuthTests/Mocks/SIWEMessageFormatterMock.swift index b576bfc68..bce7c4824 100644 --- a/Tests/AuthTests/Mocks/SIWEMessageFormatterMock.swift +++ b/Tests/AuthTests/Mocks/SIWEMessageFormatterMock.swift @@ -3,7 +3,7 @@ import Foundation class SIWEMessageFormatterMock: SIWEMessageFormatting { var formattedMessage: String! - func formatMessage(from request: AuthRequestParams) throws -> String { + func formatMessage(from authPayload: AuthPayload, address: String) -> String { return formattedMessage } } diff --git a/Tests/AuthTests/SIWEMessageFormatterTests.swift b/Tests/AuthTests/SIWEMessageFormatterTests.swift new file mode 100644 index 000000000..b7d8e0b96 --- /dev/null +++ b/Tests/AuthTests/SIWEMessageFormatterTests.swift @@ -0,0 +1,34 @@ +import Foundation +@testable import Auth +import XCTest + +class SIWEMessageFormatterTests: XCTestCase { + var sut: SIWEMessageFormatter! + var expectedMessage = + """ + service.invalid wants you to sign in with your Ethereum account: + 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + + I accept the ServiceOrg Terms of Service: https://service.invalid/tos + + URI: https://service.invalid/login + Version: 1 + Chain ID: 1 + Nonce: 32891756 + Issued At: 2021-09-30T16:25:24Z + Resources: + - ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/ + - https://example.com/my-web2-claim.json + """ + + override func setUp() { + sut = SIWEMessageFormatter() + } + + func testFormatMessage() { + let address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + let message = sut.formatMessage(from: AuthPayload.stub(), address: address) + print(message) + XCTAssertEqual(message, expectedMessage) + } +} diff --git a/Tests/AuthTests/Stubs/AuthPayload.swift b/Tests/AuthTests/Stubs/AuthPayload.swift new file mode 100644 index 000000000..ba088bb4d --- /dev/null +++ b/Tests/AuthTests/Stubs/AuthPayload.swift @@ -0,0 +1,8 @@ +import Foundation +@testable import Auth + +extension AuthPayload { + static func stub() -> AuthPayload { + AuthPayload(requestParams: RequestParams.stub(), iat: "2021-09-30T16:25:24Z") + } +} diff --git a/Tests/AuthTests/Stubs/RequestParams.swift b/Tests/AuthTests/Stubs/RequestParams.swift index 9a3890289..8e16ce226 100644 --- a/Tests/AuthTests/Stubs/RequestParams.swift +++ b/Tests/AuthTests/Stubs/RequestParams.swift @@ -3,6 +3,14 @@ import Foundation extension RequestParams { static func stub() -> RequestParams { - return RequestParams(domain: "", chainId: "", nonce: "", aud: "", nbf: nil, exp: nil, statement: nil, requestId: nil, resources: nil) + return RequestParams(domain: "service.invalid", + chainId: "1", + nonce: "32891756", + aud: "https://service.invalid/login", + nbf: nil, + exp: nil, + statement: "I accept the ServiceOrg Terms of Service: https://service.invalid/tos", + requestId: nil, + resources: ["ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/", "https://example.com/my-web2-claim.json"]) } } diff --git a/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift b/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift index afeb1c281..48ded537d 100644 --- a/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift +++ b/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift @@ -10,6 +10,6 @@ extension RequestSubscriptionPayload { let payload = AuthPayload(requestParams: RequestParams.stub(), iat: issueAt) let params = AuthRequestParams(requester: requester, payloadParams: payload) let request = RPCRequest(method: "wc_authRequest", params: params, rpcid: id) - return RequestSubscriptionPayload(id: 123, request: request) + return RequestSubscriptionPayload(topic: "123", request: request) } } From 835a984d4a8cf5eea63dc6002e825e8ce1f5b3a4 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 5 Aug 2022 11:02:32 +0200 Subject: [PATCH 07/20] fix siwe formatter tests --- .../Common/SIWEMessageFormatter.swift | 22 ++++++++----------- .../AuthTests/SIWEMessageFormatterTests.swift | 22 +++++++++---------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift index a5ce65da6..166c4e990 100644 --- a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift +++ b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift @@ -38,19 +38,15 @@ struct SIWEMessage: Equatable { var formatted: String { return """ - \(domain) wants you to sign in with your Ethereum account:\n - \(address)\n + \(domain) wants you to sign in with your Ethereum account: + \(address) - \(statementLine) - URI: \(uri)\n - Version: \(version)\n - Chain ID: \(chainId)\n - Nonce: \(nonce)\n - Issued At: \(iat) - \(expLine) - \(nbfLine) - \(requestIdLine) - \(resourcesSection) + \(statementLine) + URI: \(uri) + Version: \(version) + Chain ID: \(chainId) + Nonce: \(nonce) + Issued At: \(iat)\(expLine)\(nbfLine)\(requestIdLine)\(resourcesSection) """ } @@ -63,7 +59,7 @@ struct SIWEMessage: Equatable { var statementLine: String { if let statement = statement { - return "\n\(statement)" + return "\(statement)\n" } return "" } diff --git a/Tests/AuthTests/SIWEMessageFormatterTests.swift b/Tests/AuthTests/SIWEMessageFormatterTests.swift index b7d8e0b96..9bf4a002a 100644 --- a/Tests/AuthTests/SIWEMessageFormatterTests.swift +++ b/Tests/AuthTests/SIWEMessageFormatterTests.swift @@ -6,19 +6,19 @@ class SIWEMessageFormatterTests: XCTestCase { var sut: SIWEMessageFormatter! var expectedMessage = """ - service.invalid wants you to sign in with your Ethereum account: - 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + service.invalid wants you to sign in with your Ethereum account: + 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 - I accept the ServiceOrg Terms of Service: https://service.invalid/tos + I accept the ServiceOrg Terms of Service: https://service.invalid/tos - URI: https://service.invalid/login - Version: 1 - Chain ID: 1 - Nonce: 32891756 - Issued At: 2021-09-30T16:25:24Z - Resources: - - ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/ - - https://example.com/my-web2-claim.json + URI: https://service.invalid/login + Version: 1 + Chain ID: 1 + Nonce: 32891756 + Issued At: 2021-09-30T16:25:24Z + Resources: + - ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/ + - https://example.com/my-web2-claim.json """ override func setUp() { From 6acc70308f083a7424fad00791f7506155387350 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 5 Aug 2022 12:08:46 +0200 Subject: [PATCH 08/20] change scope of siwe message --- Sources/Auth/Services/Common/SIWEMessageFormatter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift index 166c4e990..f8aa2e47b 100644 --- a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift +++ b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift @@ -22,7 +22,7 @@ struct SIWEMessageFormatter: SIWEMessageFormatting { } } -struct SIWEMessage: Equatable { +fileprivate struct SIWEMessage: Equatable { let domain: String let uri: String //aud let address: String From d6173f34edac7f5d7a26e5a7c78db5e6aa35423f Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 5 Aug 2022 15:43:32 +0200 Subject: [PATCH 09/20] update siwemessage --- .../Common/SIWEMessageFormatter.swift | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift index f8aa2e47b..7374083fd 100644 --- a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift +++ b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift @@ -51,40 +51,30 @@ fileprivate struct SIWEMessage: Equatable { } var expLine: String { - if let exp = exp { - return "\nExpiration Time: \(exp)" - } - return "" + guard let exp = exp else { return "" } + return "\nExpiration Time: \(exp)" } var statementLine: String { - if let statement = statement { - return "\(statement)\n" - } - return "" + guard let statement = statement else { return "" } + return "\(statement)\n" } var nbfLine: String { - if let nbf = nbf { - return "\nNot Before: \(nbf)" - } - return "" + guard let nbf = nbf else { return "" } + return "\nNot Before: \(nbf)" } var requestIdLine: String { - if let requestId = requestId { - return "\nRequest ID: \(requestId)" - } - return "" + guard let requestId = requestId else { return "" } + return "\nRequest ID: \(requestId)" } var resourcesSection: String { - var section = "" - if let resources = resources { - section = "\nResources:" - resources.forEach { - section.append("\n- \($0)") - } + guard let resources = resources else { return "" } + var section = "\nResources:" + resources.forEach { + section.append("\n- \($0)") } return section } From ce32f44570e4c017556d392529cf493b907a4b72 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 5 Aug 2022 15:48:12 +0200 Subject: [PATCH 10/20] update resources --- Sources/Auth/Services/Common/SIWEMessageFormatter.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift index 7374083fd..22ea7e206 100644 --- a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift +++ b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift @@ -72,10 +72,6 @@ fileprivate struct SIWEMessage: Equatable { var resourcesSection: String { guard let resources = resources else { return "" } - var section = "\nResources:" - resources.forEach { - section.append("\n- \($0)") - } - return section + return resources.reduce("\nResources:") { $0 + "\n- \($1)" } } } From bac3ff463b56098a62e6ae480d466cd8f3056f7b Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Fri, 5 Aug 2022 16:57:48 +0300 Subject: [PATCH 11/20] testNilOptionalParamsMessage --- .../AuthTests/SIWEMessageFormatterTests.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Tests/AuthTests/SIWEMessageFormatterTests.swift b/Tests/AuthTests/SIWEMessageFormatterTests.swift index 9bf4a002a..141732295 100644 --- a/Tests/AuthTests/SIWEMessageFormatterTests.swift +++ b/Tests/AuthTests/SIWEMessageFormatterTests.swift @@ -28,7 +28,24 @@ class SIWEMessageFormatterTests: XCTestCase { func testFormatMessage() { let address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" let message = sut.formatMessage(from: AuthPayload.stub(), address: address) - print(message) + XCTAssertEqual(message, expectedMessage) } + + func testNilOptionalParamsMessage() { + let address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + + let message = sut.formatMessage(from: AuthPayload( + requestParams: RequestParams( + domain: "domain", + chainId: "chainId", + nonce: "nonce", + aud: "aud", + nbf: nil, exp: nil, statement: nil, requestId: nil, resources: nil + ), + iat: "2021-09-30T16:25:24Z" + ), address: address) + + XCTAssertEqual(message, "") + } } From e44379d52373c9d1cc0257e97290092ef2e4a2b4 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Aug 2022 07:30:48 +0200 Subject: [PATCH 12/20] Add test cases --- .../Common/SIWEMessageFormatter.swift | 3 +- .../AuthTests/SIWEMessageFormatterTests.swift | 110 +++++++++++++----- Tests/AuthTests/Stubs/AuthPayload.swift | 4 +- Tests/AuthTests/Stubs/RequestParams.swift | 28 +++-- 4 files changed, 99 insertions(+), 46 deletions(-) diff --git a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift index 22ea7e206..733198e33 100644 --- a/Sources/Auth/Services/Common/SIWEMessageFormatter.swift +++ b/Sources/Auth/Services/Common/SIWEMessageFormatter.swift @@ -40,7 +40,6 @@ fileprivate struct SIWEMessage: Equatable { return """ \(domain) wants you to sign in with your Ethereum account: \(address) - \(statementLine) URI: \(uri) Version: \(version) @@ -57,7 +56,7 @@ fileprivate struct SIWEMessage: Equatable { var statementLine: String { guard let statement = statement else { return "" } - return "\(statement)\n" + return "\n\(statement)\n" } var nbfLine: String { diff --git a/Tests/AuthTests/SIWEMessageFormatterTests.swift b/Tests/AuthTests/SIWEMessageFormatterTests.swift index 141732295..98e9945b0 100644 --- a/Tests/AuthTests/SIWEMessageFormatterTests.swift +++ b/Tests/AuthTests/SIWEMessageFormatterTests.swift @@ -4,48 +4,94 @@ import XCTest class SIWEMessageFormatterTests: XCTestCase { var sut: SIWEMessageFormatter! - var expectedMessage = - """ - service.invalid wants you to sign in with your Ethereum account: - 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 - - I accept the ServiceOrg Terms of Service: https://service.invalid/tos - - URI: https://service.invalid/login - Version: 1 - Chain ID: 1 - Nonce: 32891756 - Issued At: 2021-09-30T16:25:24Z - Resources: - - ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/ - - https://example.com/my-web2-claim.json - """ + let address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + override func setUp() { sut = SIWEMessageFormatter() } func testFormatMessage() { - let address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + let expectedMessage = + """ + service.invalid wants you to sign in with your Ethereum account: + 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + + I accept the ServiceOrg Terms of Service: https://service.invalid/tos + + URI: https://service.invalid/login + Version: 1 + Chain ID: 1 + Nonce: 32891756 + Issued At: 2021-09-30T16:25:24Z + Resources: + - ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/ + - https://example.com/my-web2-claim.json + """ let message = sut.formatMessage(from: AuthPayload.stub(), address: address) + XCTAssertEqual(message, expectedMessage) + } + + func testNilStatement() { + let expectedMessage = + """ + service.invalid wants you to sign in with your Ethereum account: + 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + URI: https://service.invalid/login + Version: 1 + Chain ID: 1 + Nonce: 32891756 + Issued At: 2021-09-30T16:25:24Z + Resources: + - ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/ + - https://example.com/my-web2-claim.json + """ + let message = sut.formatMessage( + from: AuthPayload.stub( + requestParams: RequestParams.stub(statement: nil)), + address: address) XCTAssertEqual(message, expectedMessage) } - func testNilOptionalParamsMessage() { - let address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" - - let message = sut.formatMessage(from: AuthPayload( - requestParams: RequestParams( - domain: "domain", - chainId: "chainId", - nonce: "nonce", - aud: "aud", - nbf: nil, exp: nil, statement: nil, requestId: nil, resources: nil - ), - iat: "2021-09-30T16:25:24Z" - ), address: address) - - XCTAssertEqual(message, "") + func testNilResources() { + let expectedMessage = + """ + service.invalid wants you to sign in with your Ethereum account: + 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + + I accept the ServiceOrg Terms of Service: https://service.invalid/tos + + URI: https://service.invalid/login + Version: 1 + Chain ID: 1 + Nonce: 32891756 + Issued At: 2021-09-30T16:25:24Z + """ + let message = sut.formatMessage( + from: AuthPayload.stub( + requestParams: RequestParams.stub(resources: nil)), + address: address) + XCTAssertEqual(message, expectedMessage) + } + + func testNilAllOptionalParams() { + let expectedMessage = + """ + service.invalid wants you to sign in with your Ethereum account: + 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + + URI: https://service.invalid/login + Version: 1 + Chain ID: 1 + Nonce: 32891756 + Issued At: 2021-09-30T16:25:24Z + """ + let message = sut.formatMessage( + from: AuthPayload.stub( + requestParams: RequestParams.stub(statement: nil, + resources: nil)), + address: address) + XCTAssertEqual(message, expectedMessage) } } diff --git a/Tests/AuthTests/Stubs/AuthPayload.swift b/Tests/AuthTests/Stubs/AuthPayload.swift index ba088bb4d..c305aee03 100644 --- a/Tests/AuthTests/Stubs/AuthPayload.swift +++ b/Tests/AuthTests/Stubs/AuthPayload.swift @@ -2,7 +2,7 @@ import Foundation @testable import Auth extension AuthPayload { - static func stub() -> AuthPayload { - AuthPayload(requestParams: RequestParams.stub(), iat: "2021-09-30T16:25:24Z") + static func stub(requestParams: RequestParams = RequestParams.stub()) -> AuthPayload { + AuthPayload(requestParams: requestParams, iat: "2021-09-30T16:25:24Z") } } diff --git a/Tests/AuthTests/Stubs/RequestParams.swift b/Tests/AuthTests/Stubs/RequestParams.swift index 8e16ce226..e594798ee 100644 --- a/Tests/AuthTests/Stubs/RequestParams.swift +++ b/Tests/AuthTests/Stubs/RequestParams.swift @@ -2,15 +2,23 @@ import Foundation @testable import Auth extension RequestParams { - static func stub() -> RequestParams { - return RequestParams(domain: "service.invalid", - chainId: "1", - nonce: "32891756", - aud: "https://service.invalid/login", - nbf: nil, - exp: nil, - statement: "I accept the ServiceOrg Terms of Service: https://service.invalid/tos", - requestId: nil, - resources: ["ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/", "https://example.com/my-web2-claim.json"]) + static func stub(domain: String = "service.invalid", + chainId: String = "1", + nonce: String = "32891756", + aud: String = "https://service.invalid/login", + nbf: String? = nil, + exp: String? = nil, + statement: String? = "I accept the ServiceOrg Terms of Service: https://service.invalid/tos", + requestId: String? = nil, + resources: [String]? = ["ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/", "https://example.com/my-web2-claim.json"]) -> RequestParams { + return RequestParams(domain: domain, + chainId: chainId, + nonce: nonce, + aud: aud, + nbf: nbf, + exp: exp, + statement: statement, + requestId: requestId, + resources: resources) } } From df7df5409513fd3941f6e1d1c04581409e8026c5 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Aug 2022 08:30:03 +0200 Subject: [PATCH 13/20] test --- .github/actions/ci/action.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index 4e6735c13..5f28b0e83 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -16,7 +16,8 @@ runs: -project Example/ExampleApp.xcodeproj \ -scheme WalletConnect \ -clonedSourcePackagesDirPath SourcePackages \ - -sdk iphonesimulator" + -sdk iphonesimulator \ + test" # Integration tests - name: Run integration tests From 9b3dd7d3f8e04bf8d6fa1e79340eac893ad04cf0 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Aug 2022 08:37:19 +0200 Subject: [PATCH 14/20] add destination --- .github/actions/ci/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index 5f28b0e83..1e887a78c 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -16,7 +16,7 @@ runs: -project Example/ExampleApp.xcodeproj \ -scheme WalletConnect \ -clonedSourcePackagesDirPath SourcePackages \ - -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 13' \ test" # Integration tests From 7dbbf7d4a065775abee782d1dc9b9bcfa66f8774 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Aug 2022 08:48:41 +0200 Subject: [PATCH 15/20] fix jsonrpc test id params --- .../Stubs/RequestSubscriptionPayload.swift | 2 +- Tests/JSONRPCTests/Helpers.swift | 4 ++-- Tests/JSONRPCTests/RPCResponseTests.swift | 14 +++++++------- Tests/TestingUtils/Helpers.swift | 6 ++++++ .../WalletConnectUtilsTests/RPCHistoryTests.swift | 2 +- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift b/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift index afeb1c281..48ded537d 100644 --- a/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift +++ b/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift @@ -10,6 +10,6 @@ extension RequestSubscriptionPayload { let payload = AuthPayload(requestParams: RequestParams.stub(), iat: issueAt) let params = AuthRequestParams(requester: requester, payloadParams: payload) let request = RPCRequest(method: "wc_authRequest", params: params, rpcid: id) - return RequestSubscriptionPayload(id: 123, request: request) + return RequestSubscriptionPayload(topic: "123", request: request) } } diff --git a/Tests/JSONRPCTests/Helpers.swift b/Tests/JSONRPCTests/Helpers.swift index 9ffc0b45c..df20bab6b 100644 --- a/Tests/JSONRPCTests/Helpers.swift +++ b/Tests/JSONRPCTests/Helpers.swift @@ -3,14 +3,14 @@ import Commons final class TestIdentifierGenerator: IdentifierGenerator { - var id: RPCID = .right(Int.random()) + var id: RPCID = .right(Int64.random()) func next() -> RPCID { return id } } -extension Either where L == String, R == Int { +extension Either where L == String, R == Int64 { var isString: Bool { left != nil diff --git a/Tests/JSONRPCTests/RPCResponseTests.swift b/Tests/JSONRPCTests/RPCResponseTests.swift index 954dcc322..d067761b3 100644 --- a/Tests/JSONRPCTests/RPCResponseTests.swift +++ b/Tests/JSONRPCTests/RPCResponseTests.swift @@ -5,20 +5,20 @@ import TestingUtils private func makeResultResponses() -> [RPCResponse] { return [ - RPCResponse(id: Int.random(), result: Int.random()), - RPCResponse(id: Int.random(), result: Bool.random()), - RPCResponse(id: Int.random(), result: String.random()), - RPCResponse(id: Int.random(), result: (1...10).map { String($0) }), - RPCResponse(id: Int.random(), result: EmptyCodable()), + RPCResponse(id: Int64.random(), result: Int.random()), + RPCResponse(id: Int64.random(), result: Bool.random()), + RPCResponse(id: Int64.random(), result: String.random()), + RPCResponse(id: Int64.random(), result: (1...10).map { String($0) }), + RPCResponse(id: Int64.random(), result: EmptyCodable()), RPCResponse(id: String.random(), result: Int.random()) ] } private func makeErrorResponses() -> [RPCResponse] { return [ - RPCResponse(id: Int.random(), error: JSONRPCError.stub()), + RPCResponse(id: Int64.random(), error: JSONRPCError.stub()), RPCResponse(id: String.random(), error: JSONRPCError.stub(data: AnyCodable(Int.random()))), - RPCResponse(id: Int.random(), errorCode: Int.random(), message: String.random(), associatedData: AnyCodable(String.random())), + RPCResponse(id: Int64.random(), errorCode: Int.random(), message: String.random(), associatedData: AnyCodable(String.random())), RPCResponse(id: String.random(), errorCode: Int.random(), message: String.random(), associatedData: nil) ] } diff --git a/Tests/TestingUtils/Helpers.swift b/Tests/TestingUtils/Helpers.swift index dbe46147d..00cd925e1 100644 --- a/Tests/TestingUtils/Helpers.swift +++ b/Tests/TestingUtils/Helpers.swift @@ -9,6 +9,12 @@ public extension Int { } } +public extension Int64 { + static func random() -> Int64 { + random(in: Int64.min...Int64.max) + } +} + public extension Double { // Do not use this function when testing Codables: https://bugs.swift.org/browse/SR-7054 diff --git a/Tests/WalletConnectUtilsTests/RPCHistoryTests.swift b/Tests/WalletConnectUtilsTests/RPCHistoryTests.swift index 10bfbc049..37b05ccdd 100644 --- a/Tests/WalletConnectUtilsTests/RPCHistoryTests.swift +++ b/Tests/WalletConnectUtilsTests/RPCHistoryTests.swift @@ -65,7 +65,7 @@ final class RPCHistoryTests: XCTestCase { func testSetDuplicateRequest() throws { let expectedError = RPCHistory.HistoryError.requestDuplicateNotAllowed - let id = Int.random() + let id = Int64.random() let requestA = RPCRequest.stub(method: "method-1", id: id) let requestB = RPCRequest.stub(method: "method-2", id: id) let topic = String.randomTopic() From e16941fec269cbdf9d67783960fcec31ed41d988 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Aug 2022 08:51:26 +0200 Subject: [PATCH 16/20] fix rpc tests --- Tests/JSONRPCTests/RPCRequestTests.swift | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Tests/JSONRPCTests/RPCRequestTests.swift b/Tests/JSONRPCTests/RPCRequestTests.swift index be2460bee..f34d365ba 100644 --- a/Tests/JSONRPCTests/RPCRequestTests.swift +++ b/Tests/JSONRPCTests/RPCRequestTests.swift @@ -5,13 +5,13 @@ import TestingUtils private func makeRequests() -> [RPCRequest] { return [ - RPCRequest(method: String.random(), id: Int.random()), + RPCRequest(method: String.random(), id: Int64.random()), RPCRequest(method: String.random(), id: String.random()), - RPCRequest(method: String.random(), params: EmptyCodable(), id: Int.random()), + RPCRequest(method: String.random(), params: EmptyCodable(), id: Int64.random()), RPCRequest(method: String.random(), params: EmptyCodable(), id: String.random()), - RPCRequest(method: String.random(), params: [0, 1, 2], id: Int.random()), + RPCRequest(method: String.random(), params: [0, 1, 2], id: Int64.random()), RPCRequest(method: String.random(), params: ["0", "1", "2"], id: String.random()), - RPCRequest(method: String.random(), params: [AnyCodable(0), AnyCodable("0")], id: Int.random()), + RPCRequest(method: String.random(), params: [AnyCodable(0), AnyCodable("0")], id: Int64.random()), RPCRequest(method: String.random(), params: [AnyCodable(0), AnyCodable("0")], id: String.random()) ] } @@ -38,21 +38,21 @@ final class RPCRequestTests: XCTestCase { func testCheckedParamsInit() { XCTAssertNoThrow(try RPCRequest(method: "method", checkedParams: [0])) - XCTAssertNoThrow(try RPCRequest(method: "method", checkedParams: [0], id: Int.random())) + XCTAssertNoThrow(try RPCRequest(method: "method", checkedParams: [0], id: Int64.random())) XCTAssertNoThrow(try RPCRequest(method: "method", checkedParams: [0], id: String.random())) XCTAssertNoThrow(try RPCRequest(method: "method", checkedParams: EmptyCodable())) - XCTAssertNoThrow(try RPCRequest(method: "method", checkedParams: EmptyCodable(), id: Int.random())) + XCTAssertNoThrow(try RPCRequest(method: "method", checkedParams: EmptyCodable(), id: Int64.random())) XCTAssertNoThrow(try RPCRequest(method: "method", checkedParams: EmptyCodable(), id: String.random())) } func testCheckedParamsInitFailsWithPrimitives() { - XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: 0, id: Int.random())) + XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: 0, id: Int64.random())) XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: 0, id: String.random())) - XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: "string", id: Int.random())) + XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: "string", id: Int64.random())) XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: "string", id: String.random())) - XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: Double.pi, id: Int.random())) + XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: Double.pi, id: Int64.random())) XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: Double.pi, id: String.random())) - XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: true, id: Int.random())) + XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: true, id: Int64.random())) XCTAssertThrowsError(try RPCRequest(method: "method", checkedParams: true, id: String.random())) } From 6d4246d77c9cd86a1bc3d153b2d5c6c2aee25dd2 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Aug 2022 09:05:46 +0200 Subject: [PATCH 17/20] comment out periodically failing test --- .../PairingEngineTests.swift | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/Tests/WalletConnectSignTests/PairingEngineTests.swift b/Tests/WalletConnectSignTests/PairingEngineTests.swift index f31a6ab2c..486e7e8af 100644 --- a/Tests/WalletConnectSignTests/PairingEngineTests.swift +++ b/Tests/WalletConnectSignTests/PairingEngineTests.swift @@ -86,43 +86,43 @@ final class PairingEngineTests: XCTestCase { } // Flaky test: asserting `topicB` and `sessionTopic` failed once, couldn't reproduce - @MainActor - func testHandleSessionProposeResponse() async { - let uri = try! await engine.create() - let pairing = storageMock.getPairing(forTopic: uri.topic)! - let topicA = pairing.topic - let relayOptions = RelayProtocolOptions(protocol: "", data: nil) - - // Client proposes session - // FIXME: namespace stub - try! await engine.propose(pairingTopic: pairing.topic, namespaces: ProposalNamespace.stubDictionary(), relay: relayOptions) - - guard let request = networkingInteractor.requests.first?.request, - let proposal = networkingInteractor.requests.first?.request.sessionProposal else { - XCTFail("Proposer must publish session proposal request"); return - } - - // Client receives proposal response response - let responder = Participant.stub() - let proposalResponse = SessionType.ProposeResponse(relay: relayOptions, responderPublicKey: responder.publicKey) - - let jsonRpcResponse = JSONRPCResponse(id: request.id, result: AnyCodable.decoded(proposalResponse)) - let response = WCResponse(topic: topicA, - chainId: nil, - requestMethod: request.method, - requestParams: request.params, - result: .response(jsonRpcResponse)) - - networkingInteractor.responsePublisherSubject.send(response) - let privateKey = try! cryptoMock.getPrivateKey(for: proposal.proposer.publicKey)! - let topicB = deriveTopic(publicKey: responder.publicKey, privateKey: privateKey) - let storedPairing = storageMock.getPairing(forTopic: topicA)! - let sessionTopic = networkingInteractor.subscriptions.last! - - XCTAssertTrue(networkingInteractor.didCallSubscribe) - XCTAssert(storedPairing.active) - XCTAssertEqual(topicB, sessionTopic, "Responder engine calls back with session topic") - } +// @MainActor +// func testHandleSessionProposeResponse() async { +// let uri = try! await engine.create() +// let pairing = storageMock.getPairing(forTopic: uri.topic)! +// let topicA = pairing.topic +// let relayOptions = RelayProtocolOptions(protocol: "", data: nil) +// +// // Client proposes session +// // FIXME: namespace stub +// try! await engine.propose(pairingTopic: pairing.topic, namespaces: ProposalNamespace.stubDictionary(), relay: relayOptions) +// +// guard let request = networkingInteractor.requests.first?.request, +// let proposal = networkingInteractor.requests.first?.request.sessionProposal else { +// XCTFail("Proposer must publish session proposal request"); return +// } +// +// // Client receives proposal response response +// let responder = Participant.stub() +// let proposalResponse = SessionType.ProposeResponse(relay: relayOptions, responderPublicKey: responder.publicKey) +// +// let jsonRpcResponse = JSONRPCResponse(id: request.id, result: AnyCodable.decoded(proposalResponse)) +// let response = WCResponse(topic: topicA, +// chainId: nil, +// requestMethod: request.method, +// requestParams: request.params, +// result: .response(jsonRpcResponse)) +// +// networkingInteractor.responsePublisherSubject.send(response) +// let privateKey = try! cryptoMock.getPrivateKey(for: proposal.proposer.publicKey)! +// let topicB = deriveTopic(publicKey: responder.publicKey, privateKey: privateKey) +// let storedPairing = storageMock.getPairing(forTopic: topicA)! +// let sessionTopic = networkingInteractor.subscriptions.last! +// +// XCTAssertTrue(networkingInteractor.didCallSubscribe) +// XCTAssert(storedPairing.active) +// XCTAssertEqual(topicB, sessionTopic, "Responder engine calls back with session topic") +// } func testSessionProposeError() async { let uri = try! await engine.create() From a7d4d88ba0edc8d33ecc3b5cc3b033ffc62a9eab Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Aug 2022 09:08:11 +0200 Subject: [PATCH 18/20] comment out failing assertion --- .../PairingEngineTests.swift | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Tests/WalletConnectSignTests/PairingEngineTests.swift b/Tests/WalletConnectSignTests/PairingEngineTests.swift index 486e7e8af..b62bec7b1 100644 --- a/Tests/WalletConnectSignTests/PairingEngineTests.swift +++ b/Tests/WalletConnectSignTests/PairingEngineTests.swift @@ -86,43 +86,43 @@ final class PairingEngineTests: XCTestCase { } // Flaky test: asserting `topicB` and `sessionTopic` failed once, couldn't reproduce -// @MainActor -// func testHandleSessionProposeResponse() async { -// let uri = try! await engine.create() -// let pairing = storageMock.getPairing(forTopic: uri.topic)! -// let topicA = pairing.topic -// let relayOptions = RelayProtocolOptions(protocol: "", data: nil) -// -// // Client proposes session -// // FIXME: namespace stub -// try! await engine.propose(pairingTopic: pairing.topic, namespaces: ProposalNamespace.stubDictionary(), relay: relayOptions) -// -// guard let request = networkingInteractor.requests.first?.request, -// let proposal = networkingInteractor.requests.first?.request.sessionProposal else { -// XCTFail("Proposer must publish session proposal request"); return -// } -// -// // Client receives proposal response response -// let responder = Participant.stub() -// let proposalResponse = SessionType.ProposeResponse(relay: relayOptions, responderPublicKey: responder.publicKey) -// -// let jsonRpcResponse = JSONRPCResponse(id: request.id, result: AnyCodable.decoded(proposalResponse)) -// let response = WCResponse(topic: topicA, -// chainId: nil, -// requestMethod: request.method, -// requestParams: request.params, -// result: .response(jsonRpcResponse)) -// -// networkingInteractor.responsePublisherSubject.send(response) -// let privateKey = try! cryptoMock.getPrivateKey(for: proposal.proposer.publicKey)! -// let topicB = deriveTopic(publicKey: responder.publicKey, privateKey: privateKey) -// let storedPairing = storageMock.getPairing(forTopic: topicA)! -// let sessionTopic = networkingInteractor.subscriptions.last! -// -// XCTAssertTrue(networkingInteractor.didCallSubscribe) -// XCTAssert(storedPairing.active) + @MainActor + func testHandleSessionProposeResponse() async { + let uri = try! await engine.create() + let pairing = storageMock.getPairing(forTopic: uri.topic)! + let topicA = pairing.topic + let relayOptions = RelayProtocolOptions(protocol: "", data: nil) + + // Client proposes session + // FIXME: namespace stub + try! await engine.propose(pairingTopic: pairing.topic, namespaces: ProposalNamespace.stubDictionary(), relay: relayOptions) + + guard let request = networkingInteractor.requests.first?.request, + let proposal = networkingInteractor.requests.first?.request.sessionProposal else { + XCTFail("Proposer must publish session proposal request"); return + } + + // Client receives proposal response response + let responder = Participant.stub() + let proposalResponse = SessionType.ProposeResponse(relay: relayOptions, responderPublicKey: responder.publicKey) + + let jsonRpcResponse = JSONRPCResponse(id: request.id, result: AnyCodable.decoded(proposalResponse)) + let response = WCResponse(topic: topicA, + chainId: nil, + requestMethod: request.method, + requestParams: request.params, + result: .response(jsonRpcResponse)) + + networkingInteractor.responsePublisherSubject.send(response) + let privateKey = try! cryptoMock.getPrivateKey(for: proposal.proposer.publicKey)! + let topicB = deriveTopic(publicKey: responder.publicKey, privateKey: privateKey) + let storedPairing = storageMock.getPairing(forTopic: topicA)! + let sessionTopic = networkingInteractor.subscriptions.last! + + XCTAssertTrue(networkingInteractor.didCallSubscribe) + XCTAssert(storedPairing.active) // XCTAssertEqual(topicB, sessionTopic, "Responder engine calls back with session topic") -// } + } func testSessionProposeError() async { let uri = try! await engine.create() From 410e0aba9278116d2583bcfd2f8e2e8dd3dfe8a9 Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Mon, 8 Aug 2022 10:52:45 +0300 Subject: [PATCH 19/20] Priority high --- Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift | 2 +- .../Mocks/NetworkingInteractorMock.swift | 2 +- Tests/WalletConnectSignTests/PairingEngineTests.swift | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift index 1211c63f5..84d871f48 100644 --- a/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift +++ b/Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift @@ -207,7 +207,7 @@ private extension ApproveEngine { ) settlingProposal = proposal - Task(priority: .background) { + Task(priority: .high) { try? await networkingInteractor.subscribe(topic: sessionTopic) } } catch { diff --git a/Tests/WalletConnectSignTests/Mocks/NetworkingInteractorMock.swift b/Tests/WalletConnectSignTests/Mocks/NetworkingInteractorMock.swift index 49d220625..a76d6ef91 100644 --- a/Tests/WalletConnectSignTests/Mocks/NetworkingInteractorMock.swift +++ b/Tests/WalletConnectSignTests/Mocks/NetworkingInteractorMock.swift @@ -76,8 +76,8 @@ class NetworkingInteractorMock: NetworkInteracting { } func subscribe(topic: String) { - didCallSubscribe = true subscriptions.append(topic) + didCallSubscribe = true } func unsubscribe(topic: String) { diff --git a/Tests/WalletConnectSignTests/PairingEngineTests.swift b/Tests/WalletConnectSignTests/PairingEngineTests.swift index b62bec7b1..785be6dc2 100644 --- a/Tests/WalletConnectSignTests/PairingEngineTests.swift +++ b/Tests/WalletConnectSignTests/PairingEngineTests.swift @@ -85,8 +85,6 @@ final class PairingEngineTests: XCTestCase { XCTAssertEqual(publishTopic, topicA) } - // Flaky test: asserting `topicB` and `sessionTopic` failed once, couldn't reproduce - @MainActor func testHandleSessionProposeResponse() async { let uri = try! await engine.create() let pairing = storageMock.getPairing(forTopic: uri.topic)! @@ -121,7 +119,7 @@ final class PairingEngineTests: XCTestCase { XCTAssertTrue(networkingInteractor.didCallSubscribe) XCTAssert(storedPairing.active) -// XCTAssertEqual(topicB, sessionTopic, "Responder engine calls back with session topic") + XCTAssertEqual(topicB, sessionTopic, "Responder engine calls back with session topic") } func testSessionProposeError() async { From 6838dcf5431d6a736e36430bfb12a6796347601d Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 8 Aug 2022 14:07:10 +0200 Subject: [PATCH 20/20] update user-agent --- Sources/WalletConnectRelay/EnvironmentInfo.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/WalletConnectRelay/EnvironmentInfo.swift b/Sources/WalletConnectRelay/EnvironmentInfo.swift index f726b7578..1348a621d 100644 --- a/Sources/WalletConnectRelay/EnvironmentInfo.swift +++ b/Sources/WalletConnectRelay/EnvironmentInfo.swift @@ -18,7 +18,7 @@ enum EnvironmentInfo { } static var sdkVersion: String { - "v0.9.2-rc.0" + "v0.9.3-rc.0" } static var operatingSystem: String {