This commit is contained in:
Manav Rathi
2025-06-09 14:04:58 +05:30
parent b4b34e89bc
commit 960d2fd2b1
2 changed files with 28 additions and 30 deletions

View File

@@ -37,7 +37,7 @@ export interface RecoverPageProps {
const Page: React.FC<RecoverPageProps> = ({ twoFactorType }) => {
const { logout, showMiniDialog, onGenericError } = useBaseContext();
const [sessionID, setSessionID] = useState<string | null>(null);
const [sessionID, setSessionID] = useState<string | undefined>(undefined);
const [recoveryResponse, setRecoveryResponse] = useState<
TwoFactorRecoveryResponse | undefined
>(undefined);
@@ -65,8 +65,8 @@ const Page: React.FC<RecoverPageProps> = ({ twoFactorType }) => {
useEffect(() => {
const user = getData("user");
const sid = user.passkeySessionID || user.twoFactorSessionID;
if (!user?.email || !sid) {
const sessionID = user.passkeySessionID || user.twoFactorSessionID;
if (!user?.email || !sessionID) {
void router.push("/");
} else if (
!(user.isTwoFactorEnabled || user.isTwoFactorEnabledPasskey) &&
@@ -74,8 +74,8 @@ const Page: React.FC<RecoverPageProps> = ({ twoFactorType }) => {
) {
void router.push("/generate");
} else {
setSessionID(sid);
void recoverTwoFactor(sid, twoFactorType)
setSessionID(sessionID);
void recoverTwoFactor(twoFactorType, sessionID)
.then(setRecoveryResponse)
.catch((e: unknown) => {
log.error("Second factor recovery page setup failed", e);
@@ -99,20 +99,18 @@ const Page: React.FC<RecoverPageProps> = ({ twoFactorType }) => {
const handleSubmit: SingleInputFormProps["onSubmit"] | undefined = useMemo(
() =>
sessionID && recoveryResponse
? async (recoveryKeyMnemonic: string, setFieldError) => {
try {
await recoverTwoFactorFinish(
sessionID,
twoFactorType,
recoveryResponse,
recoveryKeyMnemonic,
);
void router.push("/credentials");
} catch (e) {
log.error("Second factor recovery failed", e);
setFieldError(t("incorrect_recovery_key"));
}
}
? (recoveryKeyMnemonic, setFieldError) =>
recoverTwoFactorFinish(
twoFactorType,
sessionID,
recoveryResponse,
recoveryKeyMnemonic,
)
.then(() => router.push("/credentials"))
.catch((e: unknown) => {
log.error("Second factor recovery failed", e);
setFieldError(t("incorrect_recovery_key"));
})
: undefined,
[twoFactorType, router, sessionID, recoveryResponse],
);

View File

@@ -623,11 +623,11 @@ export type TwoFactorRecoveryResponse = z.infer<
* factor recovery secret (and nonce) from remote. The user can then decrypt
* these using their recovery key to reset or bypass their second factor.
*
* @param twoFactorType The type of second factor to reset or bypass.
*
* @param sessionID A two factor session ID ({@link twoFactorSessionID} or
* {@link passkeySessionID}) for the user.
*
* @param twoFactorType The type of second factor to reset or bypass.
*
* [Note: Second factor recovery]
*
* 1. When setting up a TOTP based second factor, client sends a (encrypted 2fa
@@ -648,11 +648,11 @@ export type TwoFactorRecoveryResponse = z.infer<
* (passkey based) the user's second factor.
*/
export const recoverTwoFactor = async (
sessionID: string,
twoFactorType: TwoFactorType,
sessionID: string,
): Promise<TwoFactorRecoveryResponse> => {
const res = await fetch(
await apiURL("/users/two-factor/recover", { sessionID, twoFactorType }),
await apiURL("/users/two-factor/recover", { twoFactorType, sessionID }),
{ headers: publicRequestHeaders() },
);
ensureOk(res);
@@ -668,13 +668,13 @@ export const recoverTwoFactor = async (
*
* This completes the recovery process both locally, and on remote.
*
* @param twoFactorType The second factor type (same value as what would've been
* passed to {@link recoverTwoFactor} for obtaining {@link recoveryResponse}).
*
* @param sessionID The second factor session ID (same value as what would've
* been passed to {@link recoverTwoFactor} for obtaining
* {@link recoveryResponse}).
*
* @param twoFactorType The second factor type (same value as what would've been
* passed to {@link recoverTwoFactor} for obtaining {@link recoveryResponse}).
*
* @param recoveryResponse The response to a previous call to
* {@link recoverTwoFactor}.
*
@@ -682,8 +682,8 @@ export const recoverTwoFactor = async (
* by the user to complete recovery.
*/
export const recoverTwoFactorFinish = async (
sessionID: string,
twoFactorType: TwoFactorType,
sessionID: string,
recoveryResponse: TwoFactorRecoveryResponse,
recoveryKeyMnemonic: string,
) => {
@@ -694,8 +694,8 @@ export const recoverTwoFactorFinish = async (
await recoveryKeyFromMnemonic(recoveryKeyMnemonic),
);
const { keyAttributes, encryptedToken, token, id } = await removeTwoFactor(
sessionID,
twoFactorType,
sessionID,
twoFactorSecret,
);
await setLSUser({
@@ -716,13 +716,13 @@ export interface TwoFactorVerificationResponse {
}
export const removeTwoFactor = async (
sessionID: string,
twoFactorType: TwoFactorType,
sessionID: string,
secret: string,
) => {
const resp = await HTTPService.post(
await apiURL("/users/two-factor/remove"),
{ sessionID, twoFactorType, secret },
{ twoFactorType, sessionID, secret },
);
return resp.data as TwoFactorVerificationResponse;
};