fix(WalletConnect): Fixing disconnect notifications

The disconnect notifications were operating on `WalletConnectService.currentSessionProposal`. This object stores the current session object on connect, but it's not necessarily the same session the user wants to disconnect.
To fix this I'm getting the active sessions from status-go when the disconnect request is received (from Status or dapp). If the topic matches to any connection topic owned by the users accounts we'll show a notification.
This commit is contained in:
Alex Jbanca 2024-08-02 14:18:58 +03:00
parent 2f1ae5297e
commit fea4e8ed76
No known key found for this signature in database
GPG Key ID: 6004079575C21C5D
5 changed files with 91 additions and 14 deletions

View File

@ -1,5 +1,5 @@
import NimQml
import chronicles
import chronicles, times, json
import app_service/service/wallet_connect/service as wallet_connect_service
import app_service/service/wallet_account/service as wallet_account_service
@ -47,6 +47,20 @@ QtObject:
self.dappsListReceived(res)
return true
proc activeSessionsReceived(self: Controller, activeSessionsJson: string) {.signal.}
# Emits signal activeSessionsReceived with the list of active sessions
# TODO: make it async
proc getActiveSessions(self: Controller): bool {.slot.} =
let validAtTimestamp = now().toTime().toUnix()
let res = self.service.getActiveSessions(validAtTimestamp)
if res.isNil:
return false
else:
let resultStr = $res
self.activeSessionsReceived(resultStr)
return true
proc userAuthenticationResult*(self: Controller, topic: string, id: string, error: bool, password: string, pin: string, payload: string) {.signal.}
# Beware, it will fail if an authentication is already in progress

View File

@ -115,6 +115,11 @@ QtObject:
# TODO #14588: call it async
return status_go.getDapps(validAtEpoch, testChains)
proc getActiveSessions*(self: Service, validAtTimestamp: int64): JsonNode =
# TODO #14588: call it async
return status_go.getActiveSessions(validAtTimestamp)
# Will fail if another authentication is in progress
proc authenticateUser*(self: Service, keyUid: string, callback: AuthenticationResponseFn): bool =
if self.authenticationCallback != nil:

View File

@ -18,7 +18,7 @@ rpc(disconnectWalletConnectSession, "wallet"):
topic: string
rpc(getWalletConnectActiveSessions, "wallet"):
validAtTimestamp: int
validAtTimestamp: int64
rpc(hashMessageEIP191, "wallet"):
message: string
@ -50,13 +50,14 @@ proc disconnectSession*(topic: string): bool =
return false
# returns nil if error
proc getActiveSessions*(validAtTimestamp: int): JsonNode =
proc getActiveSessions*(validAtTimestamp: int64): JsonNode =
try:
let rpcRes = getWalletConnectActiveSessions(validAtTimestamp)
if(not isSuccessResponse(rpcRes)):
return nil
let jsonResultStr = rpcRes.result.getStr()
let jsonResultStr = $rpcRes.result
if jsonResultStr == "null" or jsonResultStr == "":
return newJArray()

View File

@ -210,16 +210,7 @@ QObject {
}
function onSessionDelete(topic, err) {
store.deactivateWalletConnectSession(topic)
dappsProvider.updateDapps()
const app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
const app_domain = StringUtils.extractDomainFromLink(app_url)
if(err) {
root.displayToastMessage(qsTr("Failed to disconnect from %1").arg(app_domain), true)
} else {
root.displayToastMessage(qsTr("Disconnected from %1").arg(app_domain), false)
}
d.disconnectSessionRequested(topic, err)
}
}
@ -235,6 +226,54 @@ QObject {
timeoutTimer.stop()
root.pairingValidated(state)
}
function disconnectSessionRequested(topic, err) {
// Get all sessions and filter the active ones for known accounts
// Act on the first matching session with the same topic
const activeSessionsCallback = (allSessions, success) => {
store.activeSessionsReceived.disconnect(activeSessionsCallback)
if (!success) {
// TODO #14754: implement custom dApp notification
d.notifyDappDisconnect("-", true)
return
}
// Convert to original format
const webSdkSessions = allSessions.map((session) => {
return JSON.parse(session.sessionJson)
})
const sessions = DAppsHelpers.filterActiveSessionsForKnownAccounts(webSdkSessions, root.validAccounts)
for (const sessionID in sessions) {
const session = sessions[sessionID]
if (session.topic === topic) {
store.deactivateWalletConnectSession(topic)
dappsProvider.updateDapps()
const dappUrl = session.peer.metadata.url ?? "-"
d.notifyDappDisconnect(dappUrl, err)
break
}
}
}
store.activeSessionsReceived.connect(activeSessionsCallback)
if (!store.getActiveSessions()) {
store.activeSessionsReceived.disconnect(activeSessionsCallback)
// TODO #14754: implement custom dApp notification
}
}
function notifyDappDisconnect(dappUrl, err) {
const appDomain = StringUtils.extractDomainFromLink(dappUrl)
if(err) {
root.displayToastMessage(qsTr("Failed to disconnect from %1").arg(appDomain), true)
} else {
root.displayToastMessage(qsTr("Disconnected from %1").arg(appDomain), false)
}
}
}
Component.onCompleted: {

View File

@ -8,6 +8,7 @@ QObject {
required property var controller
/// \c dappsJson serialized from status-go.wallet.GetDapps
signal dappsListReceived(string dappsJson)
signal activeSessionsReceived(var activeSessionsJsonObj, bool success)
signal userAuthenticated(string topic, string id, string password, string pin, string payload)
signal userAuthenticationFailed(string topic, string id)
@ -107,6 +108,12 @@ QObject {
return controller.getDapps()
}
/// \c getActiveSessions triggers an async response to \c activeSessionsReceived
/// \returns true if the request was sent successfully
function getActiveSessions() {
return controller.getActiveSessions()
}
function hexToDec(hex) {
return controller.hexToDecBigString(hex)
}
@ -124,6 +131,17 @@ QObject {
root.dappsListReceived(dappsJson)
}
function onActiveSessionsReceived(activeSessionsJson) {
try {
const jsonObj = JSON.parse(activeSessionsJson)
root.activeSessionsReceived(jsonObj, true)
} catch (e) {
console.error("Failed to parse activeSessionsJson", e)
root.activeSessionsReceived({}, false)
return
}
}
function onUserAuthenticationResult(topic, id, success, password, pin, payload) {
if (success) {
root.userAuthenticated(topic, id, password, pin, payload)