This commit is contained in:
Manav Rathi
2025-03-18 14:49:29 +05:30
parent bad4ae47a4
commit 7182ce015d
35 changed files with 146 additions and 211 deletions

View File

@@ -16,7 +16,7 @@ import { authTheme } from "@/base/components/utils/theme";
import { BaseContext, deriveBaseContext } from "@/base/context";
import { logStartupBanner } from "@/base/log-web";
import HTTPService from "@ente/shared/network/HTTPService";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import "@fontsource-variable/inter";
import { CssBaseline } from "@mui/material";
@@ -33,7 +33,7 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
const { showMiniDialog, miniDialogProps } = useAttributedMiniDialog();
useEffect(() => {
const user = getData(LS_KEYS.USER) as User | undefined | null;
const user = getData("user") as User | undefined | null;
logStartupBanner(user?.id);
HTTPService.setHeaders({ "X-Client-Package": clientPackageName });
}, []);

View File

@@ -9,7 +9,7 @@ import log from "@/base/log";
import VerifyMasterPasswordForm, {
type VerifyMasterPasswordFormProps,
} from "@ente/shared/components/VerifyMasterPasswordForm";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import type { KeyAttributes, User } from "@ente/shared/user/types";
import { t } from "i18next";
import { useCallback, useEffect, useState } from "react";
@@ -60,12 +60,12 @@ export const AuthenticateUser: React.FC<AuthenticateUserProps> = ({
useEffect(() => {
const main = async () => {
try {
const user = getData(LS_KEYS.USER);
const user = getData("user");
if (!user) {
throw Error("User not found");
}
setUser(user);
const keyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
const keyAttributes = getData("keyAttributes");
if (
(!user?.token && !user?.encryptedToken) ||
(keyAttributes && !keyAttributes.memLimit)

View File

@@ -15,11 +15,7 @@ import {
type CollectionSummaries,
} from "@/new/photos/services/collection/ui";
import { includes } from "@/utils/type-guards";
import {
getData,
LS_KEYS,
removeData,
} from "@ente/shared/storage/localStorage";
import { getData, removeData } from "@ente/shared/storage/localStorage";
import { AllAlbums } from "components/Collections/AllAlbums";
import { SetCollectionNamerAttributes } from "components/Collections/CollectionNamer";
import { CollectionShare } from "components/Collections/CollectionShare";
@@ -252,7 +248,7 @@ const useCollectionsSortByLocalState = (initialValue: CollectionsSortBy) => {
//
// This migration added Sep 2024, can be removed after a bit (esp
// since it effectively runs on each app start). (tag: Migration).
const oldData = getData(LS_KEYS.COLLECTION_SORT_BY);
const oldData = getData("collectionSortBy");
if (oldData) {
let newValue: CollectionsSortBy | undefined;
switch (oldData.value) {
@@ -270,7 +266,7 @@ const useCollectionsSortByLocalState = (initialValue: CollectionsSortBy) => {
localStorage.setItem(key, newValue);
setValue(newValue);
}
removeData(LS_KEYS.COLLECTION_SORT_BY);
removeData("collectionSortBy");
}
}
}, []);

View File

@@ -32,7 +32,6 @@ import HTTPService from "@ente/shared/network/HTTPService";
import {
getData,
isLocalStorageAndIndexedDBMismatch,
LS_KEYS,
} from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import "@fontsource-variable/inter";
@@ -66,7 +65,7 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
const logout = useCallback(() => void photosLogout(), []);
useEffect(() => {
const user = getData(LS_KEYS.USER) as User | undefined | null;
const user = getData("user") as User | undefined | null;
logStartupBanner(user?.id);
HTTPService.setHeaders({ "X-Client-Package": clientPackageName });
void isLocalStorageAndIndexedDBMismatch().then((mismatch) => {
@@ -126,11 +125,11 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
useEffect(() => {
const query = new URLSearchParams(window.location.search);
const needsFamilyRedirect = query.get("redirect") == "families";
if (needsFamilyRedirect && getData(LS_KEYS.USER)?.token)
if (needsFamilyRedirect && getData("user")?.token)
redirectToFamilyPortal();
router.events.on("routeChangeStart", () => {
if (needsFamilyRedirect && getData(LS_KEYS.USER)?.token) {
if (needsFamilyRedirect && getData("user")?.token) {
redirectToFamilyPortal();
// https://github.com/vercel/next.js/issues/2476#issuecomment-573460710

View File

@@ -70,7 +70,7 @@ import { usePhotosAppContext } from "@/new/photos/types/context";
import { FlexWrapper } from "@ente/shared/components/Container";
import { getRecoveryKey } from "@ente/shared/crypto/helpers";
import { CustomError } from "@ente/shared/error";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import {
getToken,
isFirstLogin,
@@ -321,7 +321,7 @@ const Page: React.FC = () => {
showPlanSelector();
}
setIsFirstLogin(false);
const user = getData(LS_KEYS.USER);
const user = getData("user");
// TODO: Pass entire snapshot to reducer?
const familyData = userDetailsSnapshot()?.familyData;
dispatch({

View File

@@ -10,7 +10,7 @@ import { albumsAppOrigin, customAPIHost } from "@/base/origins";
import { DevSettings } from "@/new/photos/components/DevSettings";
import { saveKeyInSessionStore } from "@ente/shared/crypto/helpers";
import localForage from "@ente/shared/storage/localForage";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { getKey } from "@ente/shared/storage/sessionStorage";
import { Box, Stack, Typography, styled } from "@mui/material";
@@ -60,7 +60,7 @@ const Page: React.FC = () => {
};
const handleNormalRedirect = async () => {
const user = getData(LS_KEYS.USER);
const user = getData("user");
let key = getKey("encryptionKey");
const electron = globalThis.electron;
if (!key && electron) {

View File

@@ -40,7 +40,7 @@ import {
import type { FamilyData } from "@/new/photos/services/user-details";
import { batch } from "@/utils/array";
import HTTPService from "@ente/shared/network/HTTPService";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { getActualKey } from "@ente/shared/user";
import type { User } from "@ente/shared/user/types";
@@ -190,7 +190,7 @@ export const removeFromCollection = async (
allFiles?: EnteFile[],
) => {
try {
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
const nonUserFiles = [];
const userFiles = [];
for (const file of toRemoveFiles) {
@@ -232,7 +232,7 @@ export const removeUserFiles = async (
const collections = await getLocalCollections();
const collectionsMap = new Map(collections.map((c) => [c.id, c]));
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
for (const [targetCollectionID, files] of groupedFiles.entries()) {
const targetCollection = collectionsMap.get(targetCollectionID);

View File

@@ -21,7 +21,7 @@ import { getAllLocalFiles } from "@/new/photos/services/files";
import { safeDirectoryName, safeFileName } from "@/new/photos/utils/native-fs";
import { PromiseQueue } from "@/utils/promise";
import { CustomError } from "@ente/shared/error";
import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
import { getData, setData } from "@ente/shared/storage/localStorage";
import i18n from "i18next";
import { migrateExport, type ExportRecord } from "./migration";
@@ -120,7 +120,7 @@ class ExportService {
if (this.exportSettings) {
return this.exportSettings;
}
const exportSettings = getData(LS_KEYS.EXPORT);
const exportSettings = getData("export");
this.exportSettings = exportSettings;
return exportSettings;
} catch (e) {
@@ -134,7 +134,7 @@ class ExportService {
const exportSettings = this.getExportSettings();
const newSettings = { ...exportSettings, ...newData };
this.exportSettings = newSettings;
setData(LS_KEYS.EXPORT, newSettings);
setData("export", newSettings);
} catch (e) {
log.error("updateExportSettings failed", e);
throw e;

View File

@@ -15,7 +15,7 @@ import {
sanitizeFilename,
} from "@/new/photos/utils/native-fs";
import { wait } from "@/utils/promise";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import { getIDBasedSortedFiles, getPersonalFiles } from "utils/file";
import {
@@ -135,7 +135,7 @@ async function migrationV0ToV1(
return;
}
const collectionIDPathMap = new Map<number, string>();
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
const localFiles = mergeMetadata(await getAllLocalFiles());
const localCollections = await getLocalCollections();
const personalFiles = getIDBasedSortedFiles(
@@ -170,7 +170,7 @@ async function migrationV2ToV3(
if (!exportRecord?.exportedFiles) {
return;
}
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
const localFiles = mergeMetadata(await getAllLocalFiles());
const personalFiles = getIDBasedSortedFiles(
getPersonalFiles(localFiles, user),

View File

@@ -4,7 +4,7 @@ import { apiURL } from "@/base/origins";
import type { UserDetails } from "@/new/photos/services/user-details";
import { ApiError } from "@ente/shared/error";
import HTTPService from "@ente/shared/network/HTTPService";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { HttpStatusCode } from "axios";
@@ -36,7 +36,7 @@ export const isTokenValid = async (token: string) => {
try {
await putAttributes(
token,
getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES),
getData("originalKeyAttributes"),
);
} catch (e) {
log.error("put attribute failed", e);

View File

@@ -26,7 +26,7 @@ import {
} from "@/new/photos/services/collections";
import { getAllLocalFiles, getLocalFiles } from "@/new/photos/services/files";
import { safeDirectoryName } from "@/new/photos/utils/native-fs";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import { t } from "i18next";
import {
@@ -198,7 +198,7 @@ export const changeCollectionVisibility = async (
visibility,
};
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
if (collection.owner.id === user.id) {
const updatedMagicMetadata = await updateMagicMetadata(
updatedMagicMetadataProps,
@@ -293,7 +293,7 @@ export const changeCollectionSubType = async (
};
export const getUserOwnedCollections = (collections: Collection[]) => {
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
if (!user?.id) {
throw Error("user missing");
}
@@ -341,7 +341,7 @@ export const getOrCreateAlbum = async (
albumName: string,
existingCollections: Collection[],
) => {
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
if (!user?.id) {
throw Error("user missing");
}

View File

@@ -17,7 +17,7 @@ import { FileType } from "@/media/file-type";
import { decodeLivePhoto } from "@/media/live-photo";
import { deleteFromTrash, moveToTrash } from "@/new/photos/services/collection";
import { safeFileName } from "@/new/photos/utils/native-fs";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import { t } from "i18next";
import {
@@ -328,7 +328,7 @@ export const createTypedObjectURL = async (blob: Blob, fileName: string) => {
};
export const getUserOwnedFiles = (files: EnteFile[]) => {
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
if (!user?.id) {
throw Error("user missing");
}

View File

@@ -10,7 +10,7 @@ import log from "@/base/log";
import SingleInputForm, {
type SingleInputFormProps,
} from "@ente/shared/components/SingleInputForm";
import { LS_KEYS, setData, setLSUser } from "@ente/shared/storage/localStorage";
import { setData, setLSUser } from "@ente/shared/storage/localStorage";
import { Input, Stack, Typography } from "@mui/material";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -56,7 +56,7 @@ export const LoginContents: React.FC<LoginContentsProps> = ({
void router.push("/verify");
} else {
await setLSUser({ email });
setData(LS_KEYS.SRP_ATTRIBUTES, srpAttributes);
setData("srpAttributes", srpAttributes);
void router.push("/credentials");
}
} catch (e) {

View File

@@ -5,7 +5,7 @@ import { LinkButton } from "@/base/components/LinkButton";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import { isMuseumHTTPError } from "@/base/http";
import log from "@/base/log";
import { LS_KEYS, setLSUser } from "@ente/shared//storage/localStorage";
import { setLSUser } from "@ente/shared//storage/localStorage";
import { VerticallyCentered } from "@ente/shared/components/Container";
import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
import {
@@ -107,8 +107,8 @@ export const SignUpContents: React.FC<SignUpContentsProps> = ({
const { keyAttributes, masterKey, srpSetupAttributes } =
await generateKeyAndSRPAttributes(passphrase);
setData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES, keyAttributes);
setData(LS_KEYS.SRP_SETUP_ATTRIBUTES, srpSetupAttributes);
setData("originalKeyAttributes", keyAttributes);
setData("srpSetupAttributes", srpSetupAttributes);
await generateAndSaveIntermediateKeyAttributes(
passphrase,
keyAttributes,

View File

@@ -10,7 +10,7 @@ import { LoadingButton } from "@/base/components/mui/LoadingButton";
import { isHTTPErrorWithStatus } from "@/base/http";
import log from "@/base/log";
import { VerticallyCentered } from "@ente/shared/components/Container";
import { LS_KEYS, getData, setLSUser } from "@ente/shared/storage/localStorage";
import { getData, setLSUser } from "@ente/shared/storage/localStorage";
import { Alert, Box, TextField } from "@mui/material";
import { Formik, type FormikHelpers } from "formik";
import { t } from "i18next";
@@ -23,7 +23,7 @@ const Page: React.FC = () => {
const router = useRouter();
useEffect(() => {
const user = getData(LS_KEYS.USER);
const user = getData("user");
if (!user?.token) {
void router.push("/");
}
@@ -86,7 +86,7 @@ const ChangeEmailForm: React.FC = () => {
try {
setLoading(true);
await changeEmail(email, ott!);
await setLSUser({ ...getData(LS_KEYS.USER), email });
await setLSUser({ ...getData("user"), email });
setLoading(false);
void goToApp();
} catch (e) {

View File

@@ -26,7 +26,7 @@ import {
generateLoginSubKey,
saveKeyInSessionStore,
} from "@ente/shared/crypto/helpers";
import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
import { getData, setData } from "@ente/shared/storage/localStorage";
import { getActualKey } from "@ente/shared/user";
import type { KEK, KeyAttributes, User } from "@ente/shared/user/types";
import { t } from "i18next";
@@ -40,7 +40,7 @@ const Page: React.FC = () => {
const router = useRouter();
useEffect(() => {
const user = getData(LS_KEYS.USER);
const user = getData("user");
setUser(user);
if (!user?.token) {
stashRedirect("/change-password");
@@ -56,7 +56,7 @@ const Page: React.FC = () => {
) => {
const cryptoWorker = await sharedCryptoWorker();
const key = await getActualKey();
const keyAttributes: KeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
const keyAttributes: KeyAttributes = getData("keyAttributes");
const kekSalt = await cryptoWorker.generateSaltToDeriveKey();
let kek: KEK;
try {
@@ -111,7 +111,7 @@ const Page: React.FC = () => {
if (user?.email) {
const srpAttributes = await getSRPAttributes(user.email);
if (srpAttributes) {
setData(LS_KEYS.SRP_ATTRIBUTES, srpAttributes);
setData("srpAttributes", srpAttributes);
}
}
@@ -128,7 +128,7 @@ const Page: React.FC = () => {
};
const redirectToAppHome = () => {
setData(LS_KEYS.SHOW_BACK_BUTTON, { value: true });
setData("showBackButton", { value: true });
void router.push(appHomeRoute);
};
@@ -141,7 +141,7 @@ const Page: React.FC = () => {
callback={onSubmit}
buttonText={t("change_password")}
/>
{(getData(LS_KEYS.SHOW_BACK_BUTTON)?.value ?? true) && (
{(getData("showBackButton")?.value ?? true) && (
<AccountsPageFooter>
<LinkButton onClick={router.back}>
{t("go_back")}

View File

@@ -41,12 +41,7 @@ import {
saveKeyInSessionStore,
} from "@ente/shared/crypto/helpers";
import { CustomError } from "@ente/shared/error";
import {
LS_KEYS,
getData,
setData,
setLSUser,
} from "@ente/shared/storage/localStorage";
import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import {
getToken,
isFirstLogin,
@@ -90,14 +85,8 @@ const Page: React.FC = () => {
case "valid":
break;
case "validButPasswordChanged":
setData(
LS_KEYS.KEY_ATTRIBUTES,
session.updatedKeyAttributes,
);
setData(
LS_KEYS.SRP_ATTRIBUTES,
session.updatedSRPAttributes,
);
setData("keyAttributes", session.updatedKeyAttributes);
setData("srpAttributes", session.updatedSRPAttributes);
// Set a flag that causes new interactive key attributes to
// be generated.
setIsFirstLogin(true);
@@ -115,7 +104,7 @@ const Page: React.FC = () => {
useEffect(() => {
const main = async () => {
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
if (!user?.email) {
void router.push("/");
return;
@@ -140,12 +129,8 @@ const Page: React.FC = () => {
}
const kekEncryptedAttributes: B64EncryptionResult =
getKey("keyEncryptionKey");
const keyAttributes: KeyAttributes = getData(
LS_KEYS.KEY_ATTRIBUTES,
);
const srpAttributes: SRPAttributes = getData(
LS_KEYS.SRP_ATTRIBUTES,
);
const keyAttributes: KeyAttributes = getData("keyAttributes");
const srpAttributes: SRPAttributes = getData("srpAttributes");
if (token) {
setSessionValidityCheck(validateSession());
@@ -222,7 +207,7 @@ const Page: React.FC = () => {
const sessionKeyAttributes =
await cryptoWorker.generateKeyAndEncryptToB64(kek);
setKey("keyEncryptionKey", sessionKeyAttributes);
const user = getData(LS_KEYS.USER);
const user = getData("user");
await setLSUser({
...user,
passkeySessionID,
@@ -241,7 +226,7 @@ const Page: React.FC = () => {
const sessionKeyAttributes =
await cryptoWorker.generateKeyAndEncryptToB64(kek);
setKey("keyEncryptionKey", sessionKeyAttributes);
const user = getData(LS_KEYS.USER);
const user = getData("user");
await setLSUser({
...user,
twoFactorSessionID,
@@ -250,7 +235,7 @@ const Page: React.FC = () => {
void router.push("/two-factor/verify");
throw Error(CustomError.TWO_FACTOR_ENABLED);
} else {
const user = getData(LS_KEYS.USER);
const user = getData("user");
await setLSUser({
...user,
token,
@@ -258,8 +243,7 @@ const Page: React.FC = () => {
id,
isTwoFactorEnabled: false,
});
if (keyAttributes)
setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
if (keyAttributes) setData("keyAttributes", keyAttributes);
return keyAttributes;
}
} catch (e) {
@@ -291,13 +275,12 @@ const Page: React.FC = () => {
await saveKeyInSessionStore("encryptionKey", key);
await decryptAndStoreToken(keyAttributes, key);
try {
let srpAttributes: SRPAttributes | null = getData(
LS_KEYS.SRP_ATTRIBUTES,
);
let srpAttributes: SRPAttributes | null =
getData("srpAttributes");
if (!srpAttributes && user) {
srpAttributes = await getSRPAttributes(user.email);
if (srpAttributes) {
setData(LS_KEYS.SRP_ATTRIBUTES, srpAttributes);
setData("srpAttributes", srpAttributes);
}
}
log.debug(() => `userSRPSetupPending ${!srpAttributes}`);

View File

@@ -21,7 +21,7 @@ import {
generateAndSaveIntermediateKeyAttributes,
saveKeyInSessionStore,
} from "@ente/shared/crypto/helpers";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import {
justSignedUp,
setJustSignedUp,
@@ -44,10 +44,8 @@ const Page: React.FC = () => {
useEffect(() => {
const key: string = getKey("encryptionKey");
const keyAttributes: KeyAttributes = getData(
LS_KEYS.ORIGINAL_KEY_ATTRIBUTES,
);
const user: User = getData(LS_KEYS.USER);
const keyAttributes: KeyAttributes = getData("originalKeyAttributes");
const user: User = getData("user");
setUser(user);
if (!user?.token) {
void router.push("/");

View File

@@ -2,7 +2,7 @@ import { AccountsPageContents } from "@/accounts/components/layouts/centered-pap
import { LoginContents } from "@/accounts/components/LoginContents";
import { LoadingIndicator } from "@/base/components/loaders";
import { customAPIHost } from "@/base/origins";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
@@ -14,7 +14,7 @@ const Page: React.FC = () => {
useEffect(() => {
void customAPIHost().then(setHost);
const user = getData(LS_KEYS.USER);
const user = getData("user");
if (user?.email) {
void router.push("/verify");
}

View File

@@ -3,12 +3,7 @@ import { LoadingIndicator } from "@/base/components/loaders";
import { fromB64URLSafeNoPaddingString } from "@/base/crypto/libsodium";
import log from "@/base/log";
import { nullToUndefined } from "@/utils/transform";
import {
LS_KEYS,
getData,
setData,
setLSUser,
} from "@ente/shared/storage/localStorage";
import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import { useRouter } from "next/router";
import React, { useEffect } from "react";
@@ -95,8 +90,8 @@ const saveCredentialsAndNavigateTo = async (
// user is signing into an existing account).
const { keyAttributes, encryptedToken, token, id } = decodedResponse;
await setLSUser({ ...getData(LS_KEYS.USER), token, encryptedToken, id });
setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
await setLSUser({ ...getData("user"), token, encryptedToken, id });
setData("keyAttributes", keyAttributes);
return unstashRedirect() ?? "/credentials";
};

View File

@@ -16,7 +16,7 @@ import {
decryptAndStoreToken,
saveKeyInSessionStore,
} from "@ente/shared/crypto/helpers";
import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
import { getData, setData } from "@ente/shared/storage/localStorage";
import { getKey } from "@ente/shared/storage/sessionStorage";
import type { KeyAttributes, User } from "@ente/shared/user/types";
import { t } from "i18next";
@@ -38,8 +38,8 @@ const Page: React.FC = () => {
const router = useRouter();
useEffect(() => {
const user: User = getData(LS_KEYS.USER);
const keyAttributes: KeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
const user: User = getData("user");
const keyAttributes: KeyAttributes = getData("keyAttributes");
const key = getKey("encryptionKey");
if (!user?.email) {
void router.push("/");
@@ -88,7 +88,7 @@ const Page: React.FC = () => {
await saveKeyInSessionStore("encryptionKey", masterKey);
await decryptAndStoreToken(keyAttr, masterKey);
setData(LS_KEYS.SHOW_BACK_BUTTON, { value: false });
setData("showBackButton", { value: false });
void router.push("/change-password");
} catch (e) {
log.error("password recovery failed", e);

View File

@@ -2,7 +2,7 @@ import { AccountsPageContents } from "@/accounts/components/layouts/centered-pap
import { SignUpContents } from "@/accounts/components/SignUpContents";
import { LoadingIndicator } from "@/base/components/loaders";
import { customAPIHost } from "@/base/origins";
import { LS_KEYS, getData } from "@ente/shared//storage/localStorage";
import { getData } from "@ente/shared//storage/localStorage";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
@@ -14,7 +14,7 @@ const Page: React.FC = () => {
useEffect(() => {
void customAPIHost().then(setHost);
const user = getData(LS_KEYS.USER);
const user = getData("user");
if (user?.email) {
void router.push("/verify");
}

View File

@@ -18,12 +18,7 @@ import SingleInputForm, {
type SingleInputFormProps,
} from "@ente/shared/components/SingleInputForm";
import { ApiError } from "@ente/shared/error";
import {
LS_KEYS,
getData,
setData,
setLSUser,
} from "@ente/shared/storage/localStorage";
import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import { Link } from "@mui/material";
import { HttpStatusCode } from "axios";
import { t } from "i18next";
@@ -52,7 +47,7 @@ const Page: React.FC<RecoverPageProps> = ({ twoFactorType }) => {
const router = useRouter();
useEffect(() => {
const user = getData(LS_KEYS.USER);
const user = getData("user");
const sid = user.passkeySessionID || user.twoFactorSessionID;
if (!user?.email || !sid) {
void router.push("/");
@@ -127,13 +122,13 @@ const Page: React.FC<RecoverPageProps> = ({ twoFactorType }) => {
);
const { keyAttributes, encryptedToken, token, id } = resp;
await setLSUser({
...getData(LS_KEYS.USER),
...getData("user"),
token,
encryptedToken,
id,
isTwoFactorEnabled: false,
});
setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
setData("keyAttributes", keyAttributes);
void router.push("/credentials");
} catch (e) {
log.error("two factor recovery failed", e);

View File

@@ -8,7 +8,7 @@ import { LinkButton } from "@/base/components/LinkButton";
import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator";
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { encryptWithRecoveryKey } from "@ente/shared/crypto/helpers";
import { getData, LS_KEYS, setLSUser } from "@ente/shared/storage/localStorage";
import { getData, setLSUser } from "@ente/shared/storage/localStorage";
import { Paper, Stack, styled, Typography } from "@mui/material";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -35,7 +35,7 @@ const Page: React.FC = () => {
encryptedTwoFactorSecret,
twoFactorSecretDecryptionNonce,
});
await setLSUser({ ...getData(LS_KEYS.USER), isTwoFactorEnabled: true });
await setLSUser({ ...getData("user"), isTwoFactorEnabled: true });
await router.push(appHomeRoute);
};

View File

@@ -3,12 +3,7 @@ import { verifyTwoFactor } from "@/accounts/services/user";
import { LinkButton } from "@/base/components/LinkButton";
import { useBaseContext } from "@/base/context";
import { HTTPError } from "@/base/http";
import {
LS_KEYS,
getData,
setData,
setLSUser,
} from "@ente/shared/storage/localStorage";
import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -28,7 +23,7 @@ const Page: React.FC = () => {
const router = useRouter();
useEffect(() => {
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
if (!user?.email || !user.twoFactorSessionID) {
void router.push("/");
} else if (
@@ -45,13 +40,8 @@ const Page: React.FC = () => {
try {
const resp = await verifyTwoFactor(otp, sessionID);
const { keyAttributes, encryptedToken, token, id } = resp;
await setLSUser({
...getData(LS_KEYS.USER),
token,
encryptedToken,
id,
});
setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes!);
await setLSUser({ ...getData("user"), token, encryptedToken, id });
setData("keyAttributes", keyAttributes!);
await router.push(unstashRedirect() ?? "/credentials");
} catch (e) {
if (e instanceof HTTPError && e.res.status == 404) {

View File

@@ -27,12 +27,7 @@ import SingleInputForm, {
} from "@ente/shared/components/SingleInputForm";
import { ApiError } from "@ente/shared/error";
import localForage from "@ente/shared/storage/localForage";
import {
getData,
LS_KEYS,
setData,
setLSUser,
} from "@ente/shared/storage/localStorage";
import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import {
getLocalReferralSource,
setIsFirstLogin,
@@ -63,7 +58,7 @@ const Page: React.FC = () => {
useEffect(() => {
const main = async () => {
const user: User = getData(LS_KEYS.USER);
const user: User = getData("user");
const redirect = await redirectionIfNeeded(user);
if (redirect) {
@@ -96,7 +91,7 @@ const Page: React.FC = () => {
await verifyEmail(email, ott, cleanedReferral),
);
if (passkeySessionID) {
const user = getData(LS_KEYS.USER);
const user = getData("user");
await setLSUser({
...user,
passkeySessionID,
@@ -132,19 +127,18 @@ const Page: React.FC = () => {
isTwoFactorEnabled: false,
});
if (keyAttributes) {
setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
setData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES, keyAttributes);
setData("keyAttributes", keyAttributes);
setData("originalKeyAttributes", keyAttributes);
} else {
if (getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES)) {
if (getData("originalKeyAttributes")) {
await putAttributes(
token!,
getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES),
getData("originalKeyAttributes"),
);
}
if (getData(LS_KEYS.SRP_SETUP_ATTRIBUTES)) {
const srpSetupAttributes: SRPSetupAttributes = getData(
LS_KEYS.SRP_SETUP_ATTRIBUTES,
);
if (getData("srpSetupAttributes")) {
const srpSetupAttributes: SRPSetupAttributes =
getData("srpSetupAttributes");
await configureSRP(srpSetupAttributes);
}
}
@@ -271,7 +265,7 @@ const redirectionIfNeeded = async (user: User | undefined) => {
return "/";
}
const keyAttributes: KeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
const keyAttributes: KeyAttributes = getData("keyAttributes");
if (keyAttributes?.encryptedKey && (user.token || user.encryptedToken)) {
return "/credentials";
@@ -291,7 +285,7 @@ const redirectionIfNeeded = async (user: User | undefined) => {
// saved them). If they are present and indicate that email verification is
// not required, redirect to the password verification page.
const srpAttributes: SRPAttributes = getData(LS_KEYS.SRP_ATTRIBUTES);
const srpAttributes: SRPAttributes = getData("srpAttributes");
if (srpAttributes && !srpAttributes.isEmailMFAEnabled) {
// Fetch the latest SRP attributes instead of relying on the potentially
// stale stored values. This is an infrequent scenario path, so extra

View File

@@ -12,12 +12,7 @@ import log from "@/base/log";
import { apiURL } from "@/base/origins";
import { getRecoveryKey } from "@ente/shared/crypto/helpers";
import HTTPService from "@ente/shared/network/HTTPService";
import {
getData,
LS_KEYS,
setData,
setLSUser,
} from "@ente/shared/storage/localStorage";
import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { z } from "zod";
import { unstashRedirect } from "./redirect";
@@ -265,8 +260,8 @@ export const saveCredentialsAndNavigateTo = async (
// /passkeys/finish page.
const { id, encryptedToken, keyAttributes } = response;
await setLSUser({ ...getData(LS_KEYS.USER), encryptedToken, id });
setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes!);
await setLSUser({ ...getData("user"), encryptedToken, id });
setData("keyAttributes", keyAttributes!);
return unstashRedirect() ?? "/credentials";
};

View File

@@ -1,7 +1,7 @@
import { authenticatedRequestHeaders, HTTPError } from "@/base/http";
import { ensureLocalUser } from "@/base/local-user";
import { apiURL } from "@/base/origins";
import { getData, LS_KEYS } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import type { KeyAttributes } from "@ente/shared/user/types";
import type { SRPAttributes } from "./srp-remote";
import { getSRPAttributes } from "./srp-remote";
@@ -85,7 +85,7 @@ export const checkSessionValidity = async (): Promise<SessionValidity> => {
// We should have these values locally if we reach here.
const email = ensureLocalUser().email;
const localSRPAttributes = getData(LS_KEYS.SRP_ATTRIBUTES)!;
const localSRPAttributes = getData("srpAttributes")!;
// Fetch the remote SRP attributes.
//

View File

@@ -29,7 +29,7 @@ export type LocalUser = z.infer<typeof LocalUser>;
* The user's data is stored in the browser's localStorage.
*/
export const localUser = (): LocalUser | undefined => {
// TODO(MR): duplicate of LS_KEYS.USER
// TODO: duplicate of getData("user")
const s = localStorage.getItem("user");
if (!s) return undefined;
return LocalUser.parse(JSON.parse(s));

View File

@@ -12,7 +12,7 @@ import {
} from "@/base/components/mui/SidebarDrawer";
import { useBaseContext } from "@/base/context";
import { disable2FA, get2FAStatus } from "@/new/photos/services/user";
import { LS_KEYS, getData, setLSUser } from "@ente/shared/storage/localStorage";
import { getData, setLSUser } from "@ente/shared/storage/localStorage";
import LockIcon from "@mui/icons-material/Lock";
import { Stack, Typography } from "@mui/material";
import { t } from "i18next";
@@ -28,7 +28,7 @@ export const TwoFactorSettings: React.FC<
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const isTwoFactorEnabled =
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
getData(LS_KEYS.USER).isTwoFactorEnabled ?? false;
getData("user").isTwoFactorEnabled ?? false;
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
setIsTwoFactorEnabled(isTwoFactorEnabled);
}, []);
@@ -40,7 +40,7 @@ export const TwoFactorSettings: React.FC<
setIsTwoFactorEnabled(isEnabled);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
await setLSUser({
...getData(LS_KEYS.USER),
...getData("user"),
isTwoFactorEnabled: isEnabled,
});
})();
@@ -121,10 +121,7 @@ const ManageDrawerContents: React.FC<ContentsProps> = ({ onRootClose }) => {
const disable = async () => {
await disable2FA();
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
await setLSUser({
...getData(LS_KEYS.USER),
isTwoFactorEnabled: false,
});
await setLSUser({ ...getData("user"), isTwoFactorEnabled: false });
onRootClose();
};

View File

@@ -29,7 +29,7 @@ import {
} from "@/new/photos/services/files";
import HTTPService from "@ente/shared/network/HTTPService";
import localForage from "@ente/shared/storage/localForage";
import { getData, LS_KEYS } from "@ente/shared/storage/localStorage";
import { getData } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { getActualKey } from "@ente/shared/user";
import { isHiddenCollection } from "./collection";
@@ -200,7 +200,7 @@ export const getCollectionWithSecrets = async (
masterKey: string,
): Promise<Collection> => {
const cryptoWorker = await sharedCryptoWorker();
const userID = getData(LS_KEYS.USER).id;
const userID = getData("user").id;
let collectionKey: string;
if (collection.owner.id === userID) {
collectionKey = await cryptoWorker.decryptB64(
@@ -209,7 +209,7 @@ export const getCollectionWithSecrets = async (
masterKey,
);
} else {
const keyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
const keyAttributes = getData("keyAttributes");
const secretKey = await cryptoWorker.decryptB64(
keyAttributes.encryptedSecretKey,
keyAttributes.secretKeyDecryptionNonce,

View File

@@ -7,7 +7,7 @@ import {
nullishToZero,
nullToUndefined,
} from "@/utils/transform";
import { getData, LS_KEYS, setLSUser } from "@ente/shared/storage/localStorage";
import { getData, setLSUser } from "@ente/shared/storage/localStorage";
import { z } from "zod";
/**
@@ -243,7 +243,7 @@ export const syncUserDetails = async () => {
//
// Added Nov 2024, and can be removed after a while (tag: Migration).
const oldLSUser = getData(LS_KEYS.USER) as unknown;
const oldLSUser = getData("user") as unknown;
const hasMatchingEmail =
oldLSUser &&
typeof oldLSUser == "object" &&
@@ -253,7 +253,7 @@ export const syncUserDetails = async () => {
if (!hasMatchingEmail) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
await setLSUser({ ...getData(LS_KEYS.USER), email: userDetails.email });
await setLSUser({ ...getData("user"), email: userDetails.email });
throw new Error("Email in local storage did not match user details");
}
};

View File

@@ -2,14 +2,9 @@ import { setRecoveryKey } from "@/accounts/services/user";
import { sharedCryptoWorker } from "@/base/crypto";
import log from "@/base/log";
import { masterKeyFromSession } from "@/base/session";
import {
LS_KEYS,
getData,
setData,
setLSUser,
} from "@ente/shared/storage/localStorage";
import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { SessionKey, setKey } from "@ente/shared/storage/sessionStorage";
import { type SessionKey, setKey } from "@ente/shared/storage/sessionStorage";
import { getActualKey } from "@ente/shared/user";
import type { KeyAttributes } from "@ente/shared/user/types";
@@ -23,7 +18,7 @@ export async function decryptAndStoreToken(
masterKey: string,
) {
const cryptoWorker = await sharedCryptoWorker();
const user = getData(LS_KEYS.USER);
const user = getData("user");
let decryptedToken = null;
const { encryptedToken } = user;
if (encryptedToken && encryptedToken.length > 0) {
@@ -76,7 +71,7 @@ export async function generateAndSaveIntermediateKeyAttributes(
opsLimit: intermediateKek.opsLimit,
memLimit: intermediateKek.memLimit,
});
setData(LS_KEYS.KEY_ATTRIBUTES, intermediateKeyAttributes);
setData("keyAttributes", intermediateKeyAttributes);
return intermediateKeyAttributes;
}
@@ -124,7 +119,7 @@ export const getRecoveryKey = async () => {
try {
const cryptoWorker = await sharedCryptoWorker();
const keyAttributes: KeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
const keyAttributes: KeyAttributes = getData("keyAttributes");
const {
recoveryKeyEncryptedWithMasterKey,
recoveryKeyDecryptionNonce,
@@ -152,7 +147,7 @@ export const getRecoveryKey = async () => {
// sign up
async function createNewRecoveryKey() {
const masterKey = await getActualKey();
const existingAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
const existingAttributes = getData("keyAttributes");
const cryptoWorker = await sharedCryptoWorker();
@@ -177,7 +172,7 @@ async function createNewRecoveryKey() {
existingAttributes,
recoveryKeyAttributes,
);
setData(LS_KEYS.KEY_ATTRIBUTES, updatedKeyAttributes);
setData("keyAttributes", updatedKeyAttributes);
return recoveryKey;
}
@@ -193,7 +188,7 @@ export const decryptDeleteAccountChallenge = async (
) => {
const cryptoWorker = await sharedCryptoWorker();
const masterKey = await masterKeyFromSession();
const keyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
const keyAttributes = getData("keyAttributes");
const secretKey = await cryptoWorker.decryptBoxB64(
{
encryptedData: keyAttributes.encryptedSecretKey,

View File

@@ -1,28 +1,26 @@
import { LS_KEYS, getData, setData } from ".";
import { getData, setData } from ".";
export const getToken = (): string => {
const token = getData(LS_KEYS.USER)?.token;
const token = getData("user")?.token;
return token;
};
export const isFirstLogin = () =>
getData(LS_KEYS.IS_FIRST_LOGIN)?.status ?? false;
export const isFirstLogin = () => getData("isFirstLogin")?.status ?? false;
export function setIsFirstLogin(status: boolean) {
setData(LS_KEYS.IS_FIRST_LOGIN, { status });
setData("isFirstLogin", { status });
}
export const justSignedUp = () =>
getData(LS_KEYS.JUST_SIGNED_UP)?.status ?? false;
export const justSignedUp = () => getData("justSignedUp")?.status ?? false;
export function setJustSignedUp(status: boolean) {
setData(LS_KEYS.JUST_SIGNED_UP, { status });
setData("justSignedUp", { status });
}
export function getLocalReferralSource() {
return getData(LS_KEYS.REFERRAL_SOURCE)?.source;
return getData("referralSource")?.source;
}
export function setLocalReferralSource(source: string) {
setData(LS_KEYS.REFERRAL_SOURCE, { source });
setData("referralSource", { source });
}

View File

@@ -1,30 +1,30 @@
import { getKVS, removeKV, setKV } from "@/base/kv";
import log from "@/base/log";
export enum LS_KEYS {
USER = "user",
KEY_ATTRIBUTES = "keyAttributes",
ORIGINAL_KEY_ATTRIBUTES = "originalKeyAttributes",
IS_FIRST_LOGIN = "isFirstLogin",
JUST_SIGNED_UP = "justSignedUp",
SHOW_BACK_BUTTON = "showBackButton",
EXPORT = "export",
export type LocalStorageKey =
| "user"
| "keyAttributes"
| "originalKeyAttributes"
| "isFirstLogin"
| "justSignedUp"
| "showBackButton"
| "export"
// LOGS = "logs",
// Migrated to (and only used by) useCollectionsSortByLocalState.
COLLECTION_SORT_BY = "collectionSortBy",
| "collectionSortBy"
// Moved to the new wrapper @/base/local-storage
// LOCALE = 'locale',
SRP_SETUP_ATTRIBUTES = "srpSetupAttributes",
SRP_ATTRIBUTES = "srpAttributes",
REFERRAL_SOURCE = "referralSource",
}
| "srpSetupAttributes"
| "srpAttributes"
| "referralSource";
export const setData = (key: LS_KEYS, value: object) =>
export const setData = (key: LocalStorageKey, value: object) =>
localStorage.setItem(key, JSON.stringify(value));
export const removeData = (key: LS_KEYS) => localStorage.removeItem(key);
export const removeData = (key: LocalStorageKey) =>
localStorage.removeItem(key);
export const getData = (key: LS_KEYS) => {
export const getData = (key: LocalStorageKey) => {
try {
if (
typeof localStorage === "undefined" ||
@@ -48,7 +48,7 @@ export const getData = (key: LS_KEYS) => {
// Creating a new function here to act as a funnel point.
export const setLSUser = async (user: object) => {
await migrateKVToken(user);
setData(LS_KEYS.USER, user);
setData("user", user);
};
/**
@@ -66,7 +66,7 @@ export const migrateKVToken = async (user: unknown) => {
// Throw an error if the data is in local storage but not in IndexedDB. This
// is a pre-cursor to inlining this code.
// TODO(REL): Remove this sanity check after a few days.
const oldLSUser = getData(LS_KEYS.USER);
const oldLSUser = getData("user");
const wasMissing =
oldLSUser &&
typeof oldLSUser == "object" &&
@@ -103,7 +103,7 @@ export const migrateKVToken = async (user: unknown) => {
* token in local storage, then it should also be present in IndexedDB.
*/
export const isLocalStorageAndIndexedDBMismatch = async () => {
const oldLSUser = getData(LS_KEYS.USER);
const oldLSUser = getData("user");
return (
oldLSUser &&
typeof oldLSUser == "object" &&