Skip to content

Commit

Permalink
Merge pull request #383 from WalletConnect/feature/pairing-services
Browse files Browse the repository at this point in the history
[Auth] Pairing Services
  • Loading branch information
flypaper0 authored Jul 29, 2022
2 parents 6476a30 + cbfcc61 commit 34af3e4
Show file tree
Hide file tree
Showing 39 changed files with 281 additions and 88 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ concurrency:

jobs:
build:
runs-on: macos-12
runs-on: macos-latest
strategy:
matrix:
test-type: [ui-tests, unit-tests, integration-tests, build-example-wallet, build-example-dapp]
Expand Down
10 changes: 10 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/WalletConnect.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,16 @@
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AuthTests"
BuildableName = "AuthTests"
BlueprintName = "AuthTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand Down
67 changes: 67 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/WalletConnectAuth.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1340"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "WalletConnectAuth"
BuildableName = "WalletConnectAuth"
BlueprintName = "WalletConnectAuth"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "WalletConnectAuth"
BuildableName = "WalletConnectAuth"
BlueprintName = "WalletConnectAuth"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
12 changes: 9 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,24 @@ let package = Package(
targets: ["WalletConnectSign"]),
.library(
name: "WalletConnectChat",
targets: ["Chat"])
targets: ["Chat"]),
.library(
name: "WalletConnectPairing",
targets: ["WalletConnectPairing"]),
],
dependencies: [],
targets: [
.target(
name: "WalletConnectSign",
dependencies: ["WalletConnectRelay", "WalletConnectUtils", "WalletConnectKMS"],
dependencies: ["WalletConnectRelay", "WalletConnectUtils", "WalletConnectKMS", "WalletConnectPairing"],
path: "Sources/WalletConnectSign"),
.target(
name: "Chat",
dependencies: ["WalletConnectRelay", "WalletConnectUtils", "WalletConnectKMS"],
path: "Sources/Chat"),
.target(
name: "Auth",
dependencies: ["WalletConnectRelay", "WalletConnectUtils", "WalletConnectKMS"],
dependencies: ["WalletConnectRelay", "WalletConnectUtils", "WalletConnectKMS", "WalletConnectPairing"],
path: "Sources/Auth"),
.target(
name: "WalletConnectRelay",
Expand All @@ -39,6 +42,9 @@ let package = Package(
name: "WalletConnectKMS",
dependencies: ["WalletConnectUtils"],
path: "Sources/WalletConnectKMS"),
.target(
name: "WalletConnectPairing",
dependencies: ["WalletConnectUtils"]),
.target(
name: "WalletConnectUtils",
dependencies: ["Commons"]),
Expand Down
26 changes: 26 additions & 0 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
import Foundation

class AuthClient {
enum Errors: Error {
case malformedPairingURI
}

private let appPairService: AppPairService
private let appRequestService: AuthRequestService

private let walletPairService: WalletPairService

init(appPairService: AppPairService, appRequestService: AuthRequestService, walletPairService: WalletPairService) {
self.appPairService = appPairService
self.appRequestService = appRequestService
self.walletPairService = walletPairService
}

func request(params: RequestParams) async throws -> String {
let uri = try await appPairService.create()
try await appRequestService.request(params: params, topic: uri.topic)
return uri.absoluteString
}

func pair(uri: String) async throws {
guard let pairingURI = WalletConnectURI(string: uri) else {
throw Errors.malformedPairingURI
}
try await walletPairService.pair(pairingURI)
}
}
25 changes: 25 additions & 0 deletions Sources/Auth/Services/App/AppPairService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Foundation
import WalletConnectKMS
import WalletConnectPairing

actor AppPairService {
private let networkingInteractor: NetworkInteracting
private let kms: KeyManagementServiceProtocol
private let pairingStorage: WCPairingStorage

init(networkingInteractor: NetworkInteracting, kms: KeyManagementServiceProtocol, pairingStorage: WCPairingStorage) {
self.networkingInteractor = networkingInteractor
self.kms = kms
self.pairingStorage = pairingStorage
}

func create() async throws -> WalletConnectURI {
let topic = String.generateTopic()
try await networkingInteractor.subscribe(topic: topic)
let symKey = try! kms.createSymmetricKey(topic)
let pairing = WCPairing(topic: topic)
let uri = WalletConnectURI(topic: topic, symKey: symKey.hexRepresentation, relay: pairing.relay)
pairingStorage.setPairing(pairing)
return uri
}
}
8 changes: 0 additions & 8 deletions Sources/Auth/Services/App/CreatePairingService.swift

This file was deleted.

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

protocol NetworkInteracting {
func subscribe(topic: String) async throws
}

class NetworkingInteractor: NetworkInteracting {
private let relayClient: RelayClient

init(relayClient: RelayClient) {
self.relayClient = relayClient
}

func subscribe(topic: String) async throws {
try await relayClient.subscribe(topic: topic)
}
}
8 changes: 0 additions & 8 deletions Sources/Auth/Services/Wallet/PairService.swift

This file was deleted.

37 changes: 37 additions & 0 deletions Sources/Auth/Services/Wallet/WalletPairService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation
import WalletConnectKMS
import WalletConnectPairing

actor WalletPairService {
enum Errors: Error {
case pairingAlreadyExist
}

private let networkingInteractor: NetworkInteracting
private let kms: KeyManagementServiceProtocol
private let pairingStorage: WCPairingStorage

init(networkingInteractor: NetworkInteracting,
kms: KeyManagementServiceProtocol,
pairingStorage: WCPairingStorage) {
self.networkingInteractor = networkingInteractor
self.kms = kms
self.pairingStorage = pairingStorage
}

func pair(_ uri: WalletConnectURI) async throws {
guard !hasPairing(for: uri.topic) else {
throw Errors.pairingAlreadyExist
}
var pairing = WCPairing(uri: uri)
try await networkingInteractor.subscribe(topic: pairing.topic)
let symKey = try SymmetricKey(hex: uri.symKey)
try kms.setSymmetricKey(symKey, for: pairing.topic)
pairing.activate()
pairingStorage.setPairing(pairing)
}

func hasPairing(for topic: String) -> Bool {
return pairingStorage.hasPairing(forTopic: topic)
}
}
2 changes: 0 additions & 2 deletions Sources/Auth/Types/RelayProtocolOptions.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//

import Foundation
import WalletConnectUtils

Expand Down
2 changes: 0 additions & 2 deletions Sources/Auth/Types/WalletConnectURI.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//

import Foundation
import WalletConnectUtils

Expand Down
2 changes: 0 additions & 2 deletions Sources/WalletConnectKMS/Crypto/Hash.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//

import Foundation
import CryptoKit

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
protocol WCPairingStorage: AnyObject {
import Foundation
import WalletConnectUtils

public protocol WCPairingStorage: AnyObject {
var onPairingExpiration: ((WCPairing) -> Void)? { get set }
func hasPairing(forTopic topic: String) -> Bool
func setPairing(_ pairing: WCPairing)
Expand All @@ -8,40 +11,40 @@ protocol WCPairingStorage: AnyObject {
func deleteAll()
}

final class PairingStorage: WCPairingStorage {
public final class PairingStorage: WCPairingStorage {

var onPairingExpiration: ((WCPairing) -> Void)? {
public var onPairingExpiration: ((WCPairing) -> Void)? {
get { storage.onSequenceExpiration }
set { storage.onSequenceExpiration = newValue }
}

private let storage: SequenceStore<WCPairing>

init(storage: SequenceStore<WCPairing>) {
public init(storage: SequenceStore<WCPairing>) {
self.storage = storage
}

func hasPairing(forTopic topic: String) -> Bool {
public func hasPairing(forTopic topic: String) -> Bool {
storage.hasSequence(forTopic: topic)
}

func setPairing(_ pairing: WCPairing) {
public func setPairing(_ pairing: WCPairing) {
storage.setSequence(pairing)
}

func getPairing(forTopic topic: String) -> WCPairing? {
public func getPairing(forTopic topic: String) -> WCPairing? {
try? storage.getSequence(forTopic: topic)
}

func getAll() -> [WCPairing] {
public func getAll() -> [WCPairing] {
storage.getAll()
}

func delete(topic: String) {
public func delete(topic: String) {
storage.delete(topic: topic)
}

func deleteAll() {
public func deleteAll() {
storage.deleteAll()
}
}
18 changes: 18 additions & 0 deletions Sources/WalletConnectPairing/Types/PairingType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation

// Internal namespace for pairing payloads.
public enum PairingType {

public struct DeleteParams: Codable, Equatable {
let reason: Reason
}

public struct Reason: Codable, Equatable {
let code: Int
let message: String
}

public struct PingParams: Codable, Equatable {
public init() { }
}
}
Loading

0 comments on commit 34af3e4

Please sign in to comment.