1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-18 07:23:21 +01:00
metamask-extension/ui/app/selectors/permissions.js

287 lines
7.7 KiB
JavaScript
Raw Normal View History

2020-05-02 21:41:17 +02:00
import { forOwn } from 'lodash'
2020-11-03 00:41:28 +01:00
import { CAVEAT_NAMES } from '../../../app/scripts/controllers/permissions/enums'
import {
2020-11-03 00:41:28 +01:00
getMetaMaskAccountsOrdered,
getOriginOfCurrentTab,
getSelectedAddress,
} from '.'
// selectors
/**
* Get the permission domains object.
*
* @param {Object} state - The current state.
* @returns {Object} The permissions domains object.
*/
2020-11-03 00:41:28 +01:00
export function getPermissionDomains(state) {
return state.metamask.domains || {}
}
/**
* Get the permission domains metadata object.
*
* @param {Object} state - The current state.
* @returns {Object} The permission domains metadata object.
*/
2020-11-03 00:41:28 +01:00
export function getPermissionDomainsMetadata(state) {
return state.metamask.domainMetadata || {}
}
/**
* Selects the permitted accounts from the eth_accounts permission given state
* and an origin.
*
* @param {Object} state - The current state.
* @param {string} origin - The origin/domain to get the permitted accounts for.
* @returns {Array<string>} An empty array or an array of accounts.
*/
2020-11-03 00:41:28 +01:00
export function getPermittedAccounts(state, origin) {
return getAccountsFromPermission(
2020-11-03 00:41:28 +01:00
getAccountsPermissionFromDomain(domainSelector(state, origin)),
)
}
/**
* Selects the permitted accounts from the eth_accounts permission for the
* origin of the current tab.
*
* @param {Object} state - The current state.
* @returns {Array<string>} An empty array or an array of accounts.
*/
2020-11-03 00:41:28 +01:00
export function getPermittedAccountsForCurrentTab(state) {
return getPermittedAccounts(state, getOriginOfCurrentTab(state))
}
/**
* Returns a map of permitted accounts by origin for all origins.
*
* @param {Object} state - The current state.
* @returns {Object} Permitted accounts by origin.
*/
2020-11-03 00:41:28 +01:00
export function getPermittedAccountsByOrigin(state) {
2020-05-02 21:41:17 +02:00
const domains = getPermissionDomains(state)
return Object.keys(domains).reduce((acc, domainKey) => {
const accounts = getAccountsFromPermission(
getAccountsPermissionFromDomain(domains[domainKey]),
)
if (accounts.length > 0) {
acc[domainKey] = accounts
}
return acc
}, {})
}
/**
* Returns an array of connected domain objects, with the following properties:
* - extensionId
* - key (i.e. origin)
* - name
* - icon
*
* @param {Object} state - The current state.
* @returns {Array<Object>} An array of connected domain objects.
*/
2020-11-03 00:41:28 +01:00
export function getConnectedDomainsForSelectedAddress(state) {
const { selectedAddress } = state.metamask
2020-05-02 21:41:17 +02:00
const domains = getPermissionDomains(state)
const domainMetadata = getPermissionDomainsMetadata(state)
const connectedDomains = []
forOwn(domains, (domainValue, domainKey) => {
const exposedAccounts = getAccountsFromDomain(domainValue)
if (!exposedAccounts.includes(selectedAddress)) {
return
}
2020-11-03 00:41:28 +01:00
const { extensionId, name, icon, host } = domainMetadata[domainKey] || {}
2020-05-02 21:41:17 +02:00
connectedDomains.push({
extensionId,
origin: domainKey,
2020-05-02 21:41:17 +02:00
name,
icon,
host,
2020-05-02 21:41:17 +02:00
})
})
return connectedDomains
}
/**
* Returns an object mapping addresses to objects mapping origins to connected
* domain info. Domain info objects have the following properties:
* - icon
* - name
*
* @param {Object} state - The current state.
* @returns {Object} A mapping of addresses to a mapping of origins to
* connected domain info.
*/
2020-11-03 00:41:28 +01:00
export function getAddressConnectedDomainMap(state) {
2020-05-02 21:41:17 +02:00
const domainMetadata = getPermissionDomainsMetadata(state)
const accountsMap = getPermittedAccountsByOrigin(state)
const addressConnectedIconMap = {}
Object.keys(accountsMap).forEach((domainKey) => {
const { icon, name } = domainMetadata[domainKey] || {}
accountsMap[domainKey].forEach((address) => {
const nameToRender = name || domainKey
addressConnectedIconMap[address] = addressConnectedIconMap[address]
2020-11-03 00:41:28 +01:00
? {
...addressConnectedIconMap[address],
[domainKey]: { icon, name: nameToRender },
}
2020-05-02 21:41:17 +02:00
: { [domainKey]: { icon, name: nameToRender } }
})
})
return addressConnectedIconMap
}
// selector helpers
2020-11-03 00:41:28 +01:00
function getAccountsFromDomain(domain) {
return getAccountsFromPermission(getAccountsPermissionFromDomain(domain))
2020-05-02 21:41:17 +02:00
}
2020-11-03 00:41:28 +01:00
function getAccountsPermissionFromDomain(domain = {}) {
return Array.isArray(domain.permissions)
? domain.permissions.find(
(perm) => perm.parentCapability === 'eth_accounts',
)
2020-11-03 00:41:28 +01:00
: {}
}
2020-11-03 00:41:28 +01:00
function getAccountsFromPermission(accountsPermission) {
const accountsCaveat = getAccountsCaveatFromPermission(accountsPermission)
2020-11-03 00:41:28 +01:00
return accountsCaveat && Array.isArray(accountsCaveat.value)
? accountsCaveat.value
: []
}
2020-11-03 00:41:28 +01:00
function getAccountsCaveatFromPermission(accountsPermission = {}) {
return (
Array.isArray(accountsPermission.caveats) &&
accountsPermission.caveats.find(
(c) => c.name === CAVEAT_NAMES.exposedAccounts,
)
)
}
2020-11-03 00:41:28 +01:00
function domainSelector(state, origin) {
return origin && state.metamask.domains?.[origin]
}
2020-05-15 20:53:52 +02:00
2020-11-03 00:41:28 +01:00
export function getAccountToConnectToActiveTab(state) {
2020-05-15 20:53:52 +02:00
const selectedAddress = getSelectedAddress(state)
const connectedAccounts = getPermittedAccountsForCurrentTab(state)
2020-11-03 00:41:28 +01:00
const {
metamask: { identities },
} = state
2020-05-15 20:53:52 +02:00
const numberOfAccounts = Object.keys(identities).length
2020-11-03 00:41:28 +01:00
if (
connectedAccounts.length &&
connectedAccounts.length !== numberOfAccounts
) {
if (
connectedAccounts.findIndex((address) => address === selectedAddress) ===
-1
) {
2020-05-15 20:53:52 +02:00
return identities[selectedAddress]
}
}
return undefined
}
2020-11-03 00:41:28 +01:00
export function getOrderedConnectedAccountsForActiveTab(state) {
const {
activeTab,
metamask: { permissionsHistory },
} = state
2020-05-15 20:53:52 +02:00
2020-11-03 00:41:28 +01:00
const permissionsHistoryByAccount =
// eslint-disable-next-line camelcase
2020-11-03 00:41:28 +01:00
permissionsHistory[activeTab.origin]?.eth_accounts?.accounts
const orderedAccounts = getMetaMaskAccountsOrdered(state)
const connectedAccounts = getPermittedAccountsForCurrentTab(state)
2020-05-15 20:53:52 +02:00
return orderedAccounts
.filter((account) => connectedAccounts.includes(account.address))
.map((account) => ({
...account,
lastActive: permissionsHistoryByAccount?.[account.address],
2020-05-15 20:53:52 +02:00
}))
2020-11-03 00:41:28 +01:00
.sort(
({ lastSelected: lastSelectedA }, { lastSelected: lastSelectedB }) => {
if (lastSelectedA === lastSelectedB) {
return 0
} else if (lastSelectedA === undefined) {
return 1
} else if (lastSelectedB === undefined) {
return -1
}
return lastSelectedB - lastSelectedA
},
)
2020-05-15 20:53:52 +02:00
}
2020-11-03 00:41:28 +01:00
export function getPermissionsForActiveTab(state) {
2020-05-15 20:53:52 +02:00
const { activeTab, metamask } = state
2020-11-03 00:41:28 +01:00
const { domains = {} } = metamask
2020-05-15 20:53:52 +02:00
return domains[activeTab.origin]?.permissions?.map(({ parentCapability }) => {
return {
key: parentCapability,
}
})
}
2020-11-03 00:41:28 +01:00
export function getLastConnectedInfo(state) {
const { permissionsHistory = {} } = state.metamask
return Object.keys(permissionsHistory).reduce((acc, origin) => {
2020-11-03 00:41:28 +01:00
const ethAccountsHistory = JSON.parse(
JSON.stringify(permissionsHistory[origin].eth_accounts),
)
return {
...acc,
[origin]: ethAccountsHistory,
}
}, {})
}
2020-11-03 00:41:28 +01:00
export function getPermissionsMetadataHostCounts(state) {
const metadata = getPermissionDomainsMetadata(state)
return Object.values(metadata).reduce((counts, { host }) => {
if (host) {
if (counts[host]) {
counts[host] += 1
} else {
counts[host] = 1
}
}
return counts
}, {})
}
2020-11-03 00:41:28 +01:00
export function getPermissionsRequests(state) {
return state.metamask.permissionsRequests || []
}
2020-11-03 00:41:28 +01:00
export function getPermissionsRequestCount(state) {
const permissionsRequests = getPermissionsRequests(state)
return permissionsRequests.length
}
2020-11-03 00:41:28 +01:00
export function getFirstPermissionRequest(state) {
const requests = getPermissionsRequests(state)
return requests && requests[0] ? requests[0] : null
}