Addressed PR comments

This commit is contained in:
Carlos Monastyrski
2025-09-23 09:27:14 -03:00
parent e57cd54ead
commit ba277a057e
3 changed files with 28 additions and 26 deletions

View File

@@ -56,7 +56,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
const cfg = getConfig();
server.decorateRequest("mfa", null);
server.addHook("preParsing", async (req, res) => {
server.addHook("preValidation", async (req, res) => {
const authorizationHeader = req.headers.authorization;
if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) {

View File

@@ -7,7 +7,7 @@ import Error from "@app/components/basic/Error";
import TotpRegistration from "@app/components/mfa/TotpRegistration";
import SecurityClient from "@app/components/utilities/SecurityClient";
import { Button } from "@app/components/v2";
import { useSendMfaToken } from "@app/hooks/api";
import { useLogoutUser, useSendMfaToken } from "@app/hooks/api";
import { checkUserTotpMfa, verifyMfaToken, verifyRecoveryCode } from "@app/hooks/api/auth/queries";
import { MfaMethod } from "@app/hooks/api/auth/types";
@@ -66,6 +66,7 @@ export const Mfa = ({ successCallback, closeMfa, hideLogo, email, method }: Prop
const [isLoadingResend, setIsLoadingResend] = useState(false);
const [triesLeft, setTriesLeft] = useState<number | undefined>(undefined);
const [shouldShowTotpRegistration, setShouldShowTotpRegistration] = useState(false);
const logout = useLogoutUser(true);
const sendMfaToken = useSendMfaToken();
@@ -80,10 +81,18 @@ export const Mfa = ({ successCallback, closeMfa, hideLogo, email, method }: Prop
}
}, []);
const getExpectedCodeLength = () => {
if (method === MfaMethod.EMAIL) return 6;
if (method === MfaMethod.TOTP) return showRecoveryCodeInput ? 8 : 6;
return 6;
};
const isCodeComplete = mfaCode.length === getExpectedCodeLength();
const verifyMfa = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (!mfaCode.trim()) return;
if (!mfaCode.trim() || !isCodeComplete) return;
setIsLoading(true);
try {
@@ -107,16 +116,18 @@ export const Mfa = ({ successCallback, closeMfa, hideLogo, email, method }: Prop
closeMfa();
}
} catch {
if (triesLeft) {
setTriesLeft((left) => {
if (triesLeft === 1) {
navigate({ to: "/" });
SecurityClient.setMfaToken("");
SecurityClient.setToken("");
}
return (left as number) - 1;
});
if (typeof triesLeft === "number") {
const newTriesLeft = triesLeft - 1;
setTriesLeft(newTriesLeft);
if (newTriesLeft <= 0) {
setIsLoading(false);
SecurityClient.setMfaToken("");
SecurityClient.setToken("");
SecurityClient.setSignupToken("");
await logout.mutateAsync();
navigate({ to: "/login" });
return;
}
} else {
setTriesLeft(2);
}
@@ -251,6 +262,7 @@ export const Mfa = ({ successCallback, closeMfa, hideLogo, email, method }: Prop
colorSchema="primary"
variant="outline_bg"
isLoading={isLoading}
isDisabled={!isCodeComplete}
>
{String(t("mfa.verify"))}
</Button>
@@ -263,7 +275,6 @@ export const Mfa = ({ successCallback, closeMfa, hideLogo, email, method }: Prop
onClick={() => {
setShowRecoveryCodeInput(!showRecoveryCodeInput);
setMfaCode("");
setTriesLeft(undefined);
}}
className="text-bunker-400 transition-colors duration-200 hover:text-bunker-200 hover:underline hover:decoration-primary-700 hover:underline-offset-4"
>

View File

@@ -21,16 +21,7 @@ export const RecoveryCodesDownload = ({
const [copied, setCopied] = useState(false);
const downloadRecoveryCodes = () => {
const content = [
"Infisical Two-Factor Authentication Recovery Codes",
`Generated on: ${new Date().toLocaleString()}`,
"",
"Important: Store these codes in a safe place. Each code can only be used once.",
"If you lose access to your mobile authenticator, you can use these codes to regain access to your account.",
"",
"Recovery Codes:",
...recoveryCodes.map((code, index) => `${index + 1}. ${code}`)
].join("\n");
const content = [...recoveryCodes].join("\n");
const blob = new Blob([content], { type: "text/plain" });
const url = URL.createObjectURL(blob);
@@ -75,8 +66,8 @@ export const RecoveryCodesDownload = ({
<div className="grid grid-cols-2 gap-x-6 gap-y-2 font-mono text-sm">
{recoveryCodes.map((code, index) => (
<div key={code} className="flex items-center text-mineshaft-200">
<span className="w-6 text-mineshaft-400">{index + 1}.</span>
<span>{code}</span>
<span className="w-8 text-right text-mineshaft-400">{index + 1}.</span>
<span className="pl-2">{code}</span>
</div>
))}
</div>