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 request publisher not integrated fallback #1320

Merged
merged 3 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
38 changes: 31 additions & 7 deletions Example/IntegrationTests/Sign/SignClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ final class SignClientTests: XCTestCase {
func testEIP191SessionAuthenticated() async throws {
let responseExpectation = expectation(description: "successful response delivered")

wallet.authRequestPublisher.sink { [unowned self] (request, _) in
wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in
Task(priority: .high) {
let signerFactory = DefaultSignerFactory()
let signer = MessageSignerFactory(signerFactory: signerFactory).create()
Expand Down Expand Up @@ -811,7 +811,7 @@ final class SignClientTests: XCTestCase {
func testEIP191SessionAuthenticateEmptyMethods() async throws {
let responseExpectation = expectation(description: "successful response delivered")

wallet.authRequestPublisher.sink { [unowned self] (request, _) in
wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in
Task(priority: .high) {
let signerFactory = DefaultSignerFactory()
let signer = MessageSignerFactory(signerFactory: signerFactory).create()
Expand Down Expand Up @@ -846,7 +846,7 @@ final class SignClientTests: XCTestCase {
func testEIP191SessionAuthenticatedMultiCacao() async throws {
let responseExpectation = expectation(description: "successful response delivered")

wallet.authRequestPublisher.sink { [unowned self] (request, _) in
wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in
Task(priority: .high) {
let signerFactory = DefaultSignerFactory()
let signer = MessageSignerFactory(signerFactory: signerFactory).create()
Expand Down Expand Up @@ -911,7 +911,7 @@ final class SignClientTests: XCTestCase {

try await walletPairingClient.pair(uri: uri)

wallet.authRequestPublisher.sink { [unowned self] (request, _) in
wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in
Task(priority: .high) {
let signature = CacaoSignature(t: .eip1271, s: eip1271Signature)
let cacao = try! wallet.buildSignedAuthObject(authPayload: request.payload, signature: signature, account: account)
Expand All @@ -932,7 +932,7 @@ final class SignClientTests: XCTestCase {
let uri = try! await dapp.authenticate(AuthRequestParams.stub())

try? await walletPairingClient.pair(uri: uri)
wallet.authRequestPublisher.sink { [unowned self] (request, _) in
wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in
Task(priority: .high) {
let invalidSignature = CacaoSignature(t: .eip1271, s: eip1271Signature)

Expand All @@ -954,7 +954,7 @@ final class SignClientTests: XCTestCase {
let uri = try! await dapp.authenticate(AuthRequestParams.stub())

try? await walletPairingClient.pair(uri: uri)
wallet.authRequestPublisher.sink { [unowned self] request in
wallet.authenticateRequestPublisher.sink { [unowned self] request in
Task(priority: .high) {
try! await wallet.rejectSession(requestId: request.0.id)
}
Expand All @@ -979,7 +979,7 @@ final class SignClientTests: XCTestCase {
let chain = Blockchain("eip155:1")!
// sleep is needed as emitRequestIfPending() will be called on client init and then on request itself, second request would be debouced
sleep(1)
wallet.authRequestPublisher.sink { [unowned self] (request, _) in
wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in
Task(priority: .high) {
let signerFactory = DefaultSignerFactory()
let signer = MessageSignerFactory(signerFactory: signerFactory).create()
Expand Down Expand Up @@ -1062,4 +1062,28 @@ final class SignClientTests: XCTestCase {
await fulfillment(of: [fallbackExpectation], timeout: InputConfig.defaultTimeout)
}


func testFallbackToSessionProposeIfWalletIsNotSubscribingSessionAuthenticate() async throws {
let responseExpectation = expectation(description: "successful response delivered")

let requiredNamespaces = ProposalNamespace.stubRequired()
let sessionNamespaces = SessionNamespace.make(toRespond: requiredNamespaces)

wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in
Task(priority: .high) {
do { _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") }
}
}.store(in: &publishers)

dapp.sessionSettlePublisher.sink { settledSession in
Task(priority: .high) {
responseExpectation.fulfill()
}
}.store(in: &publishers)

let uri = try await dapp.authenticate(AuthRequestParams.stub())
try await walletPairingClient.pair(uri: uri)
await fulfillment(of: [responseExpectation], timeout: InputConfig.defaultTimeout)
}

}
11 changes: 0 additions & 11 deletions Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,17 +180,6 @@ public class NotifyClient {
}
}

private extension NotifyClient {

func makeStatement(allApps: Bool) -> String {
switch allApps {
case false:
return "I further authorize this app to send me notifications. Read more at https://walletconnect.com/notifications"
case true:
return "I further authorize this app to view and manage my notifications for ALL apps. Read more at https://walletconnect.com/notifications"
}
}
}

#if targetEnvironment(simulator)
extension NotifyClient {
Expand Down
7 changes: 5 additions & 2 deletions Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ final class ApproveEngine {
private let kms: KeyManagementServiceProtocol
private let logger: ConsoleLogging
private let rpcHistory: RPCHistory
private let authRequestSubscribersTracking: AuthRequestSubscribersTracking

private var publishers = Set<AnyCancellable>()

Expand All @@ -44,7 +45,8 @@ final class ApproveEngine {
pairingStore: WCPairingStorage,
sessionStore: WCSessionStorage,
verifyClient: VerifyClientProtocol,
rpcHistory: RPCHistory
rpcHistory: RPCHistory,
authRequestSubscribersTracking: AuthRequestSubscribersTracking
) {
self.networkingInteractor = networkingInteractor
self.proposalPayloadsStore = proposalPayloadsStore
Expand All @@ -58,6 +60,7 @@ final class ApproveEngine {
self.sessionStore = sessionStore
self.verifyClient = verifyClient
self.rpcHistory = rpcHistory
self.authRequestSubscribersTracking = authRequestSubscribersTracking

setupRequestSubscriptions()
setupResponseSubscriptions()
Expand Down Expand Up @@ -217,7 +220,7 @@ private extension ApproveEngine {
guard let pairing = pairingStore.getPairing(forTopic: payload.topic) else { return }
if let methods = pairing.methods,
methods.flatMap({ $0 })
.contains(SessionAuthenticatedProtocolMethod().method) {
.contains(SessionAuthenticatedProtocolMethod().method), authRequestSubscribersTracking.hasSubscribers() {
logger.debug("Ignoring Session Proposal")
// respond with an error?
return
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Foundation

// purpose of this class is to allow fallback to session propose in case wallet did not subscribe to authenticateRequestPublisher and dapp request wc_sessionAuthenticate
class AuthRequestSubscribersTracking {
private var subscribersCount: Int = 0
private let serialQueue = DispatchQueue(label: "com.walletconnect.AuthRequestSubscribersTrackingQueue")
private let logger: ConsoleLogging

init(logger: ConsoleLogging) {
self.logger = logger
}

func increment() {
serialQueue.sync {
subscribersCount += 1
logger.debug("Incremented subscriber count: \(subscribersCount)")
}
}

func decrement() {
serialQueue.sync {
subscribersCount = max(0, subscribersCount - 1)
logger.debug("Decremented subscriber count: \(subscribersCount)")
}
}

func hasSubscribers() -> Bool {
return serialQueue.sync { subscribersCount > 0 }
}
}
15 changes: 12 additions & 3 deletions Sources/WalletConnectSign/Sign/SignClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,14 @@ public final class SignClient: SignClientProtocol {
/// Publisher that sends authentication requests
///
/// Wallet should subscribe on events in order to receive auth requests.
public var authRequestPublisher: AnyPublisher<(request: AuthenticationRequest, context: VerifyContext?), Never> {
authRequestPublisherSubject.eraseToAnyPublisher()
public var authenticateRequestPublisher: AnyPublisher<(request: AuthenticationRequest, context: VerifyContext?), Never> {
return authRequestPublisherSubject
.handleEvents(receiveSubscription: { [unowned self] _ in
authRequestSubscribersTracking.increment()
}, receiveCancel: { [unowned self] in
authRequestSubscribersTracking.decrement()
})
.eraseToAnyPublisher()
}

/// Publisher that sends authentication responses
Expand Down Expand Up @@ -175,6 +181,7 @@ public final class SignClient: SignClientProtocol {
private let pingResponsePublisherSubject = PassthroughSubject<String, Never>()
private let sessionsPublisherSubject = PassthroughSubject<[Session], Never>()
private var authRequestPublisherSubject = PassthroughSubject<(request: AuthenticationRequest, context: VerifyContext?), Never>()
private let authRequestSubscribersTracking: AuthRequestSubscribersTracking

private var publishers = Set<AnyCancellable>()

Expand Down Expand Up @@ -204,7 +211,8 @@ public final class SignClient: SignClientProtocol {
proposalExpiryWatcher: ProposalExpiryWatcher,
pendingProposalsProvider: PendingProposalsProvider,
requestsExpiryWatcher: RequestsExpiryWatcher,
authResponseTopicResubscriptionService: AuthResponseTopicResubscriptionService
authResponseTopicResubscriptionService: AuthResponseTopicResubscriptionService,
authRequestSubscribersTracking: AuthRequestSubscribersTracking
) {
self.logger = logger
self.networkingClient = networkingClient
Expand All @@ -231,6 +239,7 @@ public final class SignClient: SignClientProtocol {
self.pendingProposalsProvider = pendingProposalsProvider
self.requestsExpiryWatcher = requestsExpiryWatcher
self.authResponseTopicResubscriptionService = authResponseTopicResubscriptionService
self.authRequestSubscribersTracking = authRequestSubscribersTracking

setUpConnectionObserving()
setUpEnginesCallbacks()
Expand Down
7 changes: 5 additions & 2 deletions Sources/WalletConnectSign/Sign/SignClientFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public struct SignClientFactory {
let sessionExtendRequestSubscriber = SessionExtendRequestSubscriber(networkingInteractor: networkingClient, sessionStore: sessionStore, logger: logger)
let sessionExtendResponseSubscriber = SessionExtendResponseSubscriber(networkingInteractor: networkingClient, sessionStore: sessionStore, logger: logger)
let sessionTopicToProposal = CodableStore<Session.Proposal>(defaults: RuntimeKeyValueStorage(), identifier: SignStorageIdentifiers.sessionTopicToProposal.rawValue)
let authRequestSubscribersTracking = AuthRequestSubscribersTracking(logger: logger)
let approveEngine = ApproveEngine(
networkingInteractor: networkingClient,
proposalPayloadsStore: proposalPayloadsStore,
Expand All @@ -80,7 +81,8 @@ public struct SignClientFactory {
pairingStore: pairingStore,
sessionStore: sessionStore,
verifyClient: verifyClient,
rpcHistory: rpcHistory
rpcHistory: rpcHistory,
authRequestSubscribersTracking: authRequestSubscribersTracking
)
let cleanupService = SignCleanupService(pairingStore: pairingStore, sessionStore: sessionStore, kms: kms, sessionTopicToProposal: sessionTopicToProposal, networkInteractor: networkingClient, rpcHistory: rpcHistory)
let deleteSessionService = DeleteSessionService(networkingInteractor: networkingClient, kms: kms, sessionStore: sessionStore, logger: logger)
Expand Down Expand Up @@ -135,7 +137,8 @@ public struct SignClientFactory {
proposalExpiryWatcher: proposalExpiryWatcher,
pendingProposalsProvider: pendingProposalsProvider,
requestsExpiryWatcher: requestsExpiryWatcher,
authResponseTopicResubscriptionService: authResponseTopicResubscriptionService
authResponseTopicResubscriptionService: authResponseTopicResubscriptionService,
authRequestSubscribersTracking: authRequestSubscribersTracking
)
return client
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/WalletConnectSign/Sign/SignClientProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public protocol SignClientProtocol {
var sessionResponsePublisher: AnyPublisher<Response, Never> { get }
var sessionRejectionPublisher: AnyPublisher<(Session.Proposal, Reason), Never> { get }
var sessionEventPublisher: AnyPublisher<(event: Session.Event, sessionTopic: String, chainId: Blockchain?), Never> { get }
var authRequestPublisher: AnyPublisher<(request: AuthenticationRequest, context: VerifyContext?), Never> { get }
var authenticateRequestPublisher: AnyPublisher<(request: AuthenticationRequest, context: VerifyContext?), Never> { get }
var logsPublisher: AnyPublisher<Log, Never> {get}
var sessionProposalExpirationPublisher: AnyPublisher<Session.Proposal, Never> { get }
var pendingProposalsPublisher: AnyPublisher<[(proposal: Session.Proposal, context: VerifyContext?)], Never> { get }
Expand Down
2 changes: 1 addition & 1 deletion Sources/Web3Wallet/Web3WalletClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class Web3WalletClient {
///
/// Wallet should subscribe on events in order to receive auth requests.
public var authenticateRequestPublisher: AnyPublisher<(request: AuthenticationRequest, context: VerifyContext?), Never> {
signClient.authRequestPublisher.eraseToAnyPublisher()
signClient.authenticateRequestPublisher.eraseToAnyPublisher()
}

/// Publisher that sends sessions on every sessions update
Expand Down
3 changes: 2 additions & 1 deletion Tests/WalletConnectSignTests/AppProposalServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ final class AppProposalServiceTests: XCTestCase {
pairingStore: storageMock,
sessionStore: WCSessionStorageMock(),
verifyClient: VerifyClientMock(),
rpcHistory: history
rpcHistory: history,
authRequestSubscribersTracking: AuthRequestSubscribersTracking(logger: logger)
)
}

Expand Down
3 changes: 2 additions & 1 deletion Tests/WalletConnectSignTests/ApproveEngineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ final class ApproveEngineTests: XCTestCase {
pairingStore: pairingStorageMock,
sessionStore: sessionStorageMock,
verifyClient: VerifyClientMock(),
rpcHistory: history
rpcHistory: history,
authRequestSubscribersTracking: AuthRequestSubscribersTracking(logger: ConsoleLoggerMock())
)
}

Expand Down
Loading