1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Fix Connected Sites data selector (#8310)

This change replaces `getRenderablePermissionsDomains` with a new selector `getConnectedDomainsForSelectedAddress` that works better. The data returned from this selector is used to populated the _Connected Sites_ modal, which (as of #8262) didn't use most of the data returned from the old selector.

The old selector only looked at the first address that was exposed, making it not work for anything other than the first account connected to a particular origin.
This commit is contained in:
Whymarrh Whitby 2020-04-08 20:38:48 -02:30 committed by GitHub
parent f1c9f1ab68
commit d131014b5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 188 additions and 57 deletions

View File

@ -2,10 +2,10 @@ import { connect } from 'react-redux'
import ConnectedSites from './connected-sites.component'
import { getOpenMetamaskTabsIds, legacyExposeAccounts, removePermissionsFor } from '../../store/actions'
import {
getConnectedDomainsForSelectedAddress,
getCurrentAccountWithSendEtherInfo,
getPermissionsDomains,
getPermittedAccountsForCurrentTab,
getRenderablePermissionsDomains,
getSelectedAddress,
} from '../../selectors/selectors'
import { getOriginFromUrl } from '../../helpers/utils/util'
@ -14,7 +14,7 @@ const mapStateToProps = (state) => {
const { openMetaMaskTabs } = state.appState
const { title, url, id } = state.activeTab
const permittedAccounts = getPermittedAccountsForCurrentTab(state)
const connectedDomains = getRenderablePermissionsDomains(state)
const connectedDomains = getConnectedDomainsForSelectedAddress(state)
let tabToConnect
if (url && permittedAccounts.length === 0 && !openMetaMaskTabs[id]) {

View File

@ -1,3 +1,4 @@
import { flatten, forOwn } from 'lodash'
import { NETWORK_TYPES } from '../helpers/constants/common'
import { stripHexPrefix, addHexPrefix } from 'ethereumjs-util'
import { createSelector } from 'reselect'
@ -7,7 +8,6 @@ import { multiplyCurrencies } from '../helpers/utils/conversion-util'
import {
addressSlicer,
checksumAddress,
formatDate,
getOriginFromUrl,
getAccountByAddress,
} from '../helpers/utils/util'
@ -465,59 +465,6 @@ export function getPermittedAccountsForCurrentTab (state) {
return permittedAccountsMap[originOfCurrentTab] || []
}
export function getRenderablePermissionsDomains (state) {
const {
domains = {},
domainMetadata,
permissionsHistory,
permissionsDescriptions,
selectedAddress,
} = state.metamask
const renderableDomains = Object.keys(domains).reduce((acc, domainKey) => {
const { permissions } = domains[domainKey]
const permissionsWithCaveatsForSelectedAddress = permissions.filter((perm) => {
const caveats = perm.caveats || []
const exposedAccountCaveat = caveats.find((caveat) => caveat.name === 'exposedAccounts')
const exposedAccountCaveatValue = exposedAccountCaveat && exposedAccountCaveat.value && exposedAccountCaveat.value.length
? exposedAccountCaveat.value[0]
: {}
return exposedAccountCaveatValue === selectedAddress
})
if (permissionsWithCaveatsForSelectedAddress.length) {
const permissionKeys = permissions.map((permission) => permission.parentCapability)
const {
name,
icon,
extensionId,
} = domainMetadata[domainKey] || {}
const permissionsHistoryForDomain = permissionsHistory[domainKey] || {}
const ethAccountsPermissionsForDomain = permissionsHistoryForDomain['eth_accounts'] || {}
const accountsLastConnectedTime = ethAccountsPermissionsForDomain.accounts || {}
const selectedAddressLastConnectedTime = accountsLastConnectedTime[selectedAddress]
const lastConnectedTime = selectedAddressLastConnectedTime
? formatDate(selectedAddressLastConnectedTime, 'yyyy-MM-dd')
: ''
return [ ...acc, {
name: name || domainKey,
secondaryName: name ? domainKey : '',
icon,
key: domainKey,
lastConnectedTime,
permissionDescriptions: permissionKeys.map((permissionKey) => permissionsDescriptions[permissionKey]),
extensionId,
}]
} else {
return acc
}
}, [])
return renderableDomains
}
export function getOriginOfCurrentTab (state) {
const { activeTab } = state
return activeTab && activeTab.url && getOriginFromUrl(activeTab.url)
@ -538,3 +485,37 @@ export function getLastConnectedInfo (state) {
export function getIpfsGateway (state) {
return state.metamask.ipfsGateway
}
export function getConnectedDomainsForSelectedAddress (state) {
const {
domains = {},
domainMetadata,
selectedAddress,
} = state.metamask
const connectedDomains = []
forOwn(domains, (value, domain) => {
const exposedAccounts = flatten(value.permissions.map(
(p) => p.caveats?.find(({ name }) => name === 'exposedAccounts').value || []
))
if (!exposedAccounts.includes(selectedAddress)) {
return
}
const {
extensionId,
name,
icon,
} = domainMetadata[domain] || {}
connectedDomains.push({
extensionId,
key: domain,
name,
icon,
})
})
return connectedDomains
}

View File

@ -1,5 +1,5 @@
import assert from 'assert'
import { getAddressBook } from '../selectors.js'
import { getAddressBook, getConnectedDomainsForSelectedAddress } from '../selectors.js'
import mockState from './selectors-test-data'
describe('selectors', function () {
@ -21,4 +21,154 @@ describe('selectors', function () {
})
})
describe('getConnectedDomainsForSelectedAddress', function () {
it('should return the list of connected domains when there is 1 connected account', function () {
const mockState = {
metamask: {
selectedAddress: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5',
domainMetadata: {
'peepeth.com': {
'icon': 'https://peepeth.com/favicon-32x32.png',
'name': 'Peepeth',
},
'remix.ethereum.org': {
'icon': 'https://remix.ethereum.org/icon.png',
'name': 'Remix - Ethereum IDE',
},
},
domains: {
'peepeth.com': {
'permissions': [
{
'@context': [
'https://github.com/MetaMask/rpc-cap',
],
'caveats': [
{
'name': 'exposedAccounts',
'type': 'filterResponse',
'value': [
'0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5',
],
},
],
'date': 1585676177970,
'id': '840d72a0-925f-449f-830a-1aa1dd5ce151',
'invoker': 'peepeth.com',
'parentCapability': 'eth_accounts',
},
],
},
'remix.ethereum.org': {
'permissions': [
{
'@context': [
'https://github.com/MetaMask/rpc-cap',
],
'caveats': [
{
'type': 'filterResponse',
'value': [
'0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5',
],
'name': 'exposedAccounts',
},
],
'date': 1585685128948,
'id': '6b9615cc-64e4-4317-afab-3c4f8ee0244a',
'invoker': 'remix.ethereum.org',
'parentCapability': 'eth_accounts',
},
],
},
},
},
}
const extensionId = undefined
assert.deepEqual(getConnectedDomainsForSelectedAddress(mockState), [{
extensionId,
icon: 'https://peepeth.com/favicon-32x32.png',
key: 'peepeth.com',
name: 'Peepeth',
}, {
extensionId,
name: 'Remix - Ethereum IDE',
icon: 'https://remix.ethereum.org/icon.png',
key: 'remix.ethereum.org',
}])
})
it('should return the list of connected domains when there are 2 connected accounts', function () {
const mockState = {
metamask: {
selectedAddress: '0x7250739de134d33ec7ab1ee592711e15098c9d2d',
domainMetadata: {
'peepeth.com': {
'icon': 'https://peepeth.com/favicon-32x32.png',
'name': 'Peepeth',
},
'remix.ethereum.org': {
'icon': 'https://remix.ethereum.org/icon.png',
'name': 'Remix - Ethereum IDE',
},
},
domains: {
'peepeth.com': {
'permissions': [
{
'@context': [
'https://github.com/MetaMask/rpc-cap',
],
'caveats': [
{
'name': 'exposedAccounts',
'type': 'filterResponse',
'value': [
'0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5',
],
},
],
'date': 1585676177970,
'id': '840d72a0-925f-449f-830a-1aa1dd5ce151',
'invoker': 'peepeth.com',
'parentCapability': 'eth_accounts',
},
],
},
'remix.ethereum.org': {
'permissions': [
{
'@context': [
'https://github.com/MetaMask/rpc-cap',
],
'caveats': [
{
'type': 'filterResponse',
'value': [
'0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5',
'0x7250739de134d33ec7ab1ee592711e15098c9d2d',
],
'name': 'exposedAccounts',
},
],
'date': 1585685128948,
'id': '6b9615cc-64e4-4317-afab-3c4f8ee0244a',
'invoker': 'remix.ethereum.org',
'parentCapability': 'eth_accounts',
},
],
},
},
},
}
const extensionId = undefined
assert.deepEqual(getConnectedDomainsForSelectedAddress(mockState), [{
extensionId,
name: 'Remix - Ethereum IDE',
icon: 'https://remix.ethereum.org/icon.png',
key: 'remix.ethereum.org',
}])
})
})
})