Update
This commit is contained in:
@@ -110,12 +110,12 @@ import React, { useCallback, useEffect, useState } from "react";
|
||||
* - Redirects to "/" if there is no `email` or `twoFactorSessionID` in the
|
||||
* saved partial local user.
|
||||
*
|
||||
* - Redirects to "/credentials" if there `isTwoFactorEnabled` is not `true`
|
||||
* and either of `encryptedToken` or `token` is present in the saved partial
|
||||
* - Redirects to "/credentials" if `isTwoFactorEnabled` is not `true` and
|
||||
* either of `encryptedToken` or `token` is present in the saved partial
|
||||
* local user.
|
||||
*
|
||||
* - "/passkeys/finish" - A page that the accounts app hands off control back to
|
||||
* us (the calling app) to continue the rest of the authentication.
|
||||
* - "/passkeys/finish" - A page where the accounts app hands off control back
|
||||
* to us (the calling app) once the passkey has been verified.
|
||||
*
|
||||
* - Redirects to "/" if there is no matching `inflightPasskeySessionID` in
|
||||
* session storage.
|
||||
@@ -124,15 +124,15 @@ import React, { useCallback, useEffect, useState } from "react";
|
||||
*
|
||||
* - "/two-factor/recover" and "/passkeys/recover" - Pages that allow the user
|
||||
* to reset or bypass their second factor if they possess their recovery key.
|
||||
* Both pages work similarly, except the second factor they act on.
|
||||
* Both pages work similarly, except for the second factor they act on.
|
||||
*
|
||||
* - Redirects to "/" if there is no `email` in the saved partial local user,
|
||||
* or either of `twoFactorSessionID` and `twoFactorSessionID` is set.
|
||||
* - Redirect to "/" if there is no `email` or `twoFactorSessionID` /
|
||||
* `passkeySessionID` in the saved partial local user.
|
||||
*
|
||||
* - Redirects to "/generate" if there is an `encryptedToken` or `token` in
|
||||
* the saved partial local user.
|
||||
* - Redirect to "/generate" if there is an `encryptedToken` or `token` in the
|
||||
* saved partial local user.
|
||||
*
|
||||
* - Redirects to "/credentials" after recovery.
|
||||
* - Redirect to "/credentials" after recovery.
|
||||
*
|
||||
*/
|
||||
const Page: React.FC = () => {
|
||||
|
||||
@@ -13,6 +13,11 @@ import { useRouter } from "next/router";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
/**
|
||||
* The page where the accounts app hands back control to us once the passkey has
|
||||
* been verified.
|
||||
*
|
||||
* See: [Note: Login pages]
|
||||
*
|
||||
* [Note: Finish passkey flow in the requesting app]
|
||||
*
|
||||
* The passkey finish step needs to happen in the context of the client which
|
||||
@@ -23,7 +28,7 @@ const Page: React.FC = () => {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
// Extract response from query params
|
||||
// Extract response from query params.
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const passkeySessionID = searchParams.get("passkeySessionID");
|
||||
const response = searchParams.get("response");
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
} from "ente-base/session";
|
||||
import { t } from "i18next";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
/**
|
||||
* A page that allows the user to enter their recovery key to recover their
|
||||
@@ -44,58 +44,63 @@ const Page: React.FC = () => {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const user = savedPartialLocalUser();
|
||||
if (!user?.email) {
|
||||
void router.push("/");
|
||||
return;
|
||||
}
|
||||
if (!user?.encryptedToken && !user?.token) {
|
||||
void sendOTT(user.email, undefined);
|
||||
stashRedirect("/recover");
|
||||
void router.push("/verify");
|
||||
return;
|
||||
}
|
||||
void (async () => {
|
||||
const user = savedPartialLocalUser();
|
||||
if (!user?.email) {
|
||||
await router.push("/");
|
||||
return;
|
||||
}
|
||||
|
||||
const keyAttributes = savedKeyAttributes();
|
||||
if (!keyAttributes) {
|
||||
void router.push("/generate");
|
||||
} else if (haveMasterKeyInSession()) {
|
||||
void router.push(appHomeRoute);
|
||||
} else {
|
||||
setKeyAttributes(keyAttributes);
|
||||
}
|
||||
if (!user.encryptedToken && !user.token) {
|
||||
await sendOTT(user.email, undefined);
|
||||
stashRedirect("/recover");
|
||||
await router.push("/verify");
|
||||
return;
|
||||
}
|
||||
|
||||
const keyAttributes = savedKeyAttributes();
|
||||
if (!keyAttributes) {
|
||||
await router.push("/generate");
|
||||
} else if (haveMasterKeyInSession()) {
|
||||
await router.push(appHomeRoute);
|
||||
} else {
|
||||
setKeyAttributes(keyAttributes);
|
||||
}
|
||||
})();
|
||||
}, [router]);
|
||||
|
||||
const handleSubmit: SingleInputFormProps["onSubmit"] = async (
|
||||
recoveryKeyMnemonic: string,
|
||||
setFieldError,
|
||||
) => {
|
||||
try {
|
||||
const keyAttr = keyAttributes!;
|
||||
const masterKey = await decryptBox(
|
||||
{
|
||||
encryptedData: keyAttr.masterKeyEncryptedWithRecoveryKey!,
|
||||
nonce: keyAttr.masterKeyDecryptionNonce!,
|
||||
},
|
||||
await recoveryKeyFromMnemonic(recoveryKeyMnemonic),
|
||||
);
|
||||
await saveMasterKeyInSessionAndSafeStore(masterKey);
|
||||
await decryptAndStoreToken(keyAttr, masterKey);
|
||||
const handleSubmit: SingleInputFormProps["onSubmit"] = useCallback(
|
||||
async (recoveryKeyMnemonic: string, setFieldError) => {
|
||||
try {
|
||||
const keyAttr = keyAttributes!;
|
||||
const masterKey = await decryptBox(
|
||||
{
|
||||
encryptedData:
|
||||
keyAttr.masterKeyEncryptedWithRecoveryKey!,
|
||||
nonce: keyAttr.masterKeyDecryptionNonce!,
|
||||
},
|
||||
await recoveryKeyFromMnemonic(recoveryKeyMnemonic),
|
||||
);
|
||||
await saveMasterKeyInSessionAndSafeStore(masterKey);
|
||||
await decryptAndStoreToken(keyAttr, masterKey);
|
||||
|
||||
void router.push("/change-password?op=reset");
|
||||
} catch (e) {
|
||||
log.error("password recovery failed", e);
|
||||
setFieldError(t("incorrect_recovery_key"));
|
||||
}
|
||||
};
|
||||
void router.push("/change-password?op=reset");
|
||||
} catch (e) {
|
||||
log.error("Master key recovery failed", e);
|
||||
setFieldError(t("incorrect_recovery_key"));
|
||||
}
|
||||
},
|
||||
[router, keyAttributes],
|
||||
);
|
||||
|
||||
const showNoRecoveryKeyMessage = () =>
|
||||
const showNoRecoveryKeyMessage = useCallback(() => {
|
||||
showMiniDialog({
|
||||
title: t("sorry"),
|
||||
message: t("no_recovery_key_message"),
|
||||
continue: { color: "secondary" },
|
||||
cancel: false,
|
||||
});
|
||||
}, [showMiniDialog]);
|
||||
|
||||
return (
|
||||
<AccountsPageContents>
|
||||
|
||||
@@ -64,20 +64,23 @@ const Page: React.FC<RecoverPageProps> = ({ twoFactorType }) => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const user = savedPartialLocalUser();
|
||||
const sessionID =
|
||||
twoFactorType == "passkey"
|
||||
? user?.passkeySessionID
|
||||
: user?.twoFactorSessionID;
|
||||
if (!user?.email || !sessionID) {
|
||||
void router.push("/");
|
||||
} else if (user.encryptedToken || user.token) {
|
||||
void router.push("/generate");
|
||||
} else {
|
||||
setSessionID(sessionID);
|
||||
void recoverTwoFactor(twoFactorType, sessionID)
|
||||
.then(setRecoveryResponse)
|
||||
.catch((e: unknown) => {
|
||||
void (async () => {
|
||||
const user = savedPartialLocalUser();
|
||||
const sessionID =
|
||||
twoFactorType == "passkey"
|
||||
? user?.passkeySessionID
|
||||
: user?.twoFactorSessionID;
|
||||
if (!user?.email || !sessionID) {
|
||||
await router.push("/");
|
||||
} else if (user.encryptedToken || user.token) {
|
||||
await router.push("/generate");
|
||||
} else {
|
||||
setSessionID(sessionID);
|
||||
try {
|
||||
setRecoveryResponse(
|
||||
await recoverTwoFactor(twoFactorType, sessionID),
|
||||
);
|
||||
} catch (e) {
|
||||
log.error("Second factor recovery page setup failed", e);
|
||||
if (isHTTPErrorWithStatus(e, 404)) {
|
||||
logout();
|
||||
@@ -86,8 +89,9 @@ const Page: React.FC<RecoverPageProps> = ({ twoFactorType }) => {
|
||||
} else {
|
||||
onGenericError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [
|
||||
twoFactorType,
|
||||
logout,
|
||||
|
||||
@@ -21,6 +21,8 @@ import { unstashRedirect } from "../../services/redirect";
|
||||
|
||||
/**
|
||||
* A page that allows the user to verify their TOTP based second factor.
|
||||
*
|
||||
* See: [Note: Login pages]
|
||||
*/
|
||||
const Page: React.FC = () => {
|
||||
const { logout } = useBaseContext();
|
||||
|
||||
Reference in New Issue
Block a user