Skip to content

Commit

Permalink
Merge pull request #1016 from WalletConnect/verify-echo-fallback-to-org
Browse files Browse the repository at this point in the history
[Verify, Echo] Fallback to .org
  • Loading branch information
alexander-lsvk authored Aug 16, 2023
2 parents d571b04 + 3b1ad3f commit 37dc259
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 34 deletions.
1 change: 1 addition & 0 deletions Sources/HTTPClient/HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import Foundation
public protocol HTTPClient {
func request<T: Decodable>(_ type: T.Type, at service: HTTPService) async throws -> T
func request(service: HTTPService) async throws
func updateHost(host: String) async
}
19 changes: 18 additions & 1 deletion Sources/HTTPClient/HTTPError.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import Foundation

enum HTTPError: Error {
public enum HTTPError: Error, Equatable {
case malformedURL(HTTPService)
case couldNotConnect
case dataTaskError(Error)
case noResponse
case badStatusCode(Int)
case responseDataNil
case jsonDecodeFailed(Error, Data)

public static func ==(lhs: HTTPError, rhs: HTTPError) -> Bool {
switch (lhs, rhs) {
case (.malformedURL, .malformedURL),
(.couldNotConnect, .couldNotConnect),
(.noResponse, .noResponse),
(.responseDataNil, .responseDataNil),
(.dataTaskError, .dataTaskError),
(.badStatusCode, .badStatusCode),
(.jsonDecodeFailed, .jsonDecodeFailed):
return true

default:
return false
}
}
}
9 changes: 8 additions & 1 deletion Sources/HTTPClient/HTTPNetworkClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation

public actor HTTPNetworkClient: HTTPClient {

let host: String
private var host: String

private let session: URLSession

Expand Down Expand Up @@ -31,6 +31,10 @@ public actor HTTPNetworkClient: HTTPClient {
}
}
}

public func updateHost(host: String) async {
self.host = host
}

