Skip to content

Commit

Permalink
Merge pull request #1392 from WalletConnect/verify-v2
Browse files Browse the repository at this point in the history
Verify v2
  • Loading branch information
llbartekll authored Aug 13, 2024
2 parents 6d31244 + ee030b5 commit 8823b78
Show file tree
Hide file tree
Showing 44 changed files with 669 additions and 168 deletions.
42 changes: 12 additions & 30 deletions Example/ExampleApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2783,11 +2783,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_ENTITLEMENTS = DApp/DApp.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 173;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22;
DEVELOPMENT_TEAM = W5R8AG9K22;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = DApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = dApp;
Expand All @@ -2807,7 +2805,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.dapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.dapp";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand All @@ -2822,11 +2819,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_ENTITLEMENTS = DApp/DAppRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 173;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22;
DEVELOPMENT_TEAM = W5R8AG9K22;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = DApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = dApp;
Expand All @@ -2846,7 +2841,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.dapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.dapp";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand All @@ -2859,11 +2853,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = PNDecryptionService/PNDecryptionService.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 173;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22;
DEVELOPMENT_TEAM = W5R8AG9K22;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = PNDecryptionService/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = PNDecryptionService;
Expand All @@ -2878,7 +2870,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.walletapp.PNDecryptionService;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.walletapp.PNDecryptionService";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
Expand All @@ -2892,11 +2883,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = PNDecryptionService/PNDecryptionServiceRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 173;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22;
DEVELOPMENT_TEAM = W5R8AG9K22;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = PNDecryptionService/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = PNDecryptionService;
Expand All @@ -2911,7 +2900,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.walletapp.PNDecryptionService;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.walletapp.PNDecryptionService";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -3075,11 +3063,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = WalletApp/WalletApp.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 173;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22;
DEVELOPMENT_TEAM = W5R8AG9K22;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WalletApp/Other/Info.plist;
Expand All @@ -3098,7 +3084,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.walletapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.walletapp";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand All @@ -3114,11 +3099,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = WalletApp/WalletAppRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 173;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22;
DEVELOPMENT_TEAM = W5R8AG9K22;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WalletApp/Other/Info.plist;
Expand All @@ -3137,7 +3120,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.walletapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.walletapp";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down
4 changes: 2 additions & 2 deletions Example/RelayIntegrationTests/RelayClientEndToEndTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,12 @@ final class RelayClientEndToEndTests: XCTestCase {
expectationA.assertForOverFulfill = false
expectationB.assertForOverFulfill = false

relayA.messagePublisher.sink { topic, payload, _ in
relayA.messagePublisher.sink { topic, payload, _, _ in
(subscriptionATopic, subscriptionAPayload) = (topic, payload)
expectationA.fulfill()
}.store(in: &publishers)

relayB.messagePublisher.sink { topic, payload, _ in
relayB.messagePublisher.sink { topic, payload, _, _ in
(subscriptionBTopic, subscriptionBPayload) = (topic, payload)
Task(priority: .high) {
sleep(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ final class AuthRequestPresenter: ObservableObject {

/* Redirect */
if let uri = request.requester.redirect?.native {
// WalletConnectRouter.goBack(uri: uri)
WalletConnectRouter.goBack(uri: uri)
router.dismiss()
} else {
showSignedSheet.toggle()
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ let package = Package(
path: "Sources/WalletConnectRouter/Router"),
.target(
name: "WalletConnectVerify",
dependencies: ["WalletConnectUtils", "WalletConnectNetworking"],
dependencies: ["WalletConnectUtils", "WalletConnectNetworking", "WalletConnectJWT"],
resources: [.process("Resources/PrivacyInfo.xcprivacy")]),
.target(
name: "Database",
Expand Down
6 changes: 3 additions & 3 deletions Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ class WalletRequestSubscriber {
Task(priority: .high) {
let assertionId = payload.decryptedPayload.sha256().toHexString()
do {
let response = try await verifyClient.verifyOrigin(assertionId: assertionId)
let verifyContext = verifyClient.createVerifyContext(origin: response.origin, domain: payload.request.payloadParams.domain, isScam: response.isScam)
let response = try await verifyClient.verify(.v1(assertionId: assertionId))
let verifyContext = verifyClient.createVerifyContext(origin: response.origin, domain: payload.request.payloadParams.domain, isScam: response.isScam, isVerified: nil)
verifyContextStore.set(verifyContext, forKey: request.id.string)
onRequest?((request, verifyContext))
} catch {
let verifyContext = verifyClient.createVerifyContext(origin: nil, domain: payload.request.payloadParams.domain, isScam: nil)
let verifyContext = verifyClient.createVerifyContext(origin: nil, domain: payload.request.payloadParams.domain, isScam: nil, isVerified: nil)
verifyContextStore.set(verifyContext, forKey: request.id.string)
onRequest?((request, verifyContext))
return
Expand Down
40 changes: 37 additions & 3 deletions Sources/WalletConnectJWT/JWTValidator.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import Foundation
import CryptoKit

struct JWTValidator {
public struct JWTValidator {

let jwtString: String
private let jwtString: String

func isValid(publicKey: SigningPublicKey) throws -> Bool {
public init(jwtString: String) {
self.jwtString = jwtString
}

public func isValid(publicKey: SigningPublicKey) throws -> Bool {
var components = jwtString.components(separatedBy: ".")

guard components.count == 3 else { throw JWTError.undefinedFormat }
Expand All @@ -20,3 +25,32 @@ struct JWTValidator {
return publicKey.isValid(signature: signatureData, for: unsignedData)
}
}


public struct P256JWTValidator {

private let jwtString: String

public init(jwtString: String) {
self.jwtString = jwtString
}

public func isValid(publicKey: P256.Signing.PublicKey) throws -> Bool {
var components = jwtString.components(separatedBy: ".")

guard components.count == 3 else { throw JWTError.undefinedFormat }

let signature = components.removeLast()

guard let unsignedData = components
.joined(separator: ".")
.data(using: .utf8)
else { throw JWTError.invalidJWTString }

let signatureData = try JWTEncoder.base64urlDecodedData(string: signature)

let P256Signature = try P256.Signing.ECDSASignature(rawRepresentation: signatureData)

return publicKey.isValidSignature(P256Signature, for: unsignedData)
}
}
2 changes: 1 addition & 1 deletion Sources/WalletConnectNetworking/NetworkInteracting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public protocol NetworkInteracting {
var isSocketConnected: Bool { get }
var socketConnectionStatusPublisher: AnyPublisher<SocketConnectionStatus, Never> { get }
var networkConnectionStatusPublisher: AnyPublisher<NetworkConnectionStatus, Never> { get }
var requestPublisher: AnyPublisher<(topic: String, request: RPCRequest, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?), Never> { get }
var requestPublisher: AnyPublisher<(topic: String, request: RPCRequest, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?, encryptedMessage: String, attestation: String?), Never> { get }
func subscribe(topic: String) async throws
func unsubscribe(topic: String)
func batchSubscribe(topics: [String]) async throws
Expand Down
34 changes: 22 additions & 12 deletions Sources/WalletConnectNetworking/NetworkingInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ public class NetworkingInteractor: NetworkInteracting {
private let rpcHistory: RPCHistory
private let logger: ConsoleLogging

private let requestPublisherSubject = PassthroughSubject<(topic: String, request: RPCRequest, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?), Never>()
private let requestPublisherSubject = PassthroughSubject<(topic: String, request: RPCRequest, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?, encryptedMessage: String, attestation: String?), Never>()
private let responsePublisherSubject = PassthroughSubject<(topic: String, request: RPCRequest, response: RPCResponse, publishedAt: Date, derivedTopic: String?), Never>()

public var requestPublisher: AnyPublisher<(topic: String, request: RPCRequest, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?), Never> {
public var requestPublisher: AnyPublisher<(topic: String, request: RPCRequest, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?, encryptedMessage: String, attestation: String?), Never> {
requestPublisherSubject.eraseToAnyPublisher()
}

Expand Down Expand Up @@ -51,8 +51,8 @@ public class NetworkingInteractor: NetworkInteracting {

private func setupRelaySubscribtion() {
relayClient.messagePublisher
.sink { [unowned self] (topic, message, publishedAt) in
manageSubscription(topic, message, publishedAt)
.sink { [unowned self] (topic, message, publishedAt, attestation) in
manageSubscription(topic, message, publishedAt, attestation)
}.store(in: &publishers)
}

Expand Down Expand Up @@ -123,19 +123,29 @@ public class NetworkingInteractor: NetworkInteracting {
}.store(in: &publishers)
}


public func requestSubscription<RequestParams: Codable>(on request: ProtocolMethod) -> AnyPublisher<RequestSubscriptionPayload<RequestParams>, Never> {
return requestPublisher
.filter { rpcRequest in
return rpcRequest.request.method == request.method
}
.compactMap { [weak self] topic, rpcRequest, decryptedPayload, publishedAt, derivedTopic in
.compactMap { [weak self] topic, rpcRequest, decryptedPayload, publishedAt, derivedTopic, encryptedMessage, attestation in
do {
guard let id = rpcRequest.id, let request = try rpcRequest.params?.get(RequestParams.self) else { return nil }
return RequestSubscriptionPayload(id: id, topic: topic, request: request, decryptedPayload: decryptedPayload, publishedAt: publishedAt, derivedTopic: derivedTopic)
return RequestSubscriptionPayload(
id: id,
topic: topic,
request: request,
decryptedPayload: decryptedPayload,
publishedAt: publishedAt,
derivedTopic: derivedTopic,
encryptedMessage: encryptedMessage,
attestation: attestation
)
} catch {
self?.logger.debug("Networking Interactor - \(error)")
return nil
}
return nil
}
.eraseToAnyPublisher()
}
Expand Down Expand Up @@ -245,11 +255,11 @@ public class NetworkingInteractor: NetworkInteracting {
try await respond(topic: topic, response: response, protocolMethod: protocolMethod, envelopeType: envelopeType)
}

private func manageSubscription(_ topic: String, _ encodedEnvelope: String, _ publishedAt: Date) {
private func manageSubscription(_ topic: String, _ encodedEnvelope: String, _ publishedAt: Date, _ attestation: String?) {
if let result = serializer.tryDeserializeRequestOrResponse(topic: topic, codingType: .base64Encoded, envelopeString: encodedEnvelope) {
switch result {
case .left(let result):
handleRequest(topic: topic, request: result.request, decryptedPayload: result.decryptedPayload, publishedAt: publishedAt, derivedTopic: result.derivedTopic)
handleRequest(topic: topic, request: result.request, decryptedPayload: result.decryptedPayload, publishedAt: publishedAt, derivedTopic: result.derivedTopic, encryptedMessage: encodedEnvelope, attestation: attestation)
case .right(let result):
handleResponse(topic: topic, response: result.response, publishedAt: publishedAt, derivedTopic: result.derivedTopic)
}
Expand All @@ -259,13 +269,13 @@ public class NetworkingInteractor: NetworkInteracting {
}

public func handleHistoryRequest(topic: String, request: RPCRequest) {
requestPublisherSubject.send((topic, request, Data(), Date(), nil))
requestPublisherSubject.send((topic, request, Data(), Date(), nil, "", nil ))
}

private func handleRequest(topic: String, request: RPCRequest, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?) {
private func handleRequest(topic: String, request: RPCRequest, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?, encryptedMessage: String, attestation: String?) {
do {
try rpcHistory.set(request, forTopic: topic, emmitedBy: .remote, transportType: .relay)
requestPublisherSubject.send((topic, request, decryptedPayload, publishedAt, derivedTopic))
requestPublisherSubject.send((topic, request, decryptedPayload, publishedAt, derivedTopic, encryptedMessage, attestation))
} catch {
logger.debug(error)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@ import Foundation

public struct RequestSubscriptionPayload<Request: Codable>: Codable, SubscriptionPayload {
public let id: RPCID
public let encryptedMessage: String
public let attestation: String?
public let topic: String
public let request: Request
public let decryptedPayload: Data
public let publishedAt: Date
public let derivedTopic: String?

public init(id: RPCID, topic: String, request: Request, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?) {
public init(id: RPCID, topic: String, request: Request, decryptedPayload: Data, publishedAt: Date, derivedTopic: String?, encryptedMessage: String, attestation: String?) {
self.id = id
self.topic = topic
self.request = request
self.decryptedPayload = decryptedPayload
self.publishedAt = publishedAt
self.derivedTopic = derivedTopic
self.encryptedMessage = encryptedMessage
self.attestation = attestation
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class PairingRequestsSubscriber {
.filter { [unowned self] in !pairingProtocolMethods.contains($0.request.method)}
.filter { [unowned self] in pairingStorage.hasPairing(forTopic: $0.topic)}
.filter { [unowned self] in !registeredProtocolMethods.contains($0.request.method)}
.sink { [unowned self] topic, request, _, _, _ in
.sink { [unowned self] topic, request, _, _, _, _, _ in
Task(priority: .high) {
let protocolMethod = UnsupportedProtocolMethod(method: request.method)
logger.debug("PairingRequestsSubscriber: responding unregistered request method")
Expand Down
Loading

0 comments on commit 8823b78

Please sign in to comment.