Path: blob/1.0-develop/resources/scripts/components/dashboard/forms/SetupTOTPDialog.tsx
7461 views
import React, { useContext, useEffect, useState } from 'react';1import { Dialog, DialogWrapperContext } from '@/components/elements/dialog';2import getTwoFactorTokenData, { TwoFactorTokenData } from '@/api/account/getTwoFactorTokenData';3import { useFlashKey } from '@/plugins/useFlash';4import tw from 'twin.macro';5import QRCode from 'qrcode.react';6import { Button } from '@/components/elements/button/index';7import Spinner from '@/components/elements/Spinner';8import { Input } from '@/components/elements/inputs';9import CopyOnClick from '@/components/elements/CopyOnClick';10import Tooltip from '@/components/elements/tooltip/Tooltip';11import enableAccountTwoFactor from '@/api/account/enableAccountTwoFactor';12import FlashMessageRender from '@/components/FlashMessageRender';13import { Actions, useStoreActions } from 'easy-peasy';14import { ApplicationStore } from '@/state';15import asDialog from '@/hoc/asDialog';1617interface Props {18onTokens: (tokens: string[]) => void;19}2021const ConfigureTwoFactorForm = ({ onTokens }: Props) => {22const [submitting, setSubmitting] = useState(false);23const [value, setValue] = useState('');24const [password, setPassword] = useState('');25const [token, setToken] = useState<TwoFactorTokenData | null>(null);26const { clearAndAddHttpError } = useFlashKey('account:two-step');27const updateUserData = useStoreActions((actions: Actions<ApplicationStore>) => actions.user.updateUserData);2829const { close, setProps } = useContext(DialogWrapperContext);3031useEffect(() => {32getTwoFactorTokenData()33.then(setToken)34.catch((error) => clearAndAddHttpError(error));35}, []);3637useEffect(() => {38setProps((state) => ({ ...state, preventExternalClose: submitting }));39}, [submitting]);4041const submit = (e: React.FormEvent<HTMLFormElement>) => {42e.preventDefault();43e.stopPropagation();4445if (submitting) return;4647setSubmitting(true);48clearAndAddHttpError();49enableAccountTwoFactor(value, password)50.then((tokens) => {51updateUserData({ useTotp: true });52onTokens(tokens);53})54.catch((error) => {55clearAndAddHttpError(error);56setSubmitting(false);57});58};5960return (61<form id={'enable-totp-form'} onSubmit={submit}>62<FlashMessageRender byKey={'account:two-step'} className={'mt-4'} />63<div className={'flex items-center justify-center w-56 h-56 p-2 bg-gray-50 shadow mx-auto mt-6'}>64{!token ? (65<Spinner />66) : (67<QRCode renderAs={'svg'} value={token.image_url_data} css={tw`w-full h-full shadow-none`} />68)}69</div>70<CopyOnClick text={token?.secret}>71<p className={'font-mono text-sm text-gray-100 text-center mt-2'}>72{token?.secret.match(/.{1,4}/g)!.join(' ') || 'Loading...'}73</p>74</CopyOnClick>75<p id={'totp-code-description'} className={'mt-6'}>76Scan the QR code above using the two-step authentication app of your choice. Then, enter the 6-digit77code generated into the field below.78</p>79<Input.Text80aria-labelledby={'totp-code-description'}81variant={Input.Text.Variants.Loose}82value={value}83onChange={(e) => setValue(e.currentTarget.value)}84className={'mt-3'}85placeholder={'000000'}86type={'text'}87inputMode={'numeric'}88autoComplete={'one-time-code'}89pattern={'\\d{6}'}90/>91<label htmlFor={'totp-password'} className={'block mt-3'}>92Account Password93</label>94<Input.Text95variant={Input.Text.Variants.Loose}96className={'mt-1'}97type={'password'}98value={password}99onChange={(e) => setPassword(e.currentTarget.value)}100/>101<Dialog.Footer>102<Button.Text onClick={close}>Cancel</Button.Text>103<Tooltip104disabled={password.length > 0 && value.length === 6}105content={106!token107? 'Waiting for QR code to load...'108: 'You must enter the 6-digit code and your password to continue.'109}110delay={100}111>112<Button113disabled={!token || value.length !== 6 || !password.length}114type={'submit'}115form={'enable-totp-form'}116>117Enable118</Button>119</Tooltip>120</Dialog.Footer>121</form>122);123};124125export default asDialog({126title: 'Enable Two-Step Verification',127description:128"Help protect your account from unauthorized access. You'll be prompted for a verification code each time you sign in.",129})(ConfigureTwoFactorForm);130131132