private func request<T: Decodable>(_ type: T.Type, at service: HTTPService, completion: @escaping (Result<T, Error>) -> Void) {
guard let request = service.resolve(for: host) else {
Expand Down Expand Up @@ -67,6 +71,9 @@ public actor HTTPNetworkClient: HTTPClient {
}

private static func validate(_ urlResponse: URLResponse?, _ error: Error?) throws {
if let error = (error as? NSError), error.code == -1004 {
throw HTTPError.couldNotConnect
}
if let error = error {
throw HTTPError.dataTaskError(error)
}
Expand Down
19 changes: 12 additions & 7 deletions Sources/WalletConnectEcho/EchoClientFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@ public struct EchoClientFactory {
environment: environment)
}

public static func create(projectId: String,
echoHost: String,
keychainStorage: KeychainStorageProtocol,
environment: APNSEnvironment) -> EchoClient {

public static func create(
projectId: String,
echoHost: String,
keychainStorage: KeychainStorageProtocol,
environment: APNSEnvironment
) -> EchoClient {
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.timeoutIntervalForRequest = 5.0
sessionConfiguration.timeoutIntervalForResource = 5.0
let session = URLSession(configuration: sessionConfiguration)

let logger = ConsoleLogger(suffix: "👂🏻", loggingLevel: .debug)

let httpClient = HTTPNetworkClient(host: echoHost)
let httpClient = HTTPNetworkClient(host: echoHost, session: session)

let clientIdStorage = ClientIdStorage(keychain: keychainStorage)

Expand Down
57 changes: 42 additions & 15 deletions Sources/WalletConnectEcho/Register/EchoRegisterService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ actor EchoRegisterService {
private let environment: APNSEnvironment
private let echoAuthenticator: EchoAuthenticating
private let clientIdStorage: ClientIdStoring

/// The property is used to determine whether echo.walletconnect.org will be used
/// in case echo.walletconnect.com doesn't respond for some reason (most likely due to being blocked in the user's location).
private var fallback = false

enum Errors: Error {
case registrationFailed
}
Expand All @@ -33,29 +36,53 @@ actor EchoRegisterService {
let clientId = try clientIdStorage.getClientId()
let clientIdMutlibase = try DIDKey(did: clientId).multibase(variant: .ED25519)
logger.debug("APNS device token: \(token)")
let response = try await httpClient.request(
EchoResponse.self,
at: EchoAPI.register(clientId: clientIdMutlibase, token: token, projectId: projectId, environment: environment, auth: echoAuthToken)
)
guard response.status == .success else {
throw Errors.registrationFailed

do {
let response = try await httpClient.request(
EchoResponse.self,
at: EchoAPI.register(clientId: clientIdMutlibase, token: token, projectId: projectId, environment: environment, auth: echoAuthToken)
)
guard response.status == .success else {
throw Errors.registrationFailed
}
logger.debug("Successfully registered at Echo Server")
} catch {
if (error as? HTTPError) == .couldNotConnect && !fallback {
fallback = true
await echoHostFallback()
try await register(deviceToken: deviceToken)
}
throw error
}
logger.debug("Successfully registered at Echo Server")
}

func echoHostFallback() async {
await httpClient.updateHost(host: "echo.walletconnect.org")
}

#if DEBUG
public func register(deviceToken: String) async throws {
let echoAuthToken = try echoAuthenticator.createAuthToken()
let clientId = try clientIdStorage.getClientId()
let clientIdMutlibase = try DIDKey(did: clientId).multibase(variant: .ED25519)
let response = try await httpClient.request(
EchoResponse.self,
at: EchoAPI.register(clientId: clientIdMutlibase, token: deviceToken, projectId: projectId, environment: environment, auth: echoAuthToken)
)
guard response.status == .success else {
throw Errors.registrationFailed

do {
let response = try await httpClient.request(
EchoResponse.self,
at: EchoAPI.register(clientId: clientIdMutlibase, token: deviceToken, projectId: projectId, environment: environment, auth: echoAuthToken)
)
guard response.status == .success else {
throw Errors.registrationFailed
}
logger.debug("Successfully registered at Echo Server")
} catch {
if (error as? HTTPError) == .couldNotConnect && !fallback {
fallback = true
await echoHostFallback()
try await register(deviceToken: deviceToken)
}
throw error
}
logger.debug("Successfully registered at Echo Server")
}
#endif
}
Expand Down
40 changes: 31 additions & 9 deletions Sources/WalletConnectVerify/OriginVerifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,44 @@ public final class OriginVerifier {
case registrationFailed
}

private let verifyHost: String
private var verifyHost: String
/// The property is used to determine whether verify.walletconnect.org will be used
/// in case verify.walletconnect.com doesn't respond for some reason (most likely due to being blocked in the user's location).
private var fallback = false

init(verifyHost: String) {
self.verifyHost = verifyHost
}

func verifyOrigin(assertionId: String) async throws -> String {
let httpClient = HTTPNetworkClient(host: verifyHost)
let response = try await httpClient.request(
VerifyResponse.self,
at: VerifyAPI.resolve(assertionId: assertionId)
)
guard let origin = response.origin else {
throw Errors.registrationFailed
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.timeoutIntervalForRequest = 5.0
sessionConfiguration.timeoutIntervalForResource = 5.0
let session = URLSession(configuration: sessionConfiguration)

let httpClient = HTTPNetworkClient(host: verifyHost, session: session)

do {
let response = try await httpClient.request(
VerifyResponse.self,
at: VerifyAPI.resolve(assertionId: assertionId)
)
guard let origin = response.origin else {
throw Errors.registrationFailed
}
return origin
} catch {
if (error as? HTTPError) == .couldNotConnect && !fallback {
fallback = true
verifyHostFallback()
return try await verifyOrigin(assertionId: assertionId)
}
throw error
}
return origin
}

func verifyHostFallback() {
verifyHost = "verify.walletconnect.org"
}
}

5 changes: 4 additions & 1 deletion Tests/TestingUtils/Mocks/HTTPClientMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Foundation
@testable import HTTPClient

public final class HTTPClientMock<T: Decodable>: HTTPClient {

private let object: T

public init(object: T) {
Expand All @@ -16,4 +15,8 @@ public final class HTTPClientMock<T: Decodable>: HTTPClient {
public func request(service: HTTPService) async throws {

}

public func updateHost(host: String) async {

}
}

0 comments on commit 37dc259

Please sign in to comment.