diff --git a/web/packages/accounts/components/SignUpContents.tsx b/web/packages/accounts/components/SignUpContents.tsx index 343683c846..2392333843 100644 --- a/web/packages/accounts/components/SignUpContents.tsx +++ b/web/packages/accounts/components/SignUpContents.tsx @@ -15,7 +15,7 @@ import { } from "@mui/material"; import { saveJustSignedUp, - setData, + saveOriginalKeyAttributes, stashReferralSource, } from "ente-accounts/services/accounts-db"; import { @@ -146,7 +146,7 @@ export const SignUpContents: React.FC = ({ } const { masterKey, kek, keyAttributes } = gkResult; - setData("originalKeyAttributes", keyAttributes); + saveOriginalKeyAttributes(keyAttributes); stashSRPSetupAttributes(await generateSRPSetupAttributes(kek)); await generateAndSaveInteractiveKeyAttributes( password, diff --git a/web/packages/accounts/pages/generate.tsx b/web/packages/accounts/pages/generate.tsx index a40ef0ca53..c563bdb245 100644 --- a/web/packages/accounts/pages/generate.tsx +++ b/web/packages/accounts/pages/generate.tsx @@ -8,6 +8,7 @@ import { RecoveryKey } from "ente-accounts/components/RecoveryKey"; import { getData, savedJustSignedUp, + savedOriginalKeyAttributes, saveJustSignedUp, } from "ente-accounts/services/accounts-db"; import { appHomeRoute } from "ente-accounts/services/redirect"; @@ -15,7 +16,7 @@ import { generateSRPSetupAttributes, setupSRP, } from "ente-accounts/services/srp"; -import type { KeyAttributes, User } from "ente-accounts/services/user"; +import type { User } from "ente-accounts/services/user"; import { generateAndSaveInteractiveKeyAttributes, generateKeysAndAttributes, @@ -48,7 +49,6 @@ const Page: React.FC = () => { const router = useRouter(); useEffect(() => { - const keyAttributes: KeyAttributes = getData("originalKeyAttributes"); const user: User = getData("user"); setUser(user); if (!user?.token) { @@ -60,7 +60,7 @@ const Page: React.FC = () => { } else { void router.push(appHomeRoute); } - } else if (keyAttributes?.encryptedKey) { + } else if (savedOriginalKeyAttributes()?.encryptedKey) { void router.push("/credentials"); } else { setLoading(false); diff --git a/web/packages/accounts/pages/verify.tsx b/web/packages/accounts/pages/verify.tsx index a2aa9816fd..1157a5cf28 100644 --- a/web/packages/accounts/pages/verify.tsx +++ b/web/packages/accounts/pages/verify.tsx @@ -9,8 +9,10 @@ import { SecondFactorChoice } from "ente-accounts/components/SecondFactorChoice" import { useSecondFactorChoiceIfNeeded } from "ente-accounts/components/utils/second-factor-choice"; import { getData, + savedOriginalKeyAttributes, saveIsFirstLogin, - setData, + saveKeyAttributes, + saveOriginalKeyAttributes, setLSUser, unstashReferralSource, } from "ente-accounts/services/accounts-db"; @@ -130,12 +132,10 @@ const Page: React.FC = () => { isTwoFactorEnabled: false, }); if (keyAttributes) { - setData("keyAttributes", keyAttributes); - setData("originalKeyAttributes", keyAttributes); + saveKeyAttributes(keyAttributes); + saveOriginalKeyAttributes(keyAttributes); } else { - const originalKeyAttributes = getData( - "originalKeyAttributes", - ); + const originalKeyAttributes = savedOriginalKeyAttributes(); if (originalKeyAttributes) { await putUserKeyAttributes(originalKeyAttributes); } diff --git a/web/packages/accounts/services/accounts-db.ts b/web/packages/accounts/services/accounts-db.ts index 06b4d81384..011ebd56e9 100644 --- a/web/packages/accounts/services/accounts-db.ts +++ b/web/packages/accounts/services/accounts-db.ts @@ -128,6 +128,8 @@ export const isLocalStorageAndIndexedDBMismatch = async () => { * The key attributes are stored in the browser's localStorage. Thus, this * function only works from the main thread, not from web workers (local storage * is not accessible to web workers). + * + * See also: [Note: Original vs interactive key attributes] */ export const savedKeyAttributes = (): KeyAttributes | undefined => { const jsonString = localStorage.getItem("keyAttributes"); @@ -143,6 +145,41 @@ export const savedKeyAttributes = (): KeyAttributes | undefined => { export const saveKeyAttributes = (keyAttributes: KeyAttributes) => localStorage.setItem("keyAttributes", JSON.stringify(keyAttributes)); +/** + * Return the user's original {@link KeyAttributes} if they are present in local + * storage. + * + * [Note: Original vs interactive key attributes] + * + * This function is similar to {@link savedKeyAttributes} except it returns the + * user's "original" key attributes. These are the key attributes that were + * either freshly generated (if the user signed up on this client) or were + * fetched from remote (otherwise). + * + * In contrast, the regular key attributes get overwritten by the local only + * interactive key attributes for the user's convenience. See the documentation + * of {@link generateAndSaveInteractiveKeyAttributes} for more details. + */ +export const savedOriginalKeyAttributes = (): KeyAttributes | undefined => { + const jsonString = localStorage.getItem("originalKeyAttributes"); + if (!jsonString) return undefined; + return RemoteKeyAttributes.parse(JSON.parse(jsonString)); +}; + +/** + * Save the user's {@link KeyAttributes} in local storage. + * + * Once saved, these values are not replaced (in contrast with the regular key + * attributes which can get overwritten with interactive ones). + * + * Use {@link savedOriginalKeyAttributes} to retrieve them. + */ +export const saveOriginalKeyAttributes = (keyAttributes: KeyAttributes) => + localStorage.setItem( + "originalKeyAttributes", + JSON.stringify(keyAttributes), + ); + export const getToken = (): string => { const token = getData("user")?.token; return token; diff --git a/web/packages/accounts/services/session.ts b/web/packages/accounts/services/session.ts index e9d30177b1..8c51839582 100644 --- a/web/packages/accounts/services/session.ts +++ b/web/packages/accounts/services/session.ts @@ -1,4 +1,7 @@ -import { getData } from "ente-accounts/services/accounts-db"; +import { + getData, + savedOriginalKeyAttributes, +} from "ente-accounts/services/accounts-db"; import type { KeyAttributes } from "ente-accounts/services/user"; import { authenticatedRequestHeaders, HTTPError } from "ente-base/http"; import log from "ente-base/log"; @@ -159,7 +162,7 @@ export const isSessionInvalid = async (): Promise => { const { hasSetKeys } = SessionValidityResponse.parse(await res.json()); if (!hasSetKeys) { - const originalKeyAttributes = getData("originalKeyAttributes"); + const originalKeyAttributes = savedOriginalKeyAttributes(); if (originalKeyAttributes) await putUserKeyAttributes(originalKeyAttributes); }