diff --git a/Example/IntegrationTests/Auth/AuthTests.swift b/Example/IntegrationTests/Auth/AuthTests.swift index 20337b451..8e343268f 100644 --- a/Example/IntegrationTests/Auth/AuthTests.swift +++ b/Example/IntegrationTests/Auth/AuthTests.swift @@ -67,7 +67,7 @@ final class AuthTests: XCTestCase { try! await wallet.pair(uri: uri) wallet.authRequestPublisher.sink { [unowned self] (id, message) in Task(priority: .high) { - let signature = try! MessageSigner(signer: Signer()).sign(message: message, privateKey: prvKey) + let signature = try! MessageSigner().sign(message: message, privateKey: prvKey) let cacaoSignature = CacaoSignature(t: "eip191", s: signature) try! await wallet.respond(requestId: id, result: .success(cacaoSignature)) } @@ -80,4 +80,25 @@ final class AuthTests: XCTestCase { .store(in: &publishers) wait(for: [responseExpectation], timeout: 5) } + + func testRespondSignatureVerificationFailed() async { + let responseExpectation = expectation(description: "invalid signature response delivered") + let uri = try! await app.request(RequestParams.stub()) + try! await wallet.pair(uri: uri) + wallet.authRequestPublisher.sink { [unowned self] (id, message) in + Task(priority: .high) { + let invalidSignature = "438effc459956b57fcd9f3dac6c675f9cee88abf21acab7305e8e32aa0303a883b06dcbd956279a7a2ca21ffa882ff55cc22e8ab8ec0f3fe90ab45f306938cfa1b" + let cacaoSignature = CacaoSignature(t: "eip191", s: invalidSignature) + try! await wallet.respond(requestId: id, result: .success(cacaoSignature)) + } + } + .store(in: &publishers) + app.authResponsePublisher.sink { (id, result) in + guard case .failure(let error) = result else { XCTFail(); return } + XCTAssertEqual(error, .signatureVerificationFailed) + responseExpectation.fulfill() + } + .store(in: &publishers) + wait(for: [responseExpectation], timeout: 2) + } } diff --git a/Sources/Auth/Services/App/AppRespondSubscriber.swift b/Sources/Auth/Services/App/AppRespondSubscriber.swift index d013d8fb4..bc7e13c72 100644 --- a/Sources/Auth/Services/App/AppRespondSubscriber.swift +++ b/Sources/Auth/Services/App/AppRespondSubscriber.swift @@ -49,7 +49,7 @@ class AppRespondSubscriber { else { self.onResponse?(requestId, .failure(.messageCompromised)); return } guard let _ = try? signatureVerifier.verify(signature: cacao.signature.s, message: message, address: address) - else { self.onResponse?(requestId, .failure(.messageVerificationFailed)); return } + else { self.onResponse?(requestId, .failure(.signatureVerificationFailed)); return } onResponse?(requestId, .success(cacao)) diff --git a/Sources/Auth/Services/Signer/MessageSigner.swift b/Sources/Auth/Services/Signer/MessageSigner.swift index b9b8dda11..d07972a5c 100644 --- a/Sources/Auth/Services/Signer/MessageSigner.swift +++ b/Sources/Auth/Services/Signer/MessageSigner.swift @@ -8,7 +8,7 @@ protocol MessageSigning { func sign(message: String, privateKey: Data) throws -> String } -struct MessageSigner: MessageSignatureVerifying, MessageSigning { +public struct MessageSigner: MessageSignatureVerifying, MessageSigning { enum Errors: Error { case signatureValidationFailed @@ -17,17 +17,17 @@ struct MessageSigner: MessageSignatureVerifying, MessageSigning { private let signer: Signer - init(signer: Signer) { + public init(signer: Signer = Signer()) { self.signer = signer } - func sign(message: String, privateKey: Data) throws -> String { + public func sign(message: String, privateKey: Data) throws -> String { guard let messageData = message.data(using: .utf8) else { throw Errors.utf8EncodingFailed } let signature = try signer.sign(message: messageData, with: privateKey) return signature.toHexString() } - func verify(signature: String, message: String, address: String) throws { + public func verify(signature: String, message: String, address: String) throws { guard let messageData = message.data(using: .utf8) else { throw Errors.utf8EncodingFailed } let signatureData = Data(hex: signature) guard try signer.isValid(signature: signatureData, message: messageData, address: address) diff --git a/Sources/Auth/Services/Signer/Signer.swift b/Sources/Auth/Services/Signer/Signer.swift index a1ba7a6e6..3d5903296 100644 --- a/Sources/Auth/Services/Signer/Signer.swift +++ b/Sources/Auth/Services/Signer/Signer.swift @@ -1,10 +1,12 @@ import Foundation import Web3 -struct Signer { +public struct Signer { typealias Signature = (v: UInt, r: [UInt8], s: [UInt8]) + public init() {} + func sign(message: Data, with key: Data) throws -> Data { let prefixed = prefixed(message: message) let privateKey = try EthereumPrivateKey(privateKey: key.bytes) diff --git a/Sources/Auth/Types/Cacao/CacaoSignature.swift b/Sources/Auth/Types/Cacao/CacaoSignature.swift index 69784b55e..b34ee1a40 100644 --- a/Sources/Auth/Types/Cacao/CacaoSignature.swift +++ b/Sources/Auth/Types/Cacao/CacaoSignature.swift @@ -1,7 +1,13 @@ import Foundation public struct CacaoSignature: Codable, Equatable { - public let t: String - public let s: String - public let m: String? = nil + let t: String + let s: String + let m: String? + + public init(t: String, s: String, m: String? = nil) { + self.t = t + self.s = s + self.m = m + } } diff --git a/Sources/Auth/Types/Errors/AuthError.swift b/Sources/Auth/Types/Errors/AuthError.swift index 05e7ed2d2..2b83d6182 100644 --- a/Sources/Auth/Types/Errors/AuthError.swift +++ b/Sources/Auth/Types/Errors/AuthError.swift @@ -5,7 +5,7 @@ public enum AuthError: Codable, Equatable, Error { case malformedResponseParams case malformedRequestParams case messageCompromised - case messageVerificationFailed + case signatureVerificationFailed } extension AuthError: Reason { @@ -20,7 +20,7 @@ extension AuthError: Reason { return 12002 case .messageCompromised: return 12003 - case .messageVerificationFailed: + case .signatureVerificationFailed: return 12004 } } @@ -35,7 +35,7 @@ extension AuthError: Reason { return "Request params malformed" case .messageCompromised: return "Original message compromised" - case .messageVerificationFailed: + case .signatureVerificationFailed: return "Message verification failed" } } diff --git a/Sources/Auth/Types/RespondParams.swift b/Sources/Auth/Types/RespondParams.swift index 79926445e..f7c4a4af8 100644 --- a/Sources/Auth/Types/RespondParams.swift +++ b/Sources/Auth/Types/RespondParams.swift @@ -1,6 +1,11 @@ import Foundation -public struct RespondParams { +public struct RespondParams: Equatable { let id: RPCID let signature: CacaoSignature + + public init(id: RPCID, signature: CacaoSignature) { + self.id = id + self.signature = signature + } }