From 92926ca193468b301f4ab513da2c77c6868e53b4 Mon Sep 17 00:00:00 2001 From: DaneEveritt Date: Sun, 3 Jul 2022 13:43:54 -0400 Subject: [PATCH] Cleanup logic powering totp enabling modal --- .../forms/ConfigureTwoFactorForm.tsx | 12 +- .../dashboard/forms/SetupTOTPModal.tsx | 151 ++++++++---------- 2 files changed, 76 insertions(+), 87 deletions(-) diff --git a/resources/scripts/components/dashboard/forms/ConfigureTwoFactorForm.tsx b/resources/scripts/components/dashboard/forms/ConfigureTwoFactorForm.tsx index 60d524add..109eb182a 100644 --- a/resources/scripts/components/dashboard/forms/ConfigureTwoFactorForm.tsx +++ b/resources/scripts/components/dashboard/forms/ConfigureTwoFactorForm.tsx @@ -3,16 +3,24 @@ import { useStoreState } from 'easy-peasy'; import { ApplicationStore } from '@/state'; import tw from 'twin.macro'; import { Button } from '@/components/elements/button/index'; -import SetupTOTPModal from '@/components/dashboard/forms/SetupTOTPModal'; import DisableTwoFactorModal from '@/components/dashboard/forms/DisableTwoFactorModal'; +import SetupTOTPModal from '@/components/dashboard/forms/SetupTOTPModal'; +import RecoveryTokensDialog from '@/components/dashboard/forms/RecoveryTokensDialog'; export default () => { + const [tokens, setTokens] = useState([]); const [visible, setVisible] = useState<'enable' | 'disable' | null>(null); const isEnabled = useStoreState((state: ApplicationStore) => state.user.data!.useTotp); + const onTokens = (tokens: string[]) => { + setTokens(tokens); + setVisible(null); + }; + return (
- setVisible(null)} /> + setVisible(null)} onTokens={onTokens} /> + 0} onClose={() => setTokens([])} /> setVisible(null)} />

{isEnabled diff --git a/resources/scripts/components/dashboard/forms/SetupTOTPModal.tsx b/resources/scripts/components/dashboard/forms/SetupTOTPModal.tsx index 6aa3e4797..b3d72a7a1 100644 --- a/resources/scripts/components/dashboard/forms/SetupTOTPModal.tsx +++ b/resources/scripts/components/dashboard/forms/SetupTOTPModal.tsx @@ -1,5 +1,5 @@ -import React, { useEffect, useState } from 'react'; -import { Dialog, DialogProps } from '@/components/elements/dialog'; +import React, { useContext, useEffect, useState } from 'react'; +import { Dialog, DialogWrapperContext } from '@/components/elements/dialog'; import getTwoFactorTokenData, { TwoFactorTokenData } from '@/api/account/getTwoFactorTokenData'; import { useFlashKey } from '@/plugins/useFlash'; import tw from 'twin.macro'; @@ -11,39 +11,28 @@ import CopyOnClick from '@/components/elements/CopyOnClick'; import Tooltip from '@/components/elements/tooltip/Tooltip'; import enableAccountTwoFactor from '@/api/account/enableAccountTwoFactor'; import FlashMessageRender from '@/components/FlashMessageRender'; -import RecoveryTokensDialog from '@/components/dashboard/forms/RecoveryTokensDialog'; import { Actions, useStoreActions } from 'easy-peasy'; import { ApplicationStore } from '@/state'; +import asDialog from '@/hoc/asDialog'; -type SetupTOTPModalProps = DialogProps; +interface Props { + onTokens: (tokens: string[]) => void; +} -export default ({ open, onClose }: SetupTOTPModalProps) => { +const ConfigureTwoFactorForm = ({ onTokens }: Props) => { const [submitting, setSubmitting] = useState(false); const [value, setValue] = useState(''); - const [tokens, setTokens] = useState([]); const [token, setToken] = useState(null); const { clearAndAddHttpError } = useFlashKey('account:two-step'); const updateUserData = useStoreActions((actions: Actions) => actions.user.updateUserData); - useEffect(() => { - if (!open) return; + const { close } = useContext(DialogWrapperContext); + useEffect(() => { getTwoFactorTokenData() .then(setToken) - .then(() => updateUserData({ useTotp: true })) .catch((error) => clearAndAddHttpError(error)); - }, [open]); - - useEffect(() => { - if (!open) return; - - return () => { - setToken(null); - setValue(''); - setSubmitting(false); - clearAndAddHttpError(undefined); - }; - }, [open]); + }, []); const submit = () => { if (submitting) return; @@ -52,76 +41,68 @@ export default ({ open, onClose }: SetupTOTPModalProps) => { clearAndAddHttpError(); enableAccountTwoFactor(value) - .then(setTokens) - .catch(clearAndAddHttpError) - .then(() => setSubmitting(false)); + .then((tokens) => { + updateUserData({ useTotp: true }); + onTokens(tokens); + }) + .catch((error) => { + clearAndAddHttpError(error); + setSubmitting(false); + }); }; return ( <> - 0} onClose={onClose} /> -

+
- -
+ ) : ( + + )} +
+ +

+ {token?.secret.match(/.{1,4}/g)!.join(' ') || 'Loading...'} +

+
+
+

+ Scan the QR code above using the two-step authentication app of your choice. Then, enter the 6-digit + code generated into the field below. +

+
+ setValue(e.currentTarget.value)} + className={'mt-4'} + placeholder={'000000'} + type={'text'} + inputMode={'numeric'} + autoComplete={'one-time-code'} + pattern={'\\d{6}'} + /> + + Cancel + - {!token ? ( - - ) : ( - - )} -
- -

- {token?.secret.match(/.{1,4}/g)!.join(' ') || 'Loading...'} -

-
-
-

- Scan the QR code above using the two-step authentication app of your choice. Then, enter the - 6-digit code generated into the field below. -

-
- setValue(e.currentTarget.value)} - className={'mt-4'} - placeholder={'000000'} - type={'text'} - inputMode={'numeric'} - autoComplete={'one-time-code'} - pattern={'\\d{6}'} - /> - - Cancel - - - - -
+ + + ); }; + +export default asDialog({ + title: 'Enable Two-Step Verification', + description: + "Help protect your account from unauthorized access. You'll be prompted for a verification code each time you sign in.", +})(ConfigureTwoFactorForm);