Skip to content

Commit

Permalink
refactor: mf-5392 do not allow to bypass the guard (#10846)
Browse files Browse the repository at this point in the history
* refactor: mf-5392 do not allow to bypass the guard

* fix: don't use useEffect
  • Loading branch information
UncleBill committed Sep 25, 2023
1 parent a9176d5 commit 7b17f14
Show file tree
Hide file tree
Showing 21 changed files with 97 additions and 110 deletions.
6 changes: 3 additions & 3 deletions packages/mask/background/services/helper/popup-opener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ async function openOrUpdatePopupWindow(route: PopupRoutes, params: ParamMap) {
)
}

const noWalletUnlockNeeded: PopupRoutes[] = [PopupRoutes.PersonaSignRequest, PopupRoutes.Unlock, PopupRoutes.Personas]
const noWalletUnlockNeeded: PopupRoutes[] = [PopupRoutes.PersonaSignRequest, PopupRoutes.Personas]

export async function openPopupWindow<T extends PopupRoutes>(
route: T,
Expand All @@ -80,10 +80,10 @@ export async function openPopupWindow<T extends PopupRoutes>(
...params,
})
} else {
return openOrUpdatePopupWindow(PopupRoutes.Unlock, {
return openOrUpdatePopupWindow(PopupRoutes.Wallet, {
close_after_unlock: true,
from: urlcat(route, params as ParamMap),
} satisfies PopupRoutesParamsMap[PopupRoutes.Unlock])
} satisfies PopupRoutesParamsMap[PopupRoutes.Wallet])
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/mask/dashboard/pages/CreateMaskWallet/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function useContext() {
await resetWallets(password, isReset)
if (isLocked && password) await Services.Wallet.unlockWallet(password)
} else if (hasPassword && isLocked) {
await Services.Helper.openPopupWindow(PopupRoutes.Unlock, {})
await Services.Helper.openPopupWindow(PopupRoutes.Wallet, {})
return false
} else if (password && !hasPassword) {
await Services.Wallet.changePassword(getDefaultWalletPassword(), password)
Expand Down
34 changes: 15 additions & 19 deletions packages/mask/src/extension/popups/SSR-server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import type { PopupSSR_Props } from '../../../background/tasks/Cancellable/Popup
import { PersonaHomeUI } from './pages/Personas/Home/UI.js'
import { usePopupTheme } from '../../utils/theme/usePopupTheme.js'
import { PopupLayout } from './components/PopupLayout/index.js'
import { WalletLinkContext } from './components/Navigator/index.js'

const init = once(() =>
i18NextInstance.init().then(() => {
Expand Down Expand Up @@ -44,7 +43,6 @@ export async function render(props: PopupSSR_Props) {
return { html, css }
}

const walletLink = () => '#'
function PopupSSR(props: PopupSSR_Props) {
return (
// MaskUIRoot
Expand All @@ -54,23 +52,21 @@ function PopupSSR(props: PopupSSR_Props) {
useTheme={usePopupTheme}
CustomSnackbarOffsetY={0}
useMaskIconPalette={() => 'light'}>
<WalletLinkContext.Provider value={walletLink}>
<PopupLayout>
<PersonaHomeUI
accounts={props.accounts ?? EMPTY_LIST}
networks={props.networks}
onRestore={noop}
onCreatePersona={noop}
onConnect={noop}
onAccountClick={noop}
avatar={props.avatar}
publicKey={props.currentPublicKeyHex}
fingerprint={props.currentFingerPrint}
isEmpty={!props.hasPersona}
nickname={props.nickname}
/>
</PopupLayout>
</WalletLinkContext.Provider>
<PopupLayout>
<PersonaHomeUI
accounts={props.accounts ?? EMPTY_LIST}
networks={props.networks}
onRestore={noop}
onCreatePersona={noop}
onConnect={noop}
onAccountClick={noop}
avatar={props.avatar}
publicKey={props.currentPublicKeyHex}
fingerprint={props.currentFingerPrint}
isEmpty={!props.hasPersona}
nickname={props.nickname}
/>
</PopupLayout>
</MaskThemeProvider>
</StaticRouter>
</DisableShadowRootContext.Provider>
Expand Down
33 changes: 4 additions & 29 deletions packages/mask/src/extension/popups/components/Navigator/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
/// <reference types="react/canary" />
// ! This file is used during SSR. DO NOT import new files that does not work in SSR
import urlcat from 'urlcat'
import { createContext, memo, use, useContext, useMemo, useRef } from 'react'
import { memo, useContext } from 'react'
import { NavLink, type LinkProps } from 'react-router-dom'
import { BottomNavigationAction, Box, type BoxProps } from '@mui/material'
import { Icons } from '@masknet/icons'
import { makeStyles } from '@masknet/theme'
import { PopupRoutes } from '@masknet/shared-base'
import { useMessages, useWallet } from '@masknet/web3-hooks-base'
import { useHasPassword } from '../../hooks/index.js'
import { useWalletLockStatus } from '../../pages/Wallet/hooks/useWalletLockStatus.js'
import { useMessages } from '@masknet/web3-hooks-base'
import { HydrateFinished } from '../../../../utils/createNormalReactRoot.js'
import { useCurrentPersona } from '../../../../components/DataSource/useCurrentPersona.js'

const useStyle = makeStyles()((theme) => ({
container: {
Expand Down Expand Up @@ -42,17 +38,14 @@ const BottomNavLink = memo<LinkProps>(function BottomNavLink({ children, to }) {
const { classes } = useStyle()

return (
<NavLink to={to} className={({ isActive }) => (isActive && to !== '#' ? classes.selected : undefined)}>
<NavLink to={to} className={({ isActive }) => (isActive ? classes.selected : undefined)}>
{children}
</NavLink>
)
})

export const Navigator = memo(function Navigator({ className, ...rest }: BoxProps) {
const { classes, cx } = useStyle()
const walletLink = useRef(use(WalletLinkContext)).current()

const currentPersona = useCurrentPersona()

useContext(HydrateFinished)()
const messages = useMessages()
Expand All @@ -67,7 +60,7 @@ export const Navigator = memo(function Navigator({ className, ...rest }: BoxProp
className={classes.action}
/>
</BottomNavLink>
<BottomNavLink to={walletLink}>
<BottomNavLink to={PopupRoutes.Wallet}>
<BottomNavigationAction
tabIndex={-1}
showLabel={false}
Expand All @@ -94,21 +87,3 @@ export const Navigator = memo(function Navigator({ className, ...rest }: BoxProp
</Box>
)
})

export const WalletLinkContext = createContext(function useWalletLink() {
const wallet = useWallet()
const messages = useMessages()
const { isLocked, loading: lockStatusLoading } = useWalletLockStatus()
const { hasPassword, loading: hasPasswordLoading } = useHasPassword()
const walletPageLoading = lockStatusLoading || hasPasswordLoading
const walletLink = useMemo(() => {
if (walletPageLoading) return '#'
if (!wallet) return PopupRoutes.Wallet
if (!hasPassword) return PopupRoutes.SetPaymentPassword
if (isLocked)
return urlcat(PopupRoutes.Unlock, { from: messages.length ? PopupRoutes.ContractInteraction : undefined })
if (messages.length) return PopupRoutes.ContractInteraction
return PopupRoutes.Wallet
}, [wallet, walletPageLoading, isLocked, hasPassword, messages])
return walletLink
})
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ const useStyles = makeStyles()((theme) => ({
const PATTERNS = [
PopupRoutes.Personas,
PopupRoutes.Wallet,
PopupRoutes.Unlock,
PopupRoutes.SetPaymentPassword,
PopupRoutes.Friends,
PopupRoutes.Settings,
Expand Down
10 changes: 5 additions & 5 deletions packages/mask/src/extension/popups/hooks/useHasPassword.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useAsyncRetry } from 'react-use'
import { useEffect } from 'react'
import Services from '#services'
import { CrossIsolationMessages } from '@masknet/shared-base'
import { useQuery } from '@tanstack/react-query'

export function useHasPassword() {
const { value: hasPassword, loading, retry } = useAsyncRetry(Services.Wallet.hasPassword, [])
const { data: hasPassword, isLoading, refetch } = useQuery(['@@has-password'], Services.Wallet.hasPassword)

useEffect(() => {
return CrossIsolationMessages.events.passwordStatusUpdated.on(retry)
}, [retry])
return CrossIsolationMessages.events.passwordStatusUpdated.on(() => refetch())
}, [refetch])

return { hasPassword, loading }
return { hasPassword, loading: isLoading }
}
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export const PersonaHomeUI = memo<PersonaHomeUIProps>(
value === PopupHomeTabType.ConnectedWallets &&
hasPaymentPassword
) {
navigate(urlcat(PopupRoutes.Unlock, { from: PopupRoutes.Personas, goBack: true, popup: true }))
navigate(urlcat(PopupRoutes.Wallet, { from: PopupRoutes.Personas, goBack: true, popup: true }))
return
}
onChange(event, value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import { useWeb3UI, useWallets } from '@masknet/web3-hooks-base'
import { getRegisteredWeb3Networks, getRegisteredWeb3Providers } from '@masknet/plugin-infra'
import { Web3 } from '@masknet/web3-providers'
import type { Web3Helper } from '@masknet/web3-helpers'
import Services from '#services'
import { useTitle, PopupContext } from '../../../hooks/index.js'
import { useI18N } from '../../../../../utils/index.js'
import { useWalletLockStatus } from '../hooks/useWalletLockStatus.js'
import Services from '#services'

const useStyles = makeStyles()((theme) => ({
box: {
Expand Down Expand Up @@ -76,7 +76,7 @@ const ConnectWalletPage = memo(() => {
})

if (isLocked && !lockStatusLoading) {
navigate(urlcat(PopupRoutes.Unlock, { from: PopupRoutes.SelectWallet, goBack: true, popup: true }))
navigate(urlcat(PopupRoutes.Wallet, { from: PopupRoutes.SelectWallet, goBack: true, popup: true }))
return
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Services from '#services'
import { PopupRoutes } from '@masknet/shared-base'
import { ActionButton, makeStyles } from '@masknet/theme'
import { Box, Button, Typography } from '@mui/material'
import { memo, useCallback, useState } from 'react'
Expand Down Expand Up @@ -79,7 +78,7 @@ const ResetWallet = memo(function ResetWallet() {
const [answer, setAnswer] = useState('')
const disabled = answer !== 'RESET'

const onBack = useCallback(() => navigate(PopupRoutes.Unlock), [])
const onBack = useCallback(() => navigate(-1), [])

const onConfirm = useCallback(async () => {
// We don't reset existed wallets until recovery
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ const SetPaymentPassword = memo(function SetPaymentPassword() {
} else {
await Services.Wallet.setPassword(data.password)
}
queryClient.refetchQueries(['@@has-password'])
const hasPassword = await Services.Wallet.hasPassword()

if (hasPassword) {
queryClient.invalidateQueries(['@@has-password'])
const from = params.get('from')
showSnackbar(t('popups_wallet_set_payment_password_successfully'), { variant: 'success' })
CrossIsolationMessages.events.passwordStatusUpdated.sendToAll(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const SwitchWallet = memo(function SwitchWallet() {

const handleLock = useCallback(async () => {
await Services.Wallet.lockWallet()
navigate(PopupRoutes.Unlock)
navigate(PopupRoutes.Wallet)
}, [])

const action = (
Expand Down
12 changes: 5 additions & 7 deletions packages/mask/src/extension/popups/pages/Wallet/Unlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const useStyles = makeStyles()((theme) => ({
},
}))

const Unlock = memo(() => {
const Unlock = memo(function Unlock() {
const { t } = useI18N()
const { classes } = useStyles()
const [password, setPassword] = useState('')
Expand All @@ -65,12 +65,10 @@ const Unlock = memo(() => {
if (verified) {
if (close_after_unlock && !from) {
await Services.Helper.removePopupWindow()
} else {
const path = from
? urlcat(from, {
tab: from === PopupRoutes.Personas ? PopupHomeTabType.ConnectedWallets : undefined,
})
: PopupRoutes.Wallet
} else if (from) {
const path = urlcat(from, {
tab: from === PopupRoutes.Personas ? PopupHomeTabType.ConnectedWallets : undefined,
})
navigate(path, { replace: true })
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
import { PopupRoutes } from '@masknet/shared-base'
import { useWallet, useWallets } from '@masknet/web3-hooks-base'
import { memo } from 'react'
import { Outlet, useOutletContext } from 'react-router-dom'
import { Navigate, Outlet, useOutletContext } from 'react-router-dom'
import Unlock from '../Unlock/index.js'
import { WalletStartUp } from '../components/StartUp/index.js'
import { WalletSetupHeaderUI } from '../components/WalletHeader/WalletSetupHeaderUI.js'
import { WalletHeader } from '../components/WalletHeader/index.js'
import { useWalletLockStatus } from '../hooks/index.js'
import { useMessageGuard } from './useMessageGuard.js'
import { usePaymentPasswordGuard } from './usePaymentPasswordGuard.js'

export const WalletGuard = memo(function WalletGuard() {
const wallet = useWallet()
const wallets = useWallets()
const outletContext = useOutletContext()
const { isLocked, loading } = useWalletLockStatus()

const hitPaymentPasswordGuard = usePaymentPasswordGuard()
const hitMessageGuard = useMessageGuard()

if (hitPaymentPasswordGuard) return <Navigate to={PopupRoutes.SetPaymentPassword} />
if (isLocked && !loading) {
return (
<>
<WalletSetupHeaderUI />
<Unlock />
</>
)
}
if (hitMessageGuard) return <Navigate to={PopupRoutes.ContractInteraction} />

return (
<>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { PopupRoutes } from '@masknet/shared-base'
import { useMatch } from 'react-router-dom'
import { useMessages } from '@masknet/web3-hooks-base'

/**
* Guardian for pending tasks
*/
export function useMessageGuard() {
const matchInteraction = useMatch(PopupRoutes.ContractInteraction)
const messages = useMessages()

return !matchInteraction && messages.length > 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { PopupRoutes } from '@masknet/shared-base'
import { useMatch } from 'react-router-dom'
import { useHasPassword } from '../../../hooks/index.js'

export function usePaymentPasswordGuard() {
const { hasPassword, loading } = useHasPassword()
const matchSetPaymentPassword = useMatch(PopupRoutes.SetPaymentPassword)

return !matchSetPaymentPassword && !hasPassword && !loading
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export const WalletHeader = memo(function WalletHeader() {
const origin = params.get('source')

const currentNetwork = useNetwork(NetworkPluginID.PLUGIN_EVM, chainId)
const matchUnlock = useMatch(PopupRoutes.Unlock)
const matchResetWallet = useMatch(PopupRoutes.ResetWallet)
const matchWallet = PopupRoutes.Wallet === location.pathname
const customHeader = CUSTOM_HEADER_PATTERNS.some((pattern) => matchPath(pattern, location.pathname))
Expand Down Expand Up @@ -56,8 +55,7 @@ export const WalletHeader = memo(function WalletHeader() {
)
}

if (!wallet || !hasPassword || matchUnlock || matchResetWallet)
return <WalletSetupHeaderUI showBack={!!matchResetWallet} />
if (!wallet || !hasPassword || matchResetWallet) return <WalletSetupHeaderUI showBack={!!matchResetWallet} />

return matchWallet ? (
<WalletHeaderUI
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './useAsset.js'
export * from './useWalletLockStatus.js'
export * from './useAssetExpand.js'
export * from './useWalletAssets.js'
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import { useAsyncRetry } from 'react-use'
import { useEffect } from 'react'
import Services from '#services'
import { CrossIsolationMessages } from '@masknet/shared-base'
import { useQuery } from '@tanstack/react-query'

export function useWalletLockStatus() {
const {
value: isLocked,
loading,
error,
retry,
} = useAsyncRetry(async () => {
return Services.Wallet.isLocked()
}, [])
const { data: isLocked, isLoading: loading, error, refetch } = useQuery(['@@is-locked'], Services.Wallet.isLocked)

useEffect(() => {
return CrossIsolationMessages.events.walletLockStatusUpdated.on(retry)
}, [retry])
return CrossIsolationMessages.events.walletLockStatusUpdated.on(() => refetch())
}, [])

return {
error,
Expand Down

0 comments on commit 7b17f14

Please sign in to comment.