Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Auth] #377 Auth respond service #401

Merged
merged 4 commits into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Example/IntegrationTests/Chat/ChatTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ final class ChatTests: XCTestCase {
override func setUp() {
registry = KeyValueRegistry()
invitee = makeClient(prefix: "🦖 Registered")
inviter = makeClient(prefix: "🍄 Inviter")
inviter = makeClient(prefix: "🍄 Inviter")

waitClientsConnected()
}
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let package = Package(
targets: ["Chat"]),
.library(
name: "WalletConnectPairing",
targets: ["WalletConnectPairing"]),
targets: ["WalletConnectPairing"])
],
dependencies: [],
targets: [
Expand Down
3 changes: 1 addition & 2 deletions Sources/Auth/Services/App/AuthRequestService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ actor AuthRequestService {
let payload = AuthPayload(requestParams: params, iat: issueAt)
let params = AuthRequestParams(requester: requester, payloadParams: payload)
let request = RPCRequest(method: "wc_authRequest", params: params)
try await networkingInteractor.request(request, topic: topic)
try await networkingInteractor.request(request, topic: topic, tag: AuthRequestParams.tag)
try await networkingInteractor.subscribe(topic: responseTopic)
}
}

11 changes: 11 additions & 0 deletions Sources/Auth/Services/Common/CacaoFormatter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Foundation

protocol CacaoFormatting {
func format(_ request: AuthRequestParams, _ signature: CacaoSignature, _ issuer: Account) -> Cacao
}

class CacaoFormatter: CacaoFormatting {
func format(_ request: AuthRequestParams, _ signature: CacaoSignature, _ issuer: Account) -> Cacao {
fatalError("not implemented")
}
}
18 changes: 12 additions & 6 deletions Sources/Auth/Services/Common/NetworkingInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import JSONRPC
protocol NetworkInteracting {
var requestPublisher: AnyPublisher<RequestSubscriptionPayload, Never> {get}
func subscribe(topic: String) async throws
func request(_ request: RPCRequest, topic: String, envelopeType: Envelope.EnvelopeType) 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
}

extension NetworkInteracting {
func request(_ request: RPCRequest, topic: String, envelopeType: Envelope.EnvelopeType = .type0) async throws {
try await self.request(request, topic: topic, envelopeType: envelopeType)
func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType = .type0) async throws {
try await self.request(request, topic: topic, tag: tag, envelopeType: envelopeType)
}
}


class NetworkingInteractor: NetworkInteracting {
private let relayClient: RelayClient
private let serializer: Serializing
Expand All @@ -39,9 +39,15 @@ class NetworkingInteractor: NetworkInteracting {
try await relayClient.subscribe(topic: topic)
}

func request(_ request: RPCRequest, topic: String, envelopeType: Envelope.EnvelopeType) async throws {
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)
try await relayClient.publish(topic: topic, payload: message, tag: AuthRequestParams.tag)
try await relayClient.publish(topic: topic, payload: message, tag: tag)
}

