From ca4b883869c8237617ddfc544445783268894a1e Mon Sep 17 00:00:00 2001 From: Chuck Dries Date: Mon, 26 Jan 2026 15:03:25 -0800 Subject: [PATCH 01/18] Add MultifactorAuthentication RevokePage --- src/ROUTES.ts | 2 + src/SCREENS.ts | 1 + src/languages/en.ts | 8 ++ .../ModalStackNavigators/index.tsx | 1 + src/libs/Navigation/linkingConfig/config.ts | 1 + .../MultifactorAuthentication/RevokePage.tsx | 86 +++++++++++++++++++ 6 files changed, 99 insertions(+) create mode 100644 src/pages/MultifactorAuthentication/RevokePage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index a55fa3516ff5..bc0486548f3e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -3740,6 +3740,8 @@ const ROUTES = { }, MULTIFACTOR_AUTHENTICATION_NOT_FOUND: 'multifactor-authentication/not-found', + + MULTIFACTOR_AUTHENTICATION_REVOKE: 'multifactor-authentication/revoke', } as const; /** diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 467ce149dd67..3564fb3f6ca4 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -913,6 +913,7 @@ const SCREENS = { OUTCOME: 'Multifactor_Authentication_Outcome', PROMPT: 'Multifactor_Authentication_Prompt', NOT_FOUND: 'Multifactor_Authentication_Not_Found', + REVOKE: 'Multifactor_Authentication_Revoke' }, } as const; diff --git a/src/languages/en.ts b/src/languages/en.ts index daff2afeaa99..dbf0b15e6aae 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -750,6 +750,14 @@ const translations = { enableQuickVerification: { biometrics: 'Enable quick, secure verification using your face or fingerprint. No passwords or codes required.', }, + revoke: { + title: 'Face/fingerprint & passkeys', + explanation: 'Face/fingerprint or passkey verification are enabled on one or more devices. Revoking access will require a magic code for the next verification on any device', + confirmationPrompt: 'Are you sure? You\'ll need a magic code for the next verification on any device', + cta: 'Revoke access', + noDevices: 'You don\'t have any devices register for face/fingerprint or passkey verification. If you register any, you will be able to revoke that acces here.', + dismiss: 'Got it', + } }, validateCodeModal: { successfulSignInTitle: dedent(` diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index aa28338b72d8..04a4616737d2 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -1014,6 +1014,7 @@ const MultifactorAuthenticationStackNavigator = createModalStackNavigator require('../../../../pages/MultifactorAuthentication/BiometricsTestPage').default, [SCREENS.MULTIFACTOR_AUTHENTICATION.OUTCOME]: () => require('@pages/MultifactorAuthentication/OutcomePage').default, [SCREENS.MULTIFACTOR_AUTHENTICATION.PROMPT]: () => require('../../../../pages/MultifactorAuthentication/PromptPage').default, + [SCREENS.MULTIFACTOR_AUTHENTICATION.REVOKE]: () => require('@pages/MultifactorAuthentication/RevokePage').default, [SCREENS.MULTIFACTOR_AUTHENTICATION.NOT_FOUND]: () => require('../../../../pages/ErrorPage/NotFoundPage').default, }); diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index c7defe0694e4..74c2b904761d 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1945,6 +1945,7 @@ const config: LinkingOptions['config'] = { [SCREENS.MULTIFACTOR_AUTHENTICATION.OUTCOME]: ROUTES.MULTIFACTOR_AUTHENTICATION_OUTCOME.route, [SCREENS.MULTIFACTOR_AUTHENTICATION.PROMPT]: ROUTES.MULTIFACTOR_AUTHENTICATION_PROMPT.route, [SCREENS.MULTIFACTOR_AUTHENTICATION.NOT_FOUND]: ROUTES.MULTIFACTOR_AUTHENTICATION_NOT_FOUND, + [SCREENS.MULTIFACTOR_AUTHENTICATION.REVOKE]: ROUTES.MULTIFACTOR_AUTHENTICATION_REVOKE }, }, }, diff --git a/src/pages/MultifactorAuthentication/RevokePage.tsx b/src/pages/MultifactorAuthentication/RevokePage.tsx new file mode 100644 index 000000000000..c8d9be5d9070 --- /dev/null +++ b/src/pages/MultifactorAuthentication/RevokePage.tsx @@ -0,0 +1,86 @@ +import React, {useState} from 'react'; +import {View} from 'react-native'; +import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; +import Button from '@components/Button'; +import ConfirmModal from '@components/ConfirmModal'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; + +const hasDevices = true; + +function MultifactorAuthenticationRevokePage() { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const [isConfirmModalVisible, setConfirmModalVisibility] = useState(false); + + const onGoBackPress = () => { + Navigation.dismissModal(); + }; + + const showConfirmModal = () => { + setConfirmModalVisibility(true); + }; + + const hideConfirmModal = () => { + setConfirmModalVisibility(false); + }; + + const handleRevokeConfirm = () => { + hideConfirmModal(); + // TODO: Implement actual revoke logic + Navigation.dismissModal(); + }; + + return ( + + + + + + {translate(hasDevices ? 'multifactorAuthentication.revoke.explanation' : 'multifactorAuthentication.revoke.noDevices')} + + + + {hasDevices ? ( +