import React, { useEffect, useState } from "react"; import ReactCodeInput from "react-code-input"; import { Link, useNavigate } from "@tanstack/react-router"; import { t } from "i18next"; import Error from "@app/components/basic/Error"; import TotpRegistration from "@app/components/mfa/TotpRegistration"; import SecurityClient from "@app/components/utilities/SecurityClient"; import { Button, Input } from "@app/components/v2"; import { useSendMfaToken } from "@app/hooks/api"; import { checkUserTotpMfa, verifyMfaToken } from "@app/hooks/api/auth/queries"; import { MfaMethod } from "@app/hooks/api/auth/types"; // The style for the verification code input const codeInputProps = { inputStyle: { fontFamily: "monospace", margin: "4px", MozAppearance: "textfield", width: "48px", borderRadius: "5px", fontSize: "24px", height: "48px", paddingLeft: "7", backgroundColor: "#0d1117", color: "white", border: "1px solid #2d2f33", textAlign: "center", outlineColor: "#8ca542", borderColor: "#2d2f33" } } as const; const codeInputPropsPhone = { inputStyle: { fontFamily: "monospace", margin: "4px", MozAppearance: "textfield", width: "40px", borderRadius: "5px", fontSize: "24px", height: "40px", paddingLeft: "7", backgroundColor: "#0d1117", color: "white", border: "1px solid #2d2f33", textAlign: "center", outlineColor: "#8ca542", borderColor: "#2d2f33" } } as const; type Props = { successCallback: () => void | Promise; closeMfa?: () => void; hideLogo?: boolean; email: string; method: MfaMethod; }; export const Mfa = ({ successCallback, closeMfa, hideLogo, email, method }: Props) => { const [mfaCode, setMfaCode] = useState(""); const navigate = useNavigate(); const [isLoading, setIsLoading] = useState(false); const [isLoadingResend, setIsLoadingResend] = useState(false); const [triesLeft, setTriesLeft] = useState(undefined); const [shouldShowTotpRegistration, setShouldShowTotpRegistration] = useState(false); const sendMfaToken = useSendMfaToken(); useEffect(() => { if (method === MfaMethod.TOTP) { checkUserTotpMfa().then((isVerified) => { if (!isVerified) { SecurityClient.setMfaToken(""); setShouldShowTotpRegistration(true); } }); } }, []); const verifyMfa = async (event: React.FormEvent) => { event.preventDefault(); setIsLoading(true); try { const { token } = await verifyMfaToken({ email, mfaCode, mfaMethod: method }); SecurityClient.setMfaToken(""); SecurityClient.setToken(token); await successCallback(); if (closeMfa) { closeMfa(); } } catch { if (triesLeft) { setTriesLeft((left) => { if (triesLeft === 1) { navigate({ to: "/" }); SecurityClient.setMfaToken(""); SecurityClient.setToken(""); } return (left as number) - 1; }); } else { setTriesLeft(2); } } finally { setIsLoading(false); } }; const handleResendMfaCode = async () => { try { setIsLoadingResend(true); await sendMfaToken.mutateAsync({ email }); setIsLoadingResend(false); } catch (err) { console.error(err); setIsLoadingResend(false); } }; if (shouldShowTotpRegistration) { return ( <>
Your organization requires mobile authentication to be configured.
{ setShouldShowTotpRegistration(false); await successCallback(); }} />
); } return (
{!hideLogo && (
Infisical logo
)} {method === MfaMethod.EMAIL && ( <>

{t("mfa.step2-message")}

{email}

)} {method === MfaMethod.TOTP && ( <>

Authenticator MFA Required

Open the authenticator app on your mobile device to get your verification code or enter a recovery code.

)}
{method === MfaMethod.EMAIL && ( )} {method === MfaMethod.TOTP && (
setMfaCode(e.target.value)} />
)}
{method === MfaMethod.EMAIL && ( )} {method === MfaMethod.TOTP && (
setMfaCode(e.target.value)} />
)}
{typeof triesLeft === "number" && ( )}
{method === MfaMethod.TOTP && (
Lost your recovery codes? Reset your account
)} {method === MfaMethod.EMAIL && (
{t("signup.step2-resend-alert")}

{t("signup.step2-spam-alert")}

)}
); };