func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws {
try rpcHistory.resolve(response)
let message = try! serializer.serialize(topic: topic, encodable: response, envelopeType: envelopeType)
try await relayClient.publish(topic: topic, payload: message, tag: tag)
}
}
7 changes: 4 additions & 3 deletions Sources/Auth/Services/Wallet/AuthRequestSubscriber.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class AuthRequestSubscriber {
private let logger: ConsoleLogging
private var publishers = [AnyCancellable]()
private let messageFormatter: SIWEMessageFormatting
var onRequest: ((_ id: Int64, _ message: String)->())?
var onRequest: ((_ id: Int64, _ message: String)->Void)?

init(networkingInteractor: NetworkInteracting,
logger: ConsoleLogging,
Expand All @@ -21,17 +21,18 @@ class AuthRequestSubscriber {
private func subscribeForRequest() {
networkingInteractor.requestPublisher.sink { [unowned self] subscriptionPayload in
guard subscriptionPayload.request.method == "wc_authRequest" else { return }
guard let authRequest = try? subscriptionPayload.request.params?.get(AuthRequestParams.self) else {
guard let authRequestParams = try? subscriptionPayload.request.params?.get(AuthRequestParams.self) else {
logger.debug("Malformed auth request params")
return
}
do {
let message = try messageFormatter.formatMessage(from: authRequest)
let message = try messageFormatter.formatMessage(from: authRequestParams)
guard let requestId = subscriptionPayload.request.id?.right else { return }
onRequest?(requestId, message)
} catch {
logger.debug(error)
}
}.store(in: &publishers)
}

}
32 changes: 30 additions & 2 deletions Sources/Auth/Services/Wallet/AuthRespondService.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,41 @@
import Foundation
import WalletConnectKMS
import JSONRPC
import WalletConnectUtils

actor AuthRespondService {
enum Errors: Error {
case recordForIdNotFound
case malformedAuthRequestParams
}
private let networkingInteractor: NetworkInteracting
private let kms: KeyManagementService
private let rpcHistory: RPCHistory
private let logger: ConsoleLogging

init(networkingInteractor: NetworkInteracting) {
init(networkingInteractor: NetworkInteracting,
logger: ConsoleLogging,
kms: KeyManagementService,
rpcHistory: RPCHistory) {
self.networkingInteractor = networkingInteractor
self.logger = logger
self.kms = kms
self.rpcHistory = rpcHistory
}

func respond(respondParams: RespondParams) async throws {
func respond(respondParams: RespondParams, issuer: Account) async throws {
guard let request = rpcHistory.get(recordId: RPCID(respondParams.id))?.request else { throw Errors.recordForIdNotFound }
guard let authRequestParams = try? request.params?.get(AuthRequestParams.self) else { throw Errors.malformedAuthRequestParams }

let peerPubKey = authRequestParams.requester.publicKey
let responseTopic = peerPubKey.rawRepresentation.sha256().toHexString()
let selfPubKey = try kms.createX25519KeyPair()
let agreementKeys = try kms.performKeyAgreement(selfPublicKey: selfPubKey, peerPublicKey: peerPubKey)
try kms.setAgreementSecret(agreementKeys, topic: responseTopic)

let cacao = CacaoFormatter().format(authRequestParams, respondParams.signature, issuer)
let response = RPCResponse(id: request.id!, result: cacao)

try await networkingInteractor.respond(topic: respondParams.topic, response: response, tag: AuthResponseParams.tag, envelopeType: .type1(pubKey: selfPubKey.rawRepresentation))
}
}
7 changes: 7 additions & 0 deletions Sources/Auth/Types/Cacao/Cacao.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation

struct Cacao: Codable, Equatable {
let header: CacaoHeader
let payload: CacaoPayload
let signature: CacaoSignature
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import Foundation
import WalletConnectUtils

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import Foundation
import WalletConnectUtils

Expand Down
2 changes: 1 addition & 1 deletion Sources/Auth/Types/RequestSubscriptionPayload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import Foundation
import JSONRPC

struct RequestSubscriptionPayload: Codable {
let topic: String
let id: Int64
let request: RPCRequest
}
1 change: 1 addition & 0 deletions Sources/Auth/Types/RespondParams.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation

struct RespondParams {
let id: Int64
let topic: String
let signature: CacaoSignature
}
3 changes: 1 addition & 2 deletions Sources/Chat/ChatClientFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ public struct ChatClientFactory {
relayClient: RelayClient,
kms: KeyManagementService,
logger: ConsoleLogging,
keyValueStorage: KeyValueStorage) -> ChatClient
{
keyValueStorage: KeyValueStorage) -> ChatClient {
let topicToRegistryRecordStore = CodableStore<RegistryRecord>(defaults: keyValueStorage, identifier: StorageDomainIdentifiers.topicToInvitationPubKey.rawValue)
let serialiser = Serializer(kms: kms)
let jsonRpcHistory = JsonRpcHistory<ChatRequestParams>(logger: logger, keyValueStore: CodableStore<JsonRpcRecord>(defaults: keyValueStorage, identifier: StorageDomainIdentifiers.jsonRpcHistory.rawValue))
Expand Down
4 changes: 4 additions & 0 deletions Sources/JSONRPC/RPCResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public struct RPCResponse: Equatable {
self.init(id: RPCID(id), outcome: .success(AnyCodable(result)))
}

public init<C>(id: RPCID, result: C) where C: Codable {
self.init(id: id, outcome: .success(AnyCodable(result)))
}
Comment on lines +46 to +48

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that you needed an init that receives a RPCID. In your opinion, do you think it's better to add these specific inits or should we change the default init from internal to public?


public init(id: Int64, error: JSONRPCError) {
self.init(id: RPCID(id), outcome: .failure(error))
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/WalletConnectUtils/RPCHistory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public final class RPCHistory {
let id: RPCID
let topic: String
let origin: Origin
let request: RPCRequest
var response: RPCResponse? = nil
public let request: RPCRequest
var response: RPCResponse?
}

enum HistoryError: Error {
Expand Down
14 changes: 12 additions & 2 deletions Tests/AuthTests/Mocks/NetworkingInteractorMock.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import Foundation
import Combine
@testable import Auth
import JSONRPC
import WalletConnectKMS

struct NetworkingInteractorMock: NetworkInteracting {

let requestPublisherSubject = PassthroughSubject<RequestSubscriptionPayload, Never>()
var requestPublisher: AnyPublisher<RequestSubscriptionPayload, Never> {
requestPublisherSubject.eraseToAnyPublisher()
}

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 {

}

}
1 change: 0 additions & 1 deletion Tests/AuthTests/Mocks/SIWEMessageFormatterMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ class SIWEMessageFormatterMock: SIWEMessageFormatting {
return formattedMessage
}
}

3 changes: 1 addition & 2 deletions Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +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(topic: "", request: request)
return RequestSubscriptionPayload(id: 123, request: request)
}
}

2 changes: 1 addition & 1 deletion Tests/WalletConnectSignTests/ApproveEngineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ final class ApproveEngineTests: XCTestCase {
XCTAssertTrue(networkingInteractor.didCallSubscribe)
XCTAssert(cryptoMock.hasAgreementSecret(for: topicB), "Responder must store agreement key for topic B")
XCTAssertEqual(networkingInteractor.didRespondOnTopic!, topicA, "Responder must respond on topic A")
XCTAssertEqual(extendedPairing.expiryDate.timeIntervalSince1970, Date(timeIntervalSinceNow: 2_592_000).timeIntervalSince1970, accuracy: 1, "pairing expiry has been extended by 30 days")
XCTAssertEqual(extendedPairing.expiryDate.timeIntervalSince1970, Date(timeIntervalSinceNow: 2_592_000).timeIntervalSince1970, accuracy: 1, "pairing expiry has been extended by 30 days")
}

func testReceiveProposal() {
Expand Down