import { useQuery, useMutation, gql } from '@apollo/client' import Grid from '@mui/material/Grid' import Paper from '@mui/material/Paper' import { Form, Formik } from 'formik' import { QRCodeSVG as QRCode } from 'qrcode.react' import React, { useReducer, useState } from 'react' import { useLocation, useHistory } from 'react-router-dom' import { H2, Label2, Label3, P } from 'src/components/typography' import Logo from 'src/styling/icons/menu/logo.svg?react' import { ActionButton, Button } from 'src/components/buttons' import { CodeInput } from 'src/components/inputs/base' import { primaryColor } from 'src/styling/variables' import classes from './Authentication.module.css' const VALIDATE_RESET_2FA_LINK = gql` query validateReset2FALink($token: String!) { validateReset2FALink(token: $token) { user_id secret otpauth } } ` const RESET_2FA = gql` mutation reset2FA($token: String!, $userID: ID!, $code: String!) { reset2FA(token: $token, userID: $userID, code: $code) } ` const initialState = { userID: null, secret: null, otpauth: null, result: null, } const reducer = (state, action) => { const { type, payload } = action return { ...state, ...payload, result: type } } const Reset2FA = () => { const history = useHistory() const QueryParams = () => new URLSearchParams(useLocation().search) const token = QueryParams().get('t') const [isShowing, setShowing] = useState(false) const [invalidToken, setInvalidToken] = useState(false) const [twoFAConfirmation, setTwoFAConfirmation] = useState('') const [state, dispatch] = useReducer(reducer, initialState) const handle2FAChange = value => { setTwoFAConfirmation(value) setInvalidToken(false) } const { error: queryError, loading } = useQuery(VALIDATE_RESET_2FA_LINK, { variables: { token: token }, onCompleted: ({ validateReset2FALink: info }) => { if (!info) { dispatch({ type: 'failure', }) } else { dispatch({ type: 'success', payload: { userID: info.user_id, secret: info.secret, otpauth: info.otpauth, }, }) } }, onError: () => { dispatch({ type: 'failure', }) }, }) const [reset2FA, { error: mutationError }] = useMutation(RESET_2FA, { onCompleted: ({ reset2FA: success }) => { success ? history.push('/') : setInvalidToken(true) }, }) const getErrorMsg = () => { if (queryError) return 'Internal server error' if (twoFAConfirmation.length !== 6 && invalidToken) return 'The code should have 6 characters!' if (mutationError || invalidToken) return 'Code is invalid. Please try again.' return null } const handleSubmit = () => { if (twoFAConfirmation.length !== 6) { setInvalidToken(true) return } reset2FA({ variables: { token: token, userID: state.userID, code: twoFAConfirmation, }, }) } return (

Lamassu Admin

{!loading && state.result === 'success' && ( <>
To finish this process, please scan the following QR code or insert the secret further below on an authentication app of your choice, such Google Authenticator or Authy.
Your secret: {state.secret} { setShowing(!isShowing) }}> {isShowing ? 'Hide' : 'Show'}
{/* TODO: refactor the 2FA CodeInput to properly use Formik */} {}} initialValues={{}}>
{getErrorMsg() && (

{getErrorMsg()}

)}
)} {!loading && state.result === 'failure' && ( <> Link has expired )}
) } export default Reset2FA