mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Remove selected address history (#8104)
* remove selected address history, account switching; fix perm selectors, bugs Co-Authored-By: Mark Stacey <markjstacey@gmail.com>
This commit is contained in:
parent
8d0a757ab5
commit
83da3db37b
@ -61,8 +61,6 @@ class PreferencesController {
|
|||||||
|
|
||||||
// ENS decentralized website resolution
|
// ENS decentralized website resolution
|
||||||
ipfsGateway: 'ipfs.dweb.link',
|
ipfsGateway: 'ipfs.dweb.link',
|
||||||
|
|
||||||
lastSelectedAddressByOrigin: {},
|
|
||||||
}, opts.initState)
|
}, opts.initState)
|
||||||
|
|
||||||
this.diagnostics = opts.diagnostics
|
this.diagnostics = opts.diagnostics
|
||||||
@ -371,56 +369,6 @@ class PreferencesController {
|
|||||||
return this.store.getState().selectedAddress
|
return this.store.getState().selectedAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the last selected address for the given origin.
|
|
||||||
*
|
|
||||||
* @param {string} origin - The origin for which the address was selected.
|
|
||||||
* @param {string} address - The new selected address.
|
|
||||||
*/
|
|
||||||
setLastSelectedAddress (origin, address) {
|
|
||||||
|
|
||||||
const { lastSelectedAddressByOrigin } = this.store.getState()
|
|
||||||
|
|
||||||
// only update state if it's necessary
|
|
||||||
if (lastSelectedAddressByOrigin[origin] !== address) {
|
|
||||||
lastSelectedAddressByOrigin[origin] = address
|
|
||||||
this.store.updateState({ lastSelectedAddressByOrigin })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the selected address history for the given origin.
|
|
||||||
*
|
|
||||||
* @param {Array<string>} origins - The origin to remove the last selected address for.
|
|
||||||
*/
|
|
||||||
removeLastSelectedAddressesFor (origins) {
|
|
||||||
|
|
||||||
if (
|
|
||||||
!Array.isArray(origins) ||
|
|
||||||
(origins.length > 0 && typeof origins[0] !== 'string')
|
|
||||||
) {
|
|
||||||
throw new Error('Expected array of strings')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (origins.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { lastSelectedAddressByOrigin } = this.store.getState()
|
|
||||||
|
|
||||||
origins.forEach((origin) => {
|
|
||||||
delete lastSelectedAddressByOrigin[origin]
|
|
||||||
})
|
|
||||||
this.store.updateState({ lastSelectedAddressByOrigin })
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the selected address history.
|
|
||||||
*/
|
|
||||||
clearLastSelectedAddressHistory () {
|
|
||||||
this.store.updateState({ lastSelectedAddressByOrigin: {} })
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains data about tokens users add to their account.
|
* Contains data about tokens users add to their account.
|
||||||
* @typedef {Object} AddedToken
|
* @typedef {Object} AddedToken
|
||||||
|
@ -499,8 +499,6 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
setPreference: nodeify(preferencesController.setPreference, preferencesController),
|
setPreference: nodeify(preferencesController.setPreference, preferencesController),
|
||||||
completeOnboarding: nodeify(preferencesController.completeOnboarding, preferencesController),
|
completeOnboarding: nodeify(preferencesController.completeOnboarding, preferencesController),
|
||||||
addKnownMethodData: nodeify(preferencesController.addKnownMethodData, preferencesController),
|
addKnownMethodData: nodeify(preferencesController.addKnownMethodData, preferencesController),
|
||||||
clearLastSelectedAddressHistory: nodeify(preferencesController.clearLastSelectedAddressHistory, preferencesController),
|
|
||||||
removeLastSelectedAddressesFor: nodeify(preferencesController.removeLastSelectedAddressesFor, preferencesController),
|
|
||||||
|
|
||||||
// BlacklistController
|
// BlacklistController
|
||||||
whitelistPhishingDomain: this.whitelistPhishingDomain.bind(this),
|
whitelistPhishingDomain: this.whitelistPhishingDomain.bind(this),
|
||||||
@ -1054,7 +1052,6 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
async handleNewAccountSelected (origin, address) {
|
async handleNewAccountSelected (origin, address) {
|
||||||
this.permissionsController.handleNewAccountSelected(origin, address)
|
this.permissionsController.handleNewAccountSelected(origin, address)
|
||||||
this.preferencesController.setLastSelectedAddress(origin, address)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -15,7 +15,6 @@ import {
|
|||||||
getMetaMaskKeyrings,
|
getMetaMaskKeyrings,
|
||||||
getOriginOfCurrentTab,
|
getOriginOfCurrentTab,
|
||||||
getSelectedAddress,
|
getSelectedAddress,
|
||||||
// getLastSelectedAddress,
|
|
||||||
// getPermittedAccounts,
|
// getPermittedAccounts,
|
||||||
} from '../../../selectors/selectors'
|
} from '../../../selectors/selectors'
|
||||||
import AccountMenu from './account-menu.component'
|
import AccountMenu from './account-menu.component'
|
||||||
@ -31,14 +30,6 @@ function mapStateToProps (state) {
|
|||||||
const origin = getOriginOfCurrentTab(state)
|
const origin = getOriginOfCurrentTab(state)
|
||||||
const selectedAddress = getSelectedAddress(state)
|
const selectedAddress = getSelectedAddress(state)
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO:LoginPerSite:ui
|
|
||||||
* - propagate the relevant props below after computing them
|
|
||||||
*/
|
|
||||||
// const lastSelectedAddress = getLastSelectedAddress(state, origin)
|
|
||||||
// const permittedAccounts = getPermittedAccounts(state, origin)
|
|
||||||
// const selectedAccountIsPermitted = permittedAccounts.includes(selectedAddress)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isAccountMenuOpen,
|
isAccountMenuOpen,
|
||||||
addressConnectedDomainMap: getAddressConnectedDomainMap(state),
|
addressConnectedDomainMap: getAddressConnectedDomainMap(state),
|
||||||
|
@ -9,19 +9,19 @@ import {
|
|||||||
import {
|
import {
|
||||||
getRenderablePermissionsDomains,
|
getRenderablePermissionsDomains,
|
||||||
getPermissionsDomains,
|
getPermissionsDomains,
|
||||||
getAddressConnectedToCurrentTab,
|
|
||||||
getSelectedAddress,
|
getSelectedAddress,
|
||||||
|
getPermittedAccountsForCurrentTab,
|
||||||
} from '../../../selectors/selectors'
|
} from '../../../selectors/selectors'
|
||||||
import { getOriginFromUrl } from '../../../helpers/utils/util'
|
import { getOriginFromUrl } from '../../../helpers/utils/util'
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
const addressConnectedToCurrentTab = getAddressConnectedToCurrentTab(state)
|
|
||||||
const { openMetaMaskTabs } = state.appState
|
const { openMetaMaskTabs } = state.appState
|
||||||
const { title, url, id } = state.activeTab
|
const { title, url, id } = state.activeTab
|
||||||
|
const permittedAccounts = getPermittedAccountsForCurrentTab(state)
|
||||||
|
|
||||||
let tabToConnect
|
let tabToConnect
|
||||||
|
|
||||||
if (!addressConnectedToCurrentTab && url && !openMetaMaskTabs[id]) {
|
if (url && permittedAccounts.length === 0 && !openMetaMaskTabs[id]) {
|
||||||
tabToConnect = {
|
tabToConnect = {
|
||||||
title,
|
title,
|
||||||
origin: getOriginFromUrl(url),
|
origin: getOriginFromUrl(url),
|
||||||
|
@ -10,7 +10,6 @@ import {
|
|||||||
getNetworkIdentifier,
|
getNetworkIdentifier,
|
||||||
preferencesSelector,
|
preferencesSelector,
|
||||||
hasPermissionRequests,
|
hasPermissionRequests,
|
||||||
getAddressConnectedToCurrentTab,
|
|
||||||
} from '../../selectors/selectors'
|
} from '../../selectors/selectors'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
@ -109,20 +108,6 @@ class Routes extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
const { addressConnectedToCurrentTab, showAccountDetail, selectedAddress } = this.props
|
|
||||||
if (addressConnectedToCurrentTab && addressConnectedToCurrentTab !== selectedAddress) {
|
|
||||||
showAccountDetail(addressConnectedToCurrentTab)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
|
||||||
const { addressConnectedToCurrentTab, showAccountDetail } = this.props
|
|
||||||
if (addressConnectedToCurrentTab && addressConnectedToCurrentTab !== prevProps.addressConnectedToCurrentTab) {
|
|
||||||
showAccountDetail(addressConnectedToCurrentTab)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRoutes () {
|
renderRoutes () {
|
||||||
const { autoLockTimeLimit, setLastActiveTime } = this.props
|
const { autoLockTimeLimit, setLastActiveTime } = this.props
|
||||||
|
|
||||||
@ -363,7 +348,6 @@ Routes.propTypes = {
|
|||||||
textDirection: PropTypes.string,
|
textDirection: PropTypes.string,
|
||||||
network: PropTypes.string,
|
network: PropTypes.string,
|
||||||
provider: PropTypes.object,
|
provider: PropTypes.object,
|
||||||
selectedAddress: PropTypes.string,
|
|
||||||
frequentRpcListDetail: PropTypes.array,
|
frequentRpcListDetail: PropTypes.array,
|
||||||
sidebar: PropTypes.object,
|
sidebar: PropTypes.object,
|
||||||
alertOpen: PropTypes.bool,
|
alertOpen: PropTypes.bool,
|
||||||
@ -379,12 +363,6 @@ Routes.propTypes = {
|
|||||||
providerId: PropTypes.string,
|
providerId: PropTypes.string,
|
||||||
hasPermissionsRequests: PropTypes.bool,
|
hasPermissionsRequests: PropTypes.bool,
|
||||||
autoLockTimeLimit: PropTypes.number,
|
autoLockTimeLimit: PropTypes.number,
|
||||||
addressConnectedToCurrentTab: PropTypes.string,
|
|
||||||
showAccountDetail: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
Routes.defaultProps = {
|
|
||||||
selectedAddress: undefined,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
@ -418,7 +396,6 @@ function mapStateToProps (state) {
|
|||||||
providerId: getNetworkIdentifier(state),
|
providerId: getNetworkIdentifier(state),
|
||||||
autoLockTimeLimit,
|
autoLockTimeLimit,
|
||||||
hasPermissionsRequests: hasPermissionRequests(state),
|
hasPermissionsRequests: hasPermissionRequests(state),
|
||||||
addressConnectedToCurrentTab: getAddressConnectedToCurrentTab(state),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export { default } from './send-dropdown-list.component'
|
|
@ -1,56 +0,0 @@
|
|||||||
import React, { Component } from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import AccountListItem from '../../account-list-item'
|
|
||||||
|
|
||||||
export default class SendDropdownList extends Component {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
accounts: PropTypes.array,
|
|
||||||
closeDropdown: PropTypes.func,
|
|
||||||
onSelect: PropTypes.func,
|
|
||||||
activeAddress: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
getListItemIcon (accountAddress, activeAddress) {
|
|
||||||
return accountAddress === activeAddress
|
|
||||||
? <i className="fa fa-check fa-lg" style={ { color: '#02c9b1' } } />
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const {
|
|
||||||
accounts,
|
|
||||||
closeDropdown,
|
|
||||||
onSelect,
|
|
||||||
activeAddress,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className="send-v2__from-dropdown__close-area"
|
|
||||||
onClick={() => closeDropdown()}
|
|
||||||
/>
|
|
||||||
<div className="send-v2__from-dropdown__list">
|
|
||||||
{accounts.map((account, index) => (
|
|
||||||
<AccountListItem
|
|
||||||
account={account}
|
|
||||||
className="account-list-item__dropdown"
|
|
||||||
handleClick={() => {
|
|
||||||
onSelect(account)
|
|
||||||
closeDropdown()
|
|
||||||
}}
|
|
||||||
icon={this.getListItemIcon(account.address, activeAddress)}
|
|
||||||
key={`send-dropdown-account-#${index}`}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import assert from 'assert'
|
|
||||||
import { shallow } from 'enzyme'
|
|
||||||
import sinon from 'sinon'
|
|
||||||
import SendDropdownList from '../send-dropdown-list.component.js'
|
|
||||||
import AccountListItem from '../../../account-list-item/account-list-item.container'
|
|
||||||
|
|
||||||
describe('SendDropdownList Component', function () {
|
|
||||||
let wrapper
|
|
||||||
|
|
||||||
const propsMethodSpies = {
|
|
||||||
closeDropdown: sinon.spy(),
|
|
||||||
onSelect: sinon.spy(),
|
|
||||||
}
|
|
||||||
|
|
||||||
before(function () {
|
|
||||||
sinon.spy(SendDropdownList.prototype, 'getListItemIcon')
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
wrapper = shallow((
|
|
||||||
<SendDropdownList
|
|
||||||
accounts={[
|
|
||||||
{ address: 'mockAccount0' },
|
|
||||||
{ address: 'mockAccount1' },
|
|
||||||
{ address: 'mockAccount2' },
|
|
||||||
]}
|
|
||||||
closeDropdown={propsMethodSpies.closeDropdown}
|
|
||||||
onSelect={propsMethodSpies.onSelect}
|
|
||||||
activeAddress="mockAddress2"
|
|
||||||
/>
|
|
||||||
), { context: { t: (str) => str + '_t' } })
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
propsMethodSpies.closeDropdown.resetHistory()
|
|
||||||
propsMethodSpies.onSelect.resetHistory()
|
|
||||||
SendDropdownList.prototype.getListItemIcon.resetHistory()
|
|
||||||
})
|
|
||||||
|
|
||||||
after(function () {
|
|
||||||
sinon.restore()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('getListItemIcon', function () {
|
|
||||||
it('should return check icon if the passed addresses are the same', function () {
|
|
||||||
assert.deepEqual(
|
|
||||||
wrapper.instance().getListItemIcon('mockAccount0', 'mockAccount0'),
|
|
||||||
<i className="fa fa-check fa-lg" style={ { color: '#02c9b1' } } />
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return null if the passed addresses are different', function () {
|
|
||||||
assert.equal(
|
|
||||||
wrapper.instance().getListItemIcon('mockAccount0', 'mockAccount1'),
|
|
||||||
null
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('render', function () {
|
|
||||||
it('should render a single div with two children', function () {
|
|
||||||
assert(wrapper.is('div'))
|
|
||||||
assert.equal(wrapper.children().length, 2)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render the children with the correct classes', function () {
|
|
||||||
assert(wrapper.childAt(0).hasClass('send-v2__from-dropdown__close-area'))
|
|
||||||
assert(wrapper.childAt(1).hasClass('send-v2__from-dropdown__list'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should call closeDropdown onClick of the send-v2__from-dropdown__close-area', function () {
|
|
||||||
assert.equal(propsMethodSpies.closeDropdown.callCount, 0)
|
|
||||||
wrapper.childAt(0).props().onClick()
|
|
||||||
assert.equal(propsMethodSpies.closeDropdown.callCount, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render an AccountListItem for each item in accounts', function () {
|
|
||||||
assert.equal(wrapper.childAt(1).children().length, 3)
|
|
||||||
assert(wrapper.childAt(1).children().every(AccountListItem))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should pass the correct props to the AccountListItem', function () {
|
|
||||||
wrapper.childAt(1).children().forEach((accountListItem, index) => {
|
|
||||||
const {
|
|
||||||
account,
|
|
||||||
className,
|
|
||||||
handleClick,
|
|
||||||
} = accountListItem.props()
|
|
||||||
assert.deepEqual(account, { address: 'mockAccount' + index })
|
|
||||||
assert.equal(className, 'account-list-item__dropdown')
|
|
||||||
assert.equal(propsMethodSpies.onSelect.callCount, 0)
|
|
||||||
handleClick()
|
|
||||||
assert.equal(propsMethodSpies.onSelect.callCount, 1)
|
|
||||||
assert.deepEqual(propsMethodSpies.onSelect.getCall(0).args[0], { address: 'mockAccount' + index })
|
|
||||||
propsMethodSpies.onSelect.resetHistory()
|
|
||||||
propsMethodSpies.closeDropdown.resetHistory()
|
|
||||||
assert.equal(propsMethodSpies.closeDropdown.callCount, 0)
|
|
||||||
handleClick()
|
|
||||||
assert.equal(propsMethodSpies.closeDropdown.callCount, 1)
|
|
||||||
propsMethodSpies.onSelect.resetHistory()
|
|
||||||
propsMethodSpies.closeDropdown.resetHistory()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should call this.getListItemIcon for each AccountListItem', function () {
|
|
||||||
assert.equal(SendDropdownList.prototype.getListItemIcon.callCount, 3)
|
|
||||||
const getListItemIconCalls = SendDropdownList.prototype.getListItemIcon.getCalls()
|
|
||||||
assert(getListItemIconCalls.every(({ args }, index) => args[0] === 'mockAccount' + index))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1 +0,0 @@
|
|||||||
export { default } from './send-from-row.container'
|
|
@ -1,27 +0,0 @@
|
|||||||
import React, { Component } from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import SendRowWrapper from '../send-row-wrapper'
|
|
||||||
import AccountListItem from '../../account-list-item'
|
|
||||||
|
|
||||||
export default class SendFromRow extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
from: PropTypes.object,
|
|
||||||
}
|
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { t } = this.context
|
|
||||||
const { from } = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SendRowWrapper label={`${t('from')}:`}>
|
|
||||||
<div className="send-v2__from-dropdown">
|
|
||||||
<AccountListItem account={from} />
|
|
||||||
</div>
|
|
||||||
</SendRowWrapper>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { connect } from 'react-redux'
|
|
||||||
import { getSendFromObject } from '../../send.selectors.js'
|
|
||||||
import SendFromRow from './send-from-row.component'
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
|
||||||
return {
|
|
||||||
from: getSendFromObject(state),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(SendFromRow)
|
|
@ -1,31 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import assert from 'assert'
|
|
||||||
import { shallow } from 'enzyme'
|
|
||||||
import SendFromRow from '../send-from-row.component.js'
|
|
||||||
import AccountListItem from '../../../account-list-item'
|
|
||||||
import SendRowWrapper from '../../send-row-wrapper/send-row-wrapper.component'
|
|
||||||
|
|
||||||
describe('SendFromRow Component', function () {
|
|
||||||
describe('render', function () {
|
|
||||||
const wrapper = shallow(
|
|
||||||
<SendFromRow
|
|
||||||
from={ { address: 'mockAddress' } }
|
|
||||||
/>,
|
|
||||||
{ context: { t: (str) => str + '_t' } }
|
|
||||||
)
|
|
||||||
|
|
||||||
it('should render a SendRowWrapper component', function () {
|
|
||||||
assert.equal(wrapper.find(SendRowWrapper).length, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should pass the correct props to SendRowWrapper', function () {
|
|
||||||
const { label } = wrapper.find(SendRowWrapper).props()
|
|
||||||
assert.equal(label, 'from_t:')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render the FromDropdown with the correct props', function () {
|
|
||||||
const { account } = wrapper.find(AccountListItem).props()
|
|
||||||
assert.deepEqual(account, { address: 'mockAddress' })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,26 +0,0 @@
|
|||||||
import assert from 'assert'
|
|
||||||
import proxyquire from 'proxyquire'
|
|
||||||
|
|
||||||
let mapStateToProps
|
|
||||||
|
|
||||||
proxyquire('../send-from-row.container.js', {
|
|
||||||
'react-redux': {
|
|
||||||
connect: (ms) => {
|
|
||||||
mapStateToProps = ms
|
|
||||||
return () => ({})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'../../send.selectors.js': {
|
|
||||||
getSendFromObject: (s) => `mockFrom:${s}`,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('send-from-row container', function () {
|
|
||||||
describe('mapStateToProps()', function () {
|
|
||||||
it('should map the correct properties to props', function () {
|
|
||||||
assert.deepEqual(mapStateToProps('mockState'), {
|
|
||||||
from: 'mockFrom:mockState',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,48 +1,80 @@
|
|||||||
|
|
||||||
import { createSelector } from 'reselect'
|
import { createSelector } from 'reselect'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CAVEAT_NAMES,
|
CAVEAT_NAMES,
|
||||||
} from '../../../app/scripts/controllers/permissions/enums'
|
} from '../../../app/scripts/controllers/permissions/enums'
|
||||||
|
|
||||||
const permissionsSelector = (state, origin) => {
|
// selectors
|
||||||
return origin && state.metamask.domains && state.metamask.domains[origin]
|
|
||||||
}
|
|
||||||
|
|
||||||
// all permissions for the origin probably too expensive for deep equality check
|
|
||||||
const accountsPermissionSelector = createSelector(
|
|
||||||
permissionsSelector,
|
|
||||||
(domain = {}) => {
|
|
||||||
|
|
||||||
return (
|
|
||||||
Array.isArray(domain.permissions)
|
|
||||||
? domain.permissions.find(
|
|
||||||
(perm) => perm.parentCapability === 'eth_accounts'
|
|
||||||
)
|
|
||||||
: {}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the permitted accounts from an eth_accounts permission.
|
* Selects the permitted accounts from the eth_accounts permission given state
|
||||||
* Expects input from accountsPermissionsSelector.
|
* and an origin.
|
||||||
* @returns - An empty array or an array of accounts.
|
* @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.
|
||||||
*/
|
*/
|
||||||
export const getPermittedAccounts = createSelector(
|
export function getPermittedAccounts (state, origin) {
|
||||||
accountsPermissionSelector, // deep equal check performed on this output
|
return getAccountsFromPermission(
|
||||||
(accountsPermission = {}) => {
|
getAccountsPermissionFromDomain(
|
||||||
|
domainSelector(state, origin)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const accountsCaveat = (
|
/**
|
||||||
Array.isArray(accountsPermission.caveats) &&
|
* Returns a map of permitted accounts by origin for all origins.
|
||||||
accountsPermission.caveats.find(
|
* @param {Object} state - The current state.
|
||||||
(c) => c.name === CAVEAT_NAMES.exposedAccounts
|
* @returns {Object} Permitted accounts by origin.
|
||||||
|
*/
|
||||||
|
export const getPermittedAccountsMap = createSelector(
|
||||||
|
allDomainsSelector,
|
||||||
|
(domains = {}) => {
|
||||||
|
return Object.keys(domains).reduce((acc, domainKey) => {
|
||||||
|
const accounts = getAccountsFromPermission(
|
||||||
|
getAccountsPermissionFromDomain(domains[domainKey])
|
||||||
)
|
)
|
||||||
)
|
if (accounts.length > 0) {
|
||||||
|
acc[domainKey] = accounts
|
||||||
return (
|
}
|
||||||
accountsCaveat && Array.isArray(accountsCaveat.value)
|
return acc
|
||||||
? accountsCaveat.value
|
}, {})
|
||||||
: []
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// selector helpers
|
||||||
|
|
||||||
|
function getAccountsPermissionFromDomain (domain = {}) {
|
||||||
|
return (
|
||||||
|
Array.isArray(domain.permissions)
|
||||||
|
? domain.permissions.find(
|
||||||
|
(perm) => perm.parentCapability === 'eth_accounts'
|
||||||
|
)
|
||||||
|
: {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccountsFromPermission (accountsPermission) {
|
||||||
|
const accountsCaveat = getAccountsCaveatFromPermission(accountsPermission)
|
||||||
|
return (
|
||||||
|
accountsCaveat && Array.isArray(accountsCaveat.value)
|
||||||
|
? accountsCaveat.value
|
||||||
|
: []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccountsCaveatFromPermission (accountsPermission = {}) {
|
||||||
|
return (
|
||||||
|
Array.isArray(accountsPermission.caveats) &&
|
||||||
|
accountsPermission.caveats.find(
|
||||||
|
(c) => c.name === CAVEAT_NAMES.exposedAccounts
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function allDomainsSelector (state) {
|
||||||
|
return state.metamask.domains
|
||||||
|
}
|
||||||
|
|
||||||
|
function domainSelector (state, origin) {
|
||||||
|
return origin && state.metamask.domains && state.metamask.domains[origin]
|
||||||
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { NETWORK_TYPES } from '../helpers/constants/common'
|
import { NETWORK_TYPES } from '../helpers/constants/common'
|
||||||
import { mapObjectValues } from '../../../app/scripts/lib/util'
|
|
||||||
import { stripHexPrefix, addHexPrefix } from 'ethereumjs-util'
|
import { stripHexPrefix, addHexPrefix } from 'ethereumjs-util'
|
||||||
import { createSelector } from 'reselect'
|
import { createSelector } from 'reselect'
|
||||||
|
|
||||||
@ -12,7 +11,7 @@ import {
|
|||||||
getOriginFromUrl,
|
getOriginFromUrl,
|
||||||
} from '../helpers/utils/util'
|
} from '../helpers/utils/util'
|
||||||
|
|
||||||
import { getPermittedAccounts } from './permissions'
|
import { getPermittedAccountsMap } from './permissions'
|
||||||
|
|
||||||
export { getPermittedAccounts } from './permissions'
|
export { getPermittedAccounts } from './permissions'
|
||||||
|
|
||||||
@ -91,21 +90,6 @@ export function getSelectedAddress (state) {
|
|||||||
return selectedAddress
|
return selectedAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
function lastSelectedAddressSelector (state, origin) {
|
|
||||||
return state.metamask.lastSelectedAddressByOrigin[origin] || null
|
|
||||||
}
|
|
||||||
|
|
||||||
// not using reselect here since the returns are contingent;
|
|
||||||
// we have no reasons to recompute the permitted accounts if there
|
|
||||||
// exists a lastSelectedAddress
|
|
||||||
export function getLastSelectedAddress (state, origin) {
|
|
||||||
return (
|
|
||||||
lastSelectedAddressSelector(state, origin) ||
|
|
||||||
getPermittedAccounts(state, origin)[0] || // always returns array
|
|
||||||
getSelectedAddress(state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSelectedIdentity (state) {
|
export function getSelectedIdentity (state) {
|
||||||
const selectedAddress = getSelectedAddress(state)
|
const selectedAddress = getSelectedAddress(state)
|
||||||
const identities = state.metamask.identities
|
const identities = state.metamask.identities
|
||||||
@ -434,60 +418,29 @@ export function getPermissionsDomains (state) {
|
|||||||
|
|
||||||
export function getAddressConnectedDomainMap (state) {
|
export function getAddressConnectedDomainMap (state) {
|
||||||
const {
|
const {
|
||||||
domains,
|
|
||||||
domainMetadata,
|
domainMetadata,
|
||||||
} = state.metamask
|
} = state.metamask
|
||||||
|
|
||||||
|
const accountsMap = getPermittedAccountsMap(state)
|
||||||
const addressConnectedIconMap = {}
|
const addressConnectedIconMap = {}
|
||||||
|
|
||||||
if (domains) {
|
Object.keys(accountsMap).forEach((domainKey) => {
|
||||||
Object.keys(domains).forEach((domainKey) => {
|
const { icon, name } = domainMetadata[domainKey] || {}
|
||||||
const { permissions } = domains[domainKey]
|
accountsMap[domainKey].forEach((address) => {
|
||||||
const { icon, name } = domainMetadata[domainKey] || {}
|
const nameToRender = name || domainKey
|
||||||
permissions.forEach((perm) => {
|
addressConnectedIconMap[address] = addressConnectedIconMap[address]
|
||||||
const caveats = perm.caveats || []
|
? { ...addressConnectedIconMap[address], [domainKey]: { icon, name: nameToRender } }
|
||||||
const exposedAccountCaveat = caveats.find((caveat) => caveat.name === 'exposedAccounts')
|
: { [domainKey]: { icon, name: nameToRender } }
|
||||||
if (exposedAccountCaveat && exposedAccountCaveat.value && exposedAccountCaveat.value.length) {
|
|
||||||
exposedAccountCaveat.value.forEach((address) => {
|
|
||||||
const nameToRender = name || domainKey
|
|
||||||
addressConnectedIconMap[address] = addressConnectedIconMap[address]
|
|
||||||
? { ...addressConnectedIconMap[address], [domainKey]: { icon, name: nameToRender } }
|
|
||||||
: { [domainKey]: { icon, name: nameToRender } }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
return addressConnectedIconMap
|
return addressConnectedIconMap
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDomainToConnectedAddressMap (state) {
|
export function getPermittedAccountsForCurrentTab (state) {
|
||||||
const { domains = {} } = state.metamask
|
const permittedAccountsMap = getPermittedAccountsMap(state)
|
||||||
|
|
||||||
const domainToConnectedAddressMap = mapObjectValues(domains, (_, { permissions }) => {
|
|
||||||
const ethAccountsPermissions = permissions.filter((permission) => permission.parentCapability === 'eth_accounts')
|
|
||||||
const ethAccountsPermissionsExposedAccountAddresses = ethAccountsPermissions.map((permission) => {
|
|
||||||
const caveats = permission.caveats
|
|
||||||
const exposedAccountsCaveats = caveats.filter((caveat) => caveat.name === 'exposedAccounts')
|
|
||||||
const exposedAccountsAddresses = exposedAccountsCaveats.map((caveat) => caveat.value[0])
|
|
||||||
return exposedAccountsAddresses
|
|
||||||
})
|
|
||||||
const allAddressesConnectedToDomain = ethAccountsPermissionsExposedAccountAddresses.reduce((acc, arrayOfAddresses) => {
|
|
||||||
return [ ...acc, ...arrayOfAddresses ]
|
|
||||||
}, [])
|
|
||||||
return allAddressesConnectedToDomain
|
|
||||||
})
|
|
||||||
|
|
||||||
return domainToConnectedAddressMap
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAddressConnectedToCurrentTab (state) {
|
|
||||||
const domainToConnectedAddressMap = getDomainToConnectedAddressMap(state)
|
|
||||||
const originOfCurrentTab = getOriginOfCurrentTab(state)
|
const originOfCurrentTab = getOriginOfCurrentTab(state)
|
||||||
const addressesConnectedToCurrentTab = domainToConnectedAddressMap[originOfCurrentTab]
|
return permittedAccountsMap[originOfCurrentTab] || []
|
||||||
const addressConnectedToCurrentTab = addressesConnectedToCurrentTab && addressesConnectedToCurrentTab[0]
|
|
||||||
return addressConnectedToCurrentTab
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRenderablePermissionsDomains (state) {
|
export function getRenderablePermissionsDomains (state) {
|
||||||
|
@ -2322,7 +2322,6 @@ export function legacyExposeAccounts (origin, accounts) {
|
|||||||
export function removePermissionsFor (domains) {
|
export function removePermissionsFor (domains) {
|
||||||
return () => {
|
return () => {
|
||||||
background.removePermissionsFor(domains)
|
background.removePermissionsFor(domains)
|
||||||
background.removeLastSelectedAddressesFor(Object.keys(domains))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2332,7 +2331,6 @@ export function removePermissionsFor (domains) {
|
|||||||
export function clearPermissions () {
|
export function clearPermissions () {
|
||||||
return () => {
|
return () => {
|
||||||
background.clearPermissions()
|
background.clearPermissions()
|
||||||
background.clearLastSelectedAddressHistory()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user