fix(dapps): filter out dApps connected on other profiles

Add helper function to filter out dApps with sessions that don't
have any supported account in the available accounts list.
Use helper function to filter out dApps connected on other profiles
when listing dApps in the dApps list.
When disconnecting an app only disconnect sessions for the current
profile.

Closes: #14888, #15707
This commit is contained in:
Stefan 2024-07-23 17:26:55 +03:00 committed by Stefan Dunca
parent 35b7f0583d
commit 7fb241b964
4 changed files with 62 additions and 9 deletions

View File

@ -552,7 +552,9 @@ Item {
dappsListReceivedJsonStr: dappsListReceivedJsonStr
})
verify(!!store)
provider = createTemporaryObject(dappsListProviderComponent, root, {sdk: sdk, store: store})
const walletStore = createTemporaryObject(walletStoreComponent, root)
verify(!!walletStore)
provider = createTemporaryObject(dappsListProviderComponent, root, {sdk: sdk, store: store, supportedAccountsModel: walletStore.nonWatchAccounts})
verify(!!provider)
}
@ -576,7 +578,8 @@ Item {
sdk.sdkReady = true
compare(sdk.getActiveSessionsCallbacks.length, 1, "expected a call to sdk.getActiveSessions when SDK becomes ready")
let callback = sdk.getActiveSessionsCallbacks[0].callback
let session = JSON.parse(Testing.formatApproveSessionResponse([1, 2], ["0x1"], {dappMetadataJsonString: Testing.noIconsDappMetadataJsonString}))
const address = ModelUtils.get(provider.supportedAccountsModel, 0, "address")
let session = JSON.parse(Testing.formatApproveSessionResponse([1, 2], [address], {dappMetadataJsonString: Testing.noIconsDappMetadataJsonString}))
callback({"b536a": session, "b537b": session})
compare(provider.dappsModel.count, 1, "expected dappsModel have the SDK's reported dapps")
compare(provider.dappsModel.get(0).iconUrl, "", "expected iconUrl to be missing")
@ -665,6 +668,28 @@ Item {
verify(eip155.hasOwnProperty("events"))
compare(eip155.events.length, 2)
}
function test_filterActiveSessionsForKnownAccounts() {
const account1 = accountsModel.get(0)
const account2 = accountsModel.get(1)
const chainIds = [chainsModel.get(0).chainId, chainsModel.get(1).chainId]
const knownSession = JSON.parse(Testing.formatApproveSessionResponse(chainIds, [account2.address]))
// Allow the unlikely unknown accounts to cover for the deleted accounts case
const unknownSessionWithKnownAccount = JSON.parse(Testing.formatApproveSessionResponse(chainIds, ['0x03acc', account1.address]))
const unknownSession1 = JSON.parse(Testing.formatApproveSessionResponse(chainIds, ['0x83acc']))
const unknownSession2 = JSON.parse(Testing.formatApproveSessionResponse(chainIds, ['0x12acc']))
let testSessions = {
"b536a": knownSession,
"b537b": unknownSession1,
"b538c": unknownSession2,
"b539d": unknownSessionWithKnownAccount
}
let res = Helpers.filterActiveSessionsForKnownAccounts(testSessions, accountsModel)
compare(Object.keys(res).length, 2, "expected two sessions to be returned")
// Also test that order is stable
compare(res["b536a"], knownSession, "expected the known session to be returned")
compare(res["b539d"], unknownSessionWithKnownAccount, "expected the known session to be returned")
}
}
Component {

View File

@ -2,6 +2,8 @@ import QtQuick 2.15
import StatusQ.Core.Utils 0.1
import AppLayouts.Wallet.services.dapps 1.0
import shared.stores 1.0
import utils 1.0
@ -11,6 +13,7 @@ QObject {
required property WalletConnectSDKBase sdk
required property DAppsStore store
required property var supportedAccountsModel
readonly property alias dappsModel: d.dappsModel
@ -46,11 +49,12 @@ QObject {
}
getActiveSessionsFn = () => {
sdk.getActiveSessions((sessions) => {
sdk.getActiveSessions((allSessions) => {
root.store.dappsListReceived.disconnect(dappsListReceivedFn);
let tmpMap = {}
var topics = []
const sessions = Helpers.filterActiveSessionsForKnownAccounts(allSessions, root.supportedAccountsModel)
for (let key in sessions) {
let dapp = sessions[key].peer.metadata
if (!!dapp.icons && dapp.icons.length > 0) {
@ -61,7 +65,7 @@ QObject {
tmpMap[dapp.url] = dapp;
topics.push(key)
}
// TODO #14755: on SDK dApps refresh update the model that has data source from persistence instead of using reset
// TODO #15075: on SDK dApps refresh update the model that has data source from persistence instead of using reset
dapps.clear();
// Iterate tmpMap and fill dapps
for (let key in tmpMap) {

View File

@ -36,7 +36,7 @@ QObject {
readonly property alias requestHandler: requestHandler
readonly property var validAccounts: SortFilterProxyModel {
sourceModel: root.walletRootStore.nonWatchAccounts
sourceModel: d.supportedAccountsModel
proxyRoles: [
FastExpressionRole {
name: "colorizedChainPrefixes"
@ -108,10 +108,11 @@ QObject {
}
function disconnectDapp(url) {
wcSDK.getActiveSessions((sessions) => {
for (let key in sessions) {
let dapp = sessions[key].peer.metadata
let topic = sessions[key].topic
wcSDK.getActiveSessions((allSessions) => {
const sessions = Helpers.filterActiveSessionsForKnownAccounts(allSessions, d.supportedAccountsModel)
for (let session in sessions) {
let dapp = session.peer.metadata
let topic = session.topic
if (dapp.url == url) {
wcSDK.disconnectSession(topic)
}
@ -218,6 +219,8 @@ QObject {
QObject {
id: d
readonly property var supportedAccountsModel: root.walletRootStore.nonWatchAccounts
property var currentSessionProposal: null
property var acceptedSessionProposal: null
@ -255,6 +258,7 @@ QObject {
sdk: root.wcSDK
store: root.store
supportedAccountsModel: d.supportedAccountsModel
}
// Timeout for the corner case where the URL was already dismissed and the SDK doesn't respond with an error nor advances with the proposal

View File

@ -100,3 +100,23 @@ function extractInfoFromPairUri(uri) {
}
return { topic, expiry }
}
function filterActiveSessionsForKnownAccounts(sessions, accountsModel) {
let knownSessions = ({})
Object.keys(sessions).forEach((topic) => {
const session = sessions[topic]
const eip155Addresses = session.namespaces.eip155.accounts
const accountSet = new Set(
eip155Addresses.map(eip155Address => eip155Address.split(':').pop().trim())
);
const uniqueAddresses = Array.from(accountSet);
const firstAccount = SQUtils.ModelUtils.getFirstModelEntryIf(accountsModel, (account) => {
return uniqueAddresses.includes(account.address)
})
if (!firstAccount) {
return
}
knownSessions[topic] = session
})
return knownSessions
}