mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-27 21:00:13 +01:00
4ef908aeb2
This reverts commit f5265c24ab
.
Apparently it wasn't unnecessary after all. The Lock page served a few
different purposes. First, it was used to safeguard the seed phrase, in
case the user was interrupted after setting a password. Otherwise
anyone could open MetaMask and see the seed phrase without verifying
the password. Second, the submit function for the initialization unlock
screen also returned the seed phrase, so that it could be set in React
state for the confirmation step. Third, the submit function was also
responsible for navigating back to the seed phrase reveal page.
Removing the lock page had the effect of causing an infinite render
loop if onboarding was interrupted in the "Create" flow after setting
a password but before seed phrase confirmation. That redirect loop has
now been fixed.
387 lines
11 KiB
JavaScript
387 lines
11 KiB
JavaScript
import classnames from 'classnames'
|
|
import PropTypes from 'prop-types'
|
|
import React, { Component } from 'react'
|
|
import { matchPath, Route, Switch } from 'react-router-dom'
|
|
import IdleTimer from 'react-idle-timer'
|
|
|
|
import FirstTimeFlow from '../first-time-flow'
|
|
import SendTransactionScreen from '../send'
|
|
import Swaps from '../swaps'
|
|
import ConfirmTransaction from '../confirm-transaction'
|
|
import Sidebar from '../../components/app/sidebars'
|
|
import Home from '../home'
|
|
import Settings from '../settings'
|
|
import Authenticated from '../../helpers/higher-order-components/authenticated'
|
|
import Initialized from '../../helpers/higher-order-components/initialized'
|
|
import Lock from '../lock'
|
|
import PermissionsConnect from '../permissions-connect'
|
|
import RestoreVaultPage from '../keychains/restore-vault'
|
|
import RevealSeedConfirmation from '../keychains/reveal-seed'
|
|
import MobileSyncPage from '../mobile-sync'
|
|
import AddTokenPage from '../add-token'
|
|
import ConfirmAddTokenPage from '../confirm-add-token'
|
|
import ConfirmAddSuggestedTokenPage from '../confirm-add-suggested-token'
|
|
import CreateAccountPage from '../create-account'
|
|
import Loading from '../../components/ui/loading-screen'
|
|
import LoadingNetwork from '../../components/app/loading-network-screen'
|
|
import NetworkDropdown from '../../components/app/dropdowns/network-dropdown'
|
|
import AccountMenu from '../../components/app/account-menu'
|
|
import { Modal } from '../../components/app/modals'
|
|
import Alert from '../../components/ui/alert'
|
|
import AppHeader from '../../components/app/app-header'
|
|
import UnlockPage from '../unlock-page'
|
|
import Alerts from '../../components/app/alerts'
|
|
import Asset from '../asset'
|
|
|
|
import {
|
|
ADD_TOKEN_ROUTE,
|
|
ASSET_ROUTE,
|
|
CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE,
|
|
CONFIRM_ADD_TOKEN_ROUTE,
|
|
CONFIRM_TRANSACTION_ROUTE,
|
|
CONNECT_ROUTE,
|
|
DEFAULT_ROUTE,
|
|
INITIALIZE_ROUTE,
|
|
INITIALIZE_UNLOCK_ROUTE,
|
|
LOCK_ROUTE,
|
|
MOBILE_SYNC_ROUTE,
|
|
NEW_ACCOUNT_ROUTE,
|
|
RESTORE_VAULT_ROUTE,
|
|
REVEAL_SEED_ROUTE,
|
|
SEND_ROUTE,
|
|
SWAPS_ROUTE,
|
|
SETTINGS_ROUTE,
|
|
UNLOCK_ROUTE,
|
|
BUILD_QUOTE_ROUTE,
|
|
} from '../../helpers/constants/routes'
|
|
|
|
import {
|
|
ENVIRONMENT_TYPE_NOTIFICATION,
|
|
ENVIRONMENT_TYPE_POPUP,
|
|
} from '../../../../app/scripts/lib/enums'
|
|
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
|
|
import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction'
|
|
|
|
export default class Routes extends Component {
|
|
static propTypes = {
|
|
currentCurrency: PropTypes.string,
|
|
setCurrentCurrencyToUSD: PropTypes.func,
|
|
isLoading: PropTypes.bool,
|
|
loadingMessage: PropTypes.string,
|
|
alertMessage: PropTypes.string,
|
|
textDirection: PropTypes.string,
|
|
network: PropTypes.string,
|
|
provider: PropTypes.object,
|
|
frequentRpcListDetail: PropTypes.array,
|
|
sidebar: PropTypes.object,
|
|
alertOpen: PropTypes.bool,
|
|
hideSidebar: PropTypes.func,
|
|
isUnlocked: PropTypes.bool,
|
|
setLastActiveTime: PropTypes.func,
|
|
history: PropTypes.object,
|
|
location: PropTypes.object,
|
|
lockMetaMask: PropTypes.func,
|
|
submittedPendingTransactions: PropTypes.array,
|
|
isMouseUser: PropTypes.bool,
|
|
setMouseUserState: PropTypes.func,
|
|
providerId: PropTypes.string,
|
|
autoLockTimeLimit: PropTypes.number,
|
|
pageChanged: PropTypes.func.isRequired,
|
|
prepareToLeaveSwaps: PropTypes.func,
|
|
}
|
|
|
|
static contextTypes = {
|
|
t: PropTypes.func,
|
|
metricsEvent: PropTypes.func,
|
|
}
|
|
|
|
UNSAFE_componentWillMount() {
|
|
const { currentCurrency, pageChanged, setCurrentCurrencyToUSD } = this.props
|
|
|
|
if (!currentCurrency) {
|
|
setCurrentCurrencyToUSD()
|
|
}
|
|
|
|
this.props.history.listen((locationObj, action) => {
|
|
if (action === 'PUSH') {
|
|
pageChanged(locationObj.pathname)
|
|
}
|
|
})
|
|
}
|
|
|
|
renderRoutes() {
|
|
const { autoLockTimeLimit, setLastActiveTime } = this.props
|
|
|
|
const routes = (
|
|
<Switch>
|
|
<Route path={LOCK_ROUTE} component={Lock} exact />
|
|
<Route path={INITIALIZE_ROUTE} component={FirstTimeFlow} />
|
|
<Initialized path={UNLOCK_ROUTE} component={UnlockPage} exact />
|
|
<Initialized
|
|
path={RESTORE_VAULT_ROUTE}
|
|
component={RestoreVaultPage}
|
|
exact
|
|
/>
|
|
<Authenticated
|
|
path={REVEAL_SEED_ROUTE}
|
|
component={RevealSeedConfirmation}
|
|
exact
|
|
/>
|
|
<Authenticated
|
|
path={MOBILE_SYNC_ROUTE}
|
|
component={MobileSyncPage}
|
|
exact
|
|
/>
|
|
<Authenticated path={SETTINGS_ROUTE} component={Settings} />
|
|
<Authenticated
|
|
path={`${CONFIRM_TRANSACTION_ROUTE}/:id?`}
|
|
component={ConfirmTransaction}
|
|
/>
|
|
<Authenticated
|
|
path={SEND_ROUTE}
|
|
component={SendTransactionScreen}
|
|
exact
|
|
/>
|
|
<Authenticated path={SWAPS_ROUTE} component={Swaps} />
|
|
<Authenticated path={ADD_TOKEN_ROUTE} component={AddTokenPage} exact />
|
|
<Authenticated
|
|
path={CONFIRM_ADD_TOKEN_ROUTE}
|
|
component={ConfirmAddTokenPage}
|
|
exact
|
|
/>
|
|
<Authenticated
|
|
path={CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE}
|
|
component={ConfirmAddSuggestedTokenPage}
|
|
exact
|
|
/>
|
|
<Authenticated path={NEW_ACCOUNT_ROUTE} component={CreateAccountPage} />
|
|
<Authenticated
|
|
path={`${CONNECT_ROUTE}/:id`}
|
|
component={PermissionsConnect}
|
|
/>
|
|
<Authenticated path={`${ASSET_ROUTE}/:asset`} component={Asset} />
|
|
<Authenticated path={DEFAULT_ROUTE} component={Home} />
|
|
</Switch>
|
|
)
|
|
|
|
if (autoLockTimeLimit > 0) {
|
|
return (
|
|
<IdleTimer onAction={setLastActiveTime} throttle={1000}>
|
|
{routes}
|
|
</IdleTimer>
|
|
)
|
|
}
|
|
|
|
return routes
|
|
}
|
|
|
|
onInitializationUnlockPage() {
|
|
const { location } = this.props
|
|
return Boolean(
|
|
matchPath(location.pathname, {
|
|
path: INITIALIZE_UNLOCK_ROUTE,
|
|
exact: true,
|
|
}),
|
|
)
|
|
}
|
|
|
|
onConfirmPage() {
|
|
const { location } = this.props
|
|
return Boolean(
|
|
matchPath(location.pathname, {
|
|
path: CONFIRM_TRANSACTION_ROUTE,
|
|
exact: false,
|
|
}),
|
|
)
|
|
}
|
|
|
|
onSwapsPage() {
|
|
const { location } = this.props
|
|
return Boolean(
|
|
matchPath(location.pathname, { path: SWAPS_ROUTE, exact: false }),
|
|
)
|
|
}
|
|
|
|
onSwapsBuildQuotePage() {
|
|
const { location } = this.props
|
|
return Boolean(
|
|
matchPath(location.pathname, { path: BUILD_QUOTE_ROUTE, exact: false }),
|
|
)
|
|
}
|
|
|
|
hideAppHeader() {
|
|
const { location } = this.props
|
|
|
|
const isInitializing = Boolean(
|
|
matchPath(location.pathname, {
|
|
path: INITIALIZE_ROUTE,
|
|
exact: false,
|
|
}),
|
|
)
|
|
|
|
if (isInitializing && !this.onInitializationUnlockPage()) {
|
|
return true
|
|
}
|
|
|
|
const windowType = getEnvironmentType()
|
|
|
|
if (windowType === ENVIRONMENT_TYPE_NOTIFICATION) {
|
|
return true
|
|
}
|
|
|
|
if (windowType === ENVIRONMENT_TYPE_POPUP && this.onConfirmPage()) {
|
|
return true
|
|
}
|
|
|
|
const isHandlingPermissionsRequest = Boolean(
|
|
matchPath(location.pathname, {
|
|
path: CONNECT_ROUTE,
|
|
exact: false,
|
|
}),
|
|
)
|
|
|
|
return isHandlingPermissionsRequest
|
|
}
|
|
|
|
render() {
|
|
const {
|
|
isLoading,
|
|
isUnlocked,
|
|
alertMessage,
|
|
textDirection,
|
|
loadingMessage,
|
|
network,
|
|
provider,
|
|
frequentRpcListDetail,
|
|
setMouseUserState,
|
|
sidebar,
|
|
submittedPendingTransactions,
|
|
isMouseUser,
|
|
prepareToLeaveSwaps,
|
|
} = this.props
|
|
const isLoadingNetwork = network === 'loading'
|
|
const loadMessage =
|
|
loadingMessage || isLoadingNetwork
|
|
? this.getConnectingLabel(loadingMessage)
|
|
: null
|
|
|
|
const {
|
|
isOpen: sidebarIsOpen,
|
|
transitionName: sidebarTransitionName,
|
|
type: sidebarType,
|
|
props,
|
|
} = sidebar
|
|
const { transaction: sidebarTransaction } = props || {}
|
|
|
|
const sidebarShouldClose =
|
|
sidebarTransaction &&
|
|
!sidebarTransaction.status === TRANSACTION_STATUSES.FAILED &&
|
|
!submittedPendingTransactions.find(
|
|
({ id }) => id === sidebarTransaction.id,
|
|
)
|
|
|
|
return (
|
|
<div
|
|
className={classnames('app', { 'mouse-user-styles': isMouseUser })}
|
|
dir={textDirection}
|
|
onClick={() => setMouseUserState(true)}
|
|
onKeyDown={(e) => {
|
|
if (e.keyCode === 9) {
|
|
setMouseUserState(false)
|
|
}
|
|
}}
|
|
>
|
|
<Modal />
|
|
<Alert visible={this.props.alertOpen} msg={alertMessage} />
|
|
{!this.hideAppHeader() && (
|
|
<AppHeader
|
|
hideNetworkIndicator={this.onInitializationUnlockPage()}
|
|
disableNetworkIndicator={this.onSwapsPage()}
|
|
onClick={async () => {
|
|
if (this.onSwapsPage()) {
|
|
await prepareToLeaveSwaps()
|
|
}
|
|
}}
|
|
disabled={
|
|
this.onConfirmPage() ||
|
|
(this.onSwapsPage() && !this.onSwapsBuildQuotePage())
|
|
}
|
|
/>
|
|
)}
|
|
<Sidebar
|
|
sidebarOpen={sidebarIsOpen}
|
|
sidebarShouldClose={sidebarShouldClose}
|
|
hideSidebar={this.props.hideSidebar}
|
|
transitionName={sidebarTransitionName}
|
|
type={sidebarType}
|
|
sidebarProps={sidebar.props}
|
|
/>
|
|
<NetworkDropdown
|
|
provider={provider}
|
|
frequentRpcListDetail={frequentRpcListDetail}
|
|
/>
|
|
<AccountMenu />
|
|
<div className="main-container-wrapper">
|
|
{isLoading && <Loading loadingMessage={loadMessage} />}
|
|
{!isLoading && isLoadingNetwork && <LoadingNetwork />}
|
|
{this.renderRoutes()}
|
|
</div>
|
|
{isUnlocked ? <Alerts history={this.props.history} /> : null}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
toggleMetamaskActive() {
|
|
if (this.props.isUnlocked) {
|
|
// currently active: deactivate
|
|
this.props.lockMetaMask()
|
|
} else {
|
|
// currently inactive: redirect to password box
|
|
const passwordBox = document.querySelector('input[type=password]')
|
|
if (!passwordBox) {
|
|
return
|
|
}
|
|
passwordBox.focus()
|
|
}
|
|
}
|
|
|
|
getConnectingLabel(loadingMessage) {
|
|
if (loadingMessage) {
|
|
return loadingMessage
|
|
}
|
|
const { provider, providerId } = this.props
|
|
|
|
switch (provider.type) {
|
|
case 'mainnet':
|
|
return this.context.t('connectingToMainnet')
|
|
case 'ropsten':
|
|
return this.context.t('connectingToRopsten')
|
|
case 'kovan':
|
|
return this.context.t('connectingToKovan')
|
|
case 'rinkeby':
|
|
return this.context.t('connectingToRinkeby')
|
|
case 'goerli':
|
|
return this.context.t('connectingToGoerli')
|
|
default:
|
|
return this.context.t('connectingTo', [providerId])
|
|
}
|
|
}
|
|
|
|
getNetworkName() {
|
|
switch (this.props.provider.type) {
|
|
case 'mainnet':
|
|
return this.context.t('mainnet')
|
|
case 'ropsten':
|
|
return this.context.t('ropsten')
|
|
case 'kovan':
|
|
return this.context.t('kovan')
|
|
case 'rinkeby':
|
|
return this.context.t('rinkeby')
|
|
case 'goerli':
|
|
return this.context.t('goerli')
|
|
default:
|
|
return this.context.t('unknownNetwork')
|
|
}
|
|
}
|
|
}
|