From 9a5bac774ecb8c9ecafa822b68e436f7ad8bccff Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 17:24:08 +0530 Subject: [PATCH 01/10] Unused --- web/packages/shared/components/Container.tsx | 7 - .../shared/components/SingleInputForm.tsx | 203 ------------------ 2 files changed, 210 deletions(-) delete mode 100644 web/packages/shared/components/Container.tsx delete mode 100644 web/packages/shared/components/SingleInputForm.tsx diff --git a/web/packages/shared/components/Container.tsx b/web/packages/shared/components/Container.tsx deleted file mode 100644 index 6d6f935d7e..0000000000 --- a/web/packages/shared/components/Container.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { Box, styled } from "@mui/material"; - -export const FlexWrapper = styled(Box)` - display: flex; - width: 100%; - align-items: center; -`; diff --git a/web/packages/shared/components/SingleInputForm.tsx b/web/packages/shared/components/SingleInputForm.tsx deleted file mode 100644 index e05627e40d..0000000000 --- a/web/packages/shared/components/SingleInputForm.tsx +++ /dev/null @@ -1,203 +0,0 @@ -import { FormHelperText } from "@mui/material"; -import TextField from "@mui/material/TextField"; -import { FocusVisibleButton } from "ente-base/components/mui/FocusVisibleButton"; -import { LoadingButton } from "ente-base/components/mui/LoadingButton"; -import { ShowHidePasswordInputAdornment } from "ente-base/components/mui/PasswordInputAdornment"; -import { FlexWrapper } from "ente-shared/components/Container"; -import { Formik, type FormikHelpers, type FormikState } from "formik"; -import { t } from "i18next"; -import { useCallback, useMemo, useState } from "react"; -import * as Yup from "yup"; - -interface formValues { - inputValue: string; -} -export interface SingleInputFormProps { - callback: ( - inputValue: string, - setFieldError: (errorMessage: string) => void, - resetForm: (nextState?: Partial>) => void, - ) => Promise; - fieldType: "text" | "email" | "password"; - /** deprecated: Use realPlaceholder */ - placeholder?: string; - /** - * Placeholder - * - * The existing `placeholder` property uses the placeholder as a label (i.e. - * it doesn't appear as the placeholder within the text input area but - * rather as the label on top of it). This happens conditionally, so it is - * not a matter of simple rename. - * - * Gradually migrate the existing UI to use this property when we really - * want a placeholder, and then create a separate label property for places - * that actually want to set the label. - */ - realPlaceholder?: string; - /** - * Label to show on top of the text input area. - * - * Sibling of {@link realPlaceholder}. - */ - realLabel?: string; - buttonText: string; - submitButtonProps?: any; - initialValue?: string; - secondaryButtonAction?: () => void; - disableAutoFocus?: boolean; - hiddenPreInput?: any; - caption?: any; - hiddenPostInput?: any; - autoComplete?: string; - blockButton?: boolean; - hiddenLabel?: boolean; - disableAutoComplete?: boolean; -} - -/** - * Deprecated version, gradually migrate to use the one from ente-base. - */ -export default function SingleInputForm(props: SingleInputFormProps) { - const { submitButtonProps } = props; - const { sx: buttonSx, ...restSubmitButtonProps } = submitButtonProps ?? {}; - - const [loading, SetLoading] = useState(false); - const [showPassword, setShowPassword] = useState(false); - - const handleToggleShowHidePassword = useCallback( - () => setShowPassword((show) => !show), - [], - ); - - const submitForm = async ( - values: formValues, - { setFieldError, resetForm }: FormikHelpers, - ) => { - SetLoading(true); - await props.callback( - values.inputValue, - (message) => setFieldError("inputValue", message), - resetForm, - ); - SetLoading(false); - }; - - const validationSchema = useMemo(() => { - switch (props.fieldType) { - case "text": - return Yup.object().shape({ - inputValue: Yup.string().required(t("required")), - }); - case "password": - return Yup.object().shape({ - inputValue: Yup.string().required(t("required")), - }); - case "email": - return Yup.object().shape({ - inputValue: Yup.string() - .email(t("invalid_email_error")) - .required(t("required")), - }); - } - }, [props.fieldType]); - - return ( - - initialValues={{ inputValue: props.initialValue ?? "" }} - onSubmit={submitForm} - validationSchema={validationSchema} - validateOnChange={false} - validateOnBlur={false} - > - {({ values, errors, handleChange, handleSubmit }) => ( -
- {props.hiddenPreInput} - - ), - }, - }} - /> - - {props.caption} - - {props.hiddenPostInput} - - {props.secondaryButtonAction && ( - - {t("cancel")} - - )} - - {props.buttonText} - - - - )} - - ); -} From 334a996357b7e977d7c09319453f3bc1867937ca Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 17:27:46 +0530 Subject: [PATCH 02/10] Scope --- .../components/VerifyMasterPasswordForm.tsx | 14 +++++++------- web/packages/shared/error/index.ts | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx index b6a812754f..2a7e576616 100644 --- a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx +++ b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx @@ -147,17 +147,20 @@ export const VerifyMasterPasswordForm: React.FC< throw Error("couldn't get key attributes"); } + let key: string; try { - const key = await cryptoWorker.decryptB64( + key = await cryptoWorker.decryptB64( keyAttributes.encryptedKey, keyAttributes.keyDecryptionNonce, kek, ); - onVerify(key, kek, keyAttributes, passphrase); } catch (e) { - log.error("user entered a wrong password", e); - throw Error(CustomError.INCORRECT_PASSWORD); + log.warn("Incorrect password", e); + setFieldError(t("incorrect_password")); + return; } + + onVerify(key, kek, keyAttributes, passphrase); } catch (e) { if (e instanceof Error) { if (e.message === CustomError.TWO_FACTOR_ENABLED) { @@ -166,9 +169,6 @@ export const VerifyMasterPasswordForm: React.FC< } log.error("failed to verify passphrase", e); switch (e.message) { - case CustomError.INCORRECT_PASSWORD: - setFieldError(t("incorrect_password")); - break; case CustomError.INCORRECT_PASSWORD_OR_NO_ACCOUNT: setFieldError(t("incorrect_password_or_no_account")); break; diff --git a/web/packages/shared/error/index.ts b/web/packages/shared/error/index.ts index 3aa47fa01c..dd6d7d961c 100644 --- a/web/packages/shared/error/index.ts +++ b/web/packages/shared/error/index.ts @@ -40,7 +40,6 @@ export const CustomError = { BAD_REQUEST: "bad request", SUBSCRIPTION_NEEDED: "subscription not present", NOT_FOUND: "not found ", - INCORRECT_PASSWORD: "incorrect password", INCORRECT_PASSWORD_OR_NO_ACCOUNT: "incorrect password or no such account", UPLOAD_CANCELLED: "upload cancelled", UPDATE_EXPORTED_RECORD_FAILED: "update file exported record failed", From 86f282bb06190ac465ae58e87ecf01a4a23f966c Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 17:36:50 +0530 Subject: [PATCH 03/10] Scope --- .../components/VerifyMasterPasswordForm.tsx | 128 +++++++++--------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx index 2a7e576616..19f290ede1 100644 --- a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx +++ b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx @@ -101,7 +101,12 @@ export const VerifyMasterPasswordForm: React.FC< return; } - await verifyPassphrase(password, setPasswordFieldError); + try { + await verifyPassphrase(password, setPasswordFieldError); + } catch (e) { + log.error("Failed to to verify passphrase", e); + setPasswordFieldError(t("generic_error")); + } }, }); @@ -109,76 +114,75 @@ export const VerifyMasterPasswordForm: React.FC< passphrase: string, setFieldError: (message: string) => void, ) => { - try { - const cryptoWorker = await sharedCryptoWorker(); - let kek: string; - if (srpAttributes) { - try { - kek = await cryptoWorker.deriveKey( - passphrase, - srpAttributes.kekSalt, - srpAttributes.opsLimit, - srpAttributes.memLimit, - ); - } catch (e) { - log.error("Failed to derive kek", e); - setFieldError(t("weak_device_hint")); - return; - } - } else if (keyAttributes) { - try { - kek = await cryptoWorker.deriveKey( - passphrase, - keyAttributes.kekSalt, - keyAttributes.opsLimit, - keyAttributes.memLimit, - ); - } catch (e) { - log.error("Failed to derive kek", e); - setFieldError(t("weak_device_hint")); - return; - } - } else throw new Error("Both SRP and key attributes are missing"); - - if (!keyAttributes && typeof getKeyAttributes == "function") { - keyAttributes = await getKeyAttributes(kek); - } - if (!keyAttributes) { - throw Error("couldn't get key attributes"); - } - - let key: string; + const cryptoWorker = await sharedCryptoWorker(); + let kek: string; + if (srpAttributes) { try { - key = await cryptoWorker.decryptB64( - keyAttributes.encryptedKey, - keyAttributes.keyDecryptionNonce, - kek, + kek = await cryptoWorker.deriveKey( + passphrase, + srpAttributes.kekSalt, + srpAttributes.opsLimit, + srpAttributes.memLimit, ); } catch (e) { - log.warn("Incorrect password", e); - setFieldError(t("incorrect_password")); + log.error("Failed to derive kek", e); + setFieldError(t("weak_device_hint")); return; } + } else if (keyAttributes) { + try { + kek = await cryptoWorker.deriveKey( + passphrase, + keyAttributes.kekSalt, + keyAttributes.opsLimit, + keyAttributes.memLimit, + ); + } catch (e) { + log.error("Failed to derive kek", e); + setFieldError(t("weak_device_hint")); + return; + } + } else throw new Error("Both SRP and key attributes are missing"); - onVerify(key, kek, keyAttributes, passphrase); - } catch (e) { - if (e instanceof Error) { - if (e.message === CustomError.TWO_FACTOR_ENABLED) { - // two factor enabled, user has been redirected to two factor page - return; + if (!keyAttributes && typeof getKeyAttributes == "function") { + try { + keyAttributes = await getKeyAttributes(kek); + } catch (e) { + if (e instanceof Error) { + switch (e.message) { + case CustomError.TWO_FACTOR_ENABLED: + // Two factor enabled, user has been redirected to + // the two-factor verification page. + return; + + case CustomError.INCORRECT_PASSWORD_OR_NO_ACCOUNT: + log.error("Incorrect password or no account", e); + setFieldError( + t("incorrect_password_or_no_account"), + ); + return; + } } - log.error("failed to verify passphrase", e); - switch (e.message) { - case CustomError.INCORRECT_PASSWORD_OR_NO_ACCOUNT: - setFieldError(t("incorrect_password_or_no_account")); - break; - default: - setFieldError(t("generic_error")); - } - } else { - log.error("failed to verify passphrase", e); + throw e; } } + + if (!keyAttributes) throw Error("Couldn't get key attributes"); + + let key: string; + try { + key = await cryptoWorker.decryptB64( + keyAttributes.encryptedKey, + keyAttributes.keyDecryptionNonce, + kek, + ); + } catch (e) { + log.warn("Incorrect password", e); + setFieldError(t("incorrect_password")); + return; + } + + onVerify(key, kek, keyAttributes, passphrase); }; return ( From ce591e62679a120880478e9eff1f6276013edec9 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 18:11:28 +0530 Subject: [PATCH 04/10] Conv --- .../accounts/components/VerifyMasterPasswordForm.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx index 19f290ede1..cbd474aa01 100644 --- a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx +++ b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx @@ -171,9 +171,11 @@ export const VerifyMasterPasswordForm: React.FC< let key: string; try { - key = await cryptoWorker.decryptB64( - keyAttributes.encryptedKey, - keyAttributes.keyDecryptionNonce, + key = await cryptoWorker.decryptBoxB64( + { + encryptedData: keyAttributes.encryptedKey, + nonce: keyAttributes.keyDecryptionNonce, + }, kek, ); } catch (e) { From 5d3f431ee0a329ef57520d4e3b5c4ee37e17353a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 18:20:51 +0530 Subject: [PATCH 05/10] Doc --- web/packages/shared/user/types.ts | 69 +++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/web/packages/shared/user/types.ts b/web/packages/shared/user/types.ts index 86b1c1c261..cf0d124665 100644 --- a/web/packages/shared/user/types.ts +++ b/web/packages/shared/user/types.ts @@ -2,19 +2,82 @@ * A structure containing the key related attributes for a user. */ export interface KeyAttributes { - kekSalt: string; + /** + * The user's master key encrypted with the key encryption key. + * + * [Note: Key encryption key] + * + * The user's master key is encrypted with a "key encryption key" (lovingly + * called a "kek" sometimes). + * + * The kek itself is derived from the user's passphrase. + * + * 1. User enters passphrase on new device. + * + * 2. Client derives kek from this passphrase (using the {@link kekSalt}, + * {@link opsLimit} and {@link memLimit} as parameters for the + * derivation). + * + * 3. Client use kek to decrypt the master key from {@link encryptedKey} and + * {@link keyDecryptionNonce}. + */ encryptedKey: string; + /** + * The nonce used during the encryption of the master key. + * + * @see {@link encryptedKey}. + */ keyDecryptionNonce: string; + /** + * The salt used during the derivation of the kek. + * + * See: [Note: Key encryption key]. + */ + kekSalt: string; + /** + * The operation limit used during the derivation of the kek. + * + * The {@link opsLimit} and {@link memLimit} are complementary parameters + * that define the amount of work done by the key derivation function. See + * the {@link deriveKey}, {@link deriveSensitiveKey} and + * {@link deriveInteractiveKey} functions for more detail about them. + * + * See: [Note: Key encryption key]. + */ opsLimit: number; + /** + * The memory limit used during the derivation of the kek. + * + * See {@link opsLimit} for more details. + */ memLimit: number; publicKey: string; encryptedSecretKey: string; secretKeyDecryptionNonce: string; - /** Doesn't change after being initially created. */ + /** + * The user's master key after being encrypted with their recovery key. + * + * This allows the user to recover their master key if they forget their + * passphrase but still have their recovery key. + * + * Note: This value doesn't change after being initially created. + */ masterKeyEncryptedWithRecoveryKey?: string; + /** + * The nonce used during the encryption of + * {@link masterKeyEncryptedWithRecoveryKey}. + */ masterKeyDecryptionNonce?: string; - /** Doesn't change after being initially created. */ + /** + * The user's recovery key after being encrypted with their master key. + * + * Note: This value doesn't change after being initially created. + */ recoveryKeyEncryptedWithMasterKey?: string; + /** + * The nonce used during the encryption of + * {@link recoveryKeyEncryptedWithMasterKey}. + */ recoveryKeyDecryptionNonce?: string; } From 8441aafe819db98da60667af95c17b3ab7b78dfb Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 18:26:53 +0530 Subject: [PATCH 06/10] Inline --- web/packages/accounts/pages/change-password.tsx | 4 ++-- web/packages/shared/user/types.ts | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/web/packages/accounts/pages/change-password.tsx b/web/packages/accounts/pages/change-password.tsx index c39c0daa2f..4be2e58531 100644 --- a/web/packages/accounts/pages/change-password.tsx +++ b/web/packages/accounts/pages/change-password.tsx @@ -28,7 +28,7 @@ import { } from "ente-shared/crypto/helpers"; 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 type { KeyAttributes, User } from "ente-shared/user/types"; import { t } from "i18next"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; @@ -58,7 +58,7 @@ const Page: React.FC = () => { const key = await getActualKey(); const keyAttributes: KeyAttributes = getData("keyAttributes"); const kekSalt = await cryptoWorker.generateSaltToDeriveKey(); - let kek: KEK; + let kek: { key: string; opsLimit: number; memLimit: number }; try { kek = await cryptoWorker.deriveSensitiveKey(passphrase, kekSalt); } catch { diff --git a/web/packages/shared/user/types.ts b/web/packages/shared/user/types.ts index cf0d124665..ff684f00ec 100644 --- a/web/packages/shared/user/types.ts +++ b/web/packages/shared/user/types.ts @@ -90,8 +90,3 @@ export interface User { twoFactorSessionID: string; } -export interface KEK { - key: string; - opsLimit: number; - memLimit: number; -} From 3dbc336687825080bad67d5e497904bbd5171745 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 18:36:49 +0530 Subject: [PATCH 07/10] Doc --- web/packages/shared/user/types.ts | 41 +++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/web/packages/shared/user/types.ts b/web/packages/shared/user/types.ts index ff684f00ec..c0b665a935 100644 --- a/web/packages/shared/user/types.ts +++ b/web/packages/shared/user/types.ts @@ -1,10 +1,21 @@ /** - * A structure containing the key related attributes for a user. + * The user's various encrypted keys and their related attributes. + * + * - Attributes to derive the KEK, the (master) key encryption key. + * - Encrypted master key (with KEK) + * - Encrypted master key (with recovery key) + * - Encrypted recovery key (with master key). + * - Public key and encrypted private key (with master key). + * + * The various "key" attributes are base64 encoded representations of the + * underlying binary data. */ export interface KeyAttributes { /** * The user's master key encrypted with the key encryption key. * + * Base 64 encoded. + * * [Note: Key encryption key] * * The user's master key is encrypted with a "key encryption key" (lovingly @@ -25,12 +36,16 @@ export interface KeyAttributes { /** * The nonce used during the encryption of the master key. * + * Base 64 encoded. + * * @see {@link encryptedKey}. */ keyDecryptionNonce: string; /** * The salt used during the derivation of the kek. * + * Base 64 encoded. + * * See: [Note: Key encryption key]. */ kekSalt: string; @@ -51,12 +66,29 @@ export interface KeyAttributes { * See {@link opsLimit} for more details. */ memLimit: number; + /** + * The user's public key (part of their public-key keypair, the other half + * being the {@link encryptedSecretKey}). + * + * Base 64 encoded. + */ publicKey: string; + /** + * The user's private key (part of their public-key keypair, the other half + * being the {@link publicKey}) encrypted with their master key. + * + * Base 64 encoded. + */ encryptedSecretKey: string; + /** + * The nonce used during the encryption of {@link encryptedSecretKey}. + */ secretKeyDecryptionNonce: string; /** * The user's master key after being encrypted with their recovery key. * + * Base 64 encoded. + * * This allows the user to recover their master key if they forget their * passphrase but still have their recovery key. * @@ -66,17 +98,23 @@ export interface KeyAttributes { /** * The nonce used during the encryption of * {@link masterKeyEncryptedWithRecoveryKey}. + * + * Base 64 encoded. */ masterKeyDecryptionNonce?: string; /** * The user's recovery key after being encrypted with their master key. * + * Base 64 encoded. + * * Note: This value doesn't change after being initially created. */ recoveryKeyEncryptedWithMasterKey?: string; /** * The nonce used during the encryption of * {@link recoveryKeyEncryptedWithMasterKey}. + * + * Base 64 encoded. */ recoveryKeyDecryptionNonce?: string; } @@ -89,4 +127,3 @@ export interface User { isTwoFactorEnabled: boolean; twoFactorSessionID: string; } - From e6707d9fcbdb5d925319f733b263724286006022 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 18:40:25 +0530 Subject: [PATCH 08/10] Move --- web/apps/auth/src/pages/_app.tsx | 2 +- .../src/components/AuthenticateUser.tsx | 2 +- web/apps/photos/src/pages/_app.tsx | 2 +- .../photos/src/services/collectionService.ts | 2 +- web/apps/photos/src/types/gallery/index.ts | 2 +- web/apps/photos/src/utils/collection.ts | 2 +- web/apps/photos/src/utils/file/index.ts | 2 +- .../components/VerifyMasterPasswordForm.tsx | 2 +- .../accounts/pages/change-password.tsx | 7 +- web/packages/accounts/pages/credentials.tsx | 2 +- web/packages/accounts/pages/generate.tsx | 2 +- web/packages/accounts/pages/recover.tsx | 2 +- .../accounts/pages/two-factor/verify.tsx | 2 +- web/packages/accounts/pages/verify.tsx | 2 +- .../accounts/services/recovery-key.ts | 2 +- web/packages/accounts/services/session.ts | 2 +- web/packages/accounts/services/srp.ts | 2 +- web/packages/accounts/services/user.ts | 179 +++++++++++++++--- .../new/photos/components/gallery/helpers.ts | 2 +- .../new/photos/components/gallery/reducer.ts | 2 +- .../new/photos/services/collection.ts | 2 +- .../new/photos/services/export-migration.ts | 2 +- web/packages/shared/crypto/helpers.ts | 2 +- web/packages/shared/user/types.ts | 129 ------------- 24 files changed, 180 insertions(+), 177 deletions(-) delete mode 100644 web/packages/shared/user/types.ts diff --git a/web/apps/auth/src/pages/_app.tsx b/web/apps/auth/src/pages/_app.tsx index c65139559e..9aada5ae8a 100644 --- a/web/apps/auth/src/pages/_app.tsx +++ b/web/apps/auth/src/pages/_app.tsx @@ -2,6 +2,7 @@ import "@fontsource-variable/inter"; import { CssBaseline } from "@mui/material"; import { ThemeProvider } from "@mui/material/styles"; import { accountLogout } from "ente-accounts/services/logout"; +import type { User } from "ente-accounts/services/user"; import { clientPackageName, staticAppTitle } from "ente-base/app"; import { CustomHead } from "ente-base/components/Head"; import { @@ -20,7 +21,6 @@ import { BaseContext, deriveBaseContext } from "ente-base/context"; import { logStartupBanner } from "ente-base/log-web"; import HTTPService from "ente-shared/network/HTTPService"; import { getData } from "ente-shared/storage/localStorage"; -import type { User } from "ente-shared/user/types"; import { t } from "i18next"; import type { AppProps } from "next/app"; import React, { useCallback, useEffect, useMemo } from "react"; diff --git a/web/apps/photos/src/components/AuthenticateUser.tsx b/web/apps/photos/src/components/AuthenticateUser.tsx index 6ecc64af71..83f45f42b7 100644 --- a/web/apps/photos/src/components/AuthenticateUser.tsx +++ b/web/apps/photos/src/components/AuthenticateUser.tsx @@ -1,5 +1,6 @@ import { VerifyMasterPasswordForm } from "ente-accounts/components/VerifyMasterPasswordForm"; import { checkSessionValidity } from "ente-accounts/services/session"; +import type { KeyAttributes, User } from "ente-accounts/services/user"; import { TitledMiniDialog, type MiniDialogAttributes, @@ -8,7 +9,6 @@ import type { ModalVisibilityProps } from "ente-base/components/utils/modal"; import { useBaseContext } from "ente-base/context"; import log from "ente-base/log"; 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"; diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index cdd5849886..5824cb1890 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -3,6 +3,7 @@ import ArrowForwardIcon from "@mui/icons-material/ArrowForward"; import { CssBaseline, Typography } from "@mui/material"; import { styled, ThemeProvider } from "@mui/material/styles"; import { useNotification } from "components/utils/hooks-app"; +import type { User } from "ente-accounts/services/user"; import { clientPackageName, isDesktop, staticAppTitle } from "ente-base/app"; import { CenteredRow } from "ente-base/components/containers"; import { CustomHead } from "ente-base/components/Head"; @@ -43,7 +44,6 @@ import { getData, isLocalStorageAndIndexedDBMismatch, } from "ente-shared/storage/localStorage"; -import type { User } from "ente-shared/user/types"; import { t } from "i18next"; import type { AppProps } from "next/app"; import { useRouter } from "next/router"; diff --git a/web/apps/photos/src/services/collectionService.ts b/web/apps/photos/src/services/collectionService.ts index 94e60e4613..4633340226 100644 --- a/web/apps/photos/src/services/collectionService.ts +++ b/web/apps/photos/src/services/collectionService.ts @@ -1,3 +1,4 @@ +import type { User } from "ente-accounts/services/user"; import { encryptMetadataJSON, sharedCryptoWorker } from "ente-base/crypto"; import { ensureLocalUser } from "ente-base/local-user"; import log from "ente-base/log"; @@ -43,7 +44,6 @@ import HTTPService from "ente-shared/network/HTTPService"; 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"; import { batch } from "ente-utils/array"; import { changeCollectionSubType, diff --git a/web/apps/photos/src/types/gallery/index.ts b/web/apps/photos/src/types/gallery/index.ts index 67371e047d..bb23e2f2d3 100644 --- a/web/apps/photos/src/types/gallery/index.ts +++ b/web/apps/photos/src/types/gallery/index.ts @@ -1,7 +1,7 @@ import { TimeStampListItem } from "components/FileList"; import { FilesDownloadProgressAttributes } from "components/FilesDownloadProgress"; +import type { User } from "ente-accounts/services/user"; import { type SelectionContext } from "ente-new/photos/components/gallery"; -import type { User } from "ente-shared/user/types"; export interface SelectedState { [k: number]: boolean; diff --git a/web/apps/photos/src/utils/collection.ts b/web/apps/photos/src/utils/collection.ts index 7ce407387d..dbacc979e2 100644 --- a/web/apps/photos/src/utils/collection.ts +++ b/web/apps/photos/src/utils/collection.ts @@ -1,3 +1,4 @@ +import type { User } from "ente-accounts/services/user"; import { ensureElectron } from "ente-base/electron"; import { joinPath } from "ente-base/file-name"; import log from "ente-base/log"; @@ -30,7 +31,6 @@ import { } from "ente-new/photos/services/files"; import { safeDirectoryName } from "ente-new/photos/utils/native-fs"; import { getData } from "ente-shared/storage/localStorage"; -import type { User } from "ente-shared/user/types"; import { createAlbum, removeFromCollection, diff --git a/web/apps/photos/src/utils/file/index.ts b/web/apps/photos/src/utils/file/index.ts index 9b5d90257f..a3afa279a3 100644 --- a/web/apps/photos/src/utils/file/index.ts +++ b/web/apps/photos/src/utils/file/index.ts @@ -1,3 +1,4 @@ +import type { User } from "ente-accounts/services/user"; import { joinPath } from "ente-base/file-name"; import log from "ente-base/log"; import { type Electron } from "ente-base/types/ipc"; @@ -21,7 +22,6 @@ import { } from "ente-new/photos/services/collection"; import { safeFileName } from "ente-new/photos/utils/native-fs"; import { getData } from "ente-shared/storage/localStorage"; -import type { User } from "ente-shared/user/types"; import { wait } from "ente-utils/promise"; import { t } from "i18next"; import { diff --git a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx index cbd474aa01..095034e3b5 100644 --- a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx +++ b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx @@ -1,11 +1,11 @@ import { Input, TextField } from "@mui/material"; import type { SRPAttributes } from "ente-accounts/services/srp-remote"; +import type { KeyAttributes, User } from "ente-accounts/services/user"; import { LoadingButton } from "ente-base/components/mui/LoadingButton"; import { ShowHidePasswordInputAdornment } from "ente-base/components/mui/PasswordInputAdornment"; import { sharedCryptoWorker } from "ente-base/crypto"; import log from "ente-base/log"; import { CustomError } from "ente-shared/error"; -import type { KeyAttributes, User } from "ente-shared/user/types"; import { useFormik } from "formik"; import { t } from "i18next"; import { useCallback, useState } from "react"; diff --git a/web/packages/accounts/pages/change-password.tsx b/web/packages/accounts/pages/change-password.tsx index 4be2e58531..f977ba8bdc 100644 --- a/web/packages/accounts/pages/change-password.tsx +++ b/web/packages/accounts/pages/change-password.tsx @@ -18,7 +18,11 @@ import { startSRPSetup, updateSRPAndKeys, } from "ente-accounts/services/srp-remote"; -import type { UpdatedKey } from "ente-accounts/services/user"; +import type { + KeyAttributes, + UpdatedKey, + User, +} from "ente-accounts/services/user"; import { LinkButton } from "ente-base/components/LinkButton"; import { sharedCryptoWorker } from "ente-base/crypto"; import { @@ -28,7 +32,6 @@ import { } from "ente-shared/crypto/helpers"; import { getData, setData } from "ente-shared/storage/localStorage"; import { getActualKey } from "ente-shared/user"; -import type { KeyAttributes, User } from "ente-shared/user/types"; import { t } from "i18next"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; diff --git a/web/packages/accounts/pages/credentials.tsx b/web/packages/accounts/pages/credentials.tsx index 77f4c1feec..8f95ff9559 100644 --- a/web/packages/accounts/pages/credentials.tsx +++ b/web/packages/accounts/pages/credentials.tsx @@ -28,6 +28,7 @@ import { } from "ente-accounts/services/srp"; import type { SRPAttributes } from "ente-accounts/services/srp-remote"; import { getSRPAttributes } from "ente-accounts/services/srp-remote"; +import type { KeyAttributes, User } from "ente-accounts/services/user"; import { LinkButton } from "ente-base/components/LinkButton"; import { LoadingIndicator } from "ente-base/components/loaders"; import { useBaseContext } from "ente-base/context"; @@ -49,7 +50,6 @@ import { setIsFirstLogin, } from "ente-shared/storage/localStorage/helpers"; import { getKey, removeKey, setKey } from "ente-shared/storage/sessionStorage"; -import type { KeyAttributes, User } from "ente-shared/user/types"; import { t } from "i18next"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; diff --git a/web/packages/accounts/pages/generate.tsx b/web/packages/accounts/pages/generate.tsx index 0f72c562c0..ff3411b449 100644 --- a/web/packages/accounts/pages/generate.tsx +++ b/web/packages/accounts/pages/generate.tsx @@ -12,6 +12,7 @@ import { configureSRP, generateKeyAndSRPAttributes, } from "ente-accounts/services/srp"; +import type { KeyAttributes, User } from "ente-accounts/services/user"; import { putUserKeyAttributes } from "ente-accounts/services/user"; import { LinkButton } from "ente-base/components/LinkButton"; import { LoadingIndicator } from "ente-base/components/loaders"; @@ -27,7 +28,6 @@ import { setJustSignedUp, } from "ente-shared/storage/localStorage/helpers"; import { getKey } from "ente-shared/storage/sessionStorage"; -import type { KeyAttributes, User } from "ente-shared/user/types"; import { t } from "i18next"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; diff --git a/web/packages/accounts/pages/recover.tsx b/web/packages/accounts/pages/recover.tsx index d5f0f55577..76db2cfcf5 100644 --- a/web/packages/accounts/pages/recover.tsx +++ b/web/packages/accounts/pages/recover.tsx @@ -5,6 +5,7 @@ import { } from "ente-accounts/components/layouts/centered-paper"; import { recoveryKeyB64FromMnemonic } from "ente-accounts/services/recovery-key"; import { appHomeRoute, stashRedirect } from "ente-accounts/services/redirect"; +import type { KeyAttributes, User } from "ente-accounts/services/user"; import { sendOTT } from "ente-accounts/services/user"; import { LinkButton } from "ente-base/components/LinkButton"; import { @@ -20,7 +21,6 @@ import { } from "ente-shared/crypto/helpers"; 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"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; diff --git a/web/packages/accounts/pages/two-factor/verify.tsx b/web/packages/accounts/pages/two-factor/verify.tsx index 287f987c57..dd3a0ab90b 100644 --- a/web/packages/accounts/pages/two-factor/verify.tsx +++ b/web/packages/accounts/pages/two-factor/verify.tsx @@ -1,10 +1,10 @@ import { Verify2FACodeForm } from "ente-accounts/components/Verify2FACodeForm"; +import type { User } from "ente-accounts/services/user"; import { verifyTwoFactor } from "ente-accounts/services/user"; import { LinkButton } from "ente-base/components/LinkButton"; import { useBaseContext } from "ente-base/context"; import { HTTPError } from "ente-base/http"; 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"; import { useEffect, useState } from "react"; diff --git a/web/packages/accounts/pages/verify.tsx b/web/packages/accounts/pages/verify.tsx index 82e7db2f6e..521ddbd95f 100644 --- a/web/packages/accounts/pages/verify.tsx +++ b/web/packages/accounts/pages/verify.tsx @@ -22,6 +22,7 @@ import type { SRPSetupAttributes, } from "ente-accounts/services/srp-remote"; import { getSRPAttributes } from "ente-accounts/services/srp-remote"; +import type { KeyAttributes, User } from "ente-accounts/services/user"; import { putUserKeyAttributes, sendOTT, @@ -44,7 +45,6 @@ import { getLocalReferralSource, setIsFirstLogin, } from "ente-shared/storage/localStorage/helpers"; -import type { KeyAttributes, User } from "ente-shared/user/types"; import { t } from "i18next"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; diff --git a/web/packages/accounts/services/recovery-key.ts b/web/packages/accounts/services/recovery-key.ts index dcb1011337..8db572d782 100644 --- a/web/packages/accounts/services/recovery-key.ts +++ b/web/packages/accounts/services/recovery-key.ts @@ -1,4 +1,5 @@ import * as bip39 from "bip39"; +import type { KeyAttributes } from "ente-accounts/services/user"; import { decryptBoxB64, fromHex, @@ -7,7 +8,6 @@ import { } from "ente-base/crypto"; import { masterKeyFromSession } from "ente-base/session"; import { getData, setData } from "ente-shared/storage/localStorage"; -import type { KeyAttributes } from "ente-shared/user/types"; import { putUserRecoveryKeyAttributes } from "./user"; // Mobile client library only supports English. diff --git a/web/packages/accounts/services/session.ts b/web/packages/accounts/services/session.ts index 65a8a7e44d..ac6263395d 100644 --- a/web/packages/accounts/services/session.ts +++ b/web/packages/accounts/services/session.ts @@ -1,9 +1,9 @@ +import type { KeyAttributes } from "ente-accounts/services/user"; import { authenticatedRequestHeaders, HTTPError } from "ente-base/http"; import { ensureLocalUser, getAuthToken } from "ente-base/local-user"; import log from "ente-base/log"; import { apiURL } from "ente-base/origins"; import { getData } from "ente-shared/storage/localStorage"; -import type { KeyAttributes } from "ente-shared/user/types"; import { nullToUndefined } from "ente-utils/transform"; import { z } from "zod/v4"; import type { SRPAttributes } from "./srp-remote"; diff --git a/web/packages/accounts/services/srp.ts b/web/packages/accounts/services/srp.ts index 30face4208..1fe485a96a 100644 --- a/web/packages/accounts/services/srp.ts +++ b/web/packages/accounts/services/srp.ts @@ -1,8 +1,8 @@ +import type { KeyAttributes } from "ente-accounts/services/user"; import { sharedCryptoWorker } from "ente-base/crypto"; import log from "ente-base/log"; import { generateLoginSubKey } from "ente-shared/crypto/helpers"; import { getToken } from "ente-shared/storage/localStorage/helpers"; -import type { KeyAttributes } from "ente-shared/user/types"; import { SRP, SrpClient } from "fast-srp-hap"; import { v4 as uuidv4 } from "uuid"; import { diff --git a/web/packages/accounts/services/user.ts b/web/packages/accounts/services/user.ts index 0577996a81..3495979bbc 100644 --- a/web/packages/accounts/services/user.ts +++ b/web/packages/accounts/services/user.ts @@ -6,10 +6,163 @@ import { import { apiURL } from "ente-base/origins"; import HTTPService from "ente-shared/network/HTTPService"; import { getToken } from "ente-shared/storage/localStorage/helpers"; -import type { KeyAttributes } from "ente-shared/user/types"; import { nullToUndefined } from "ente-utils/transform"; import { z } from "zod/v4"; +export interface User { + id: number; + email: string; + token: string; + encryptedToken: string; + isTwoFactorEnabled: boolean; + twoFactorSessionID: string; +} + +/** + * The user's various encrypted keys and their related attributes. + * + * - Attributes to derive the KEK, the (master) key encryption key. + * - Encrypted master key (with KEK) + * - Encrypted master key (with recovery key) + * - Encrypted recovery key (with master key). + * - Public key and encrypted private key (with master key). + * + * The various "key" attributes are base64 encoded representations of the + * underlying binary data. + */ +export interface KeyAttributes { + /** + * The user's master key encrypted with the key encryption key. + * + * Base 64 encoded. + * + * [Note: Key encryption key] + * + * The user's master key is encrypted with a "key encryption key" (lovingly + * called a "kek" sometimes). + * + * The kek itself is derived from the user's passphrase. + * + * 1. User enters passphrase on new device. + * + * 2. Client derives kek from this passphrase (using the {@link kekSalt}, + * {@link opsLimit} and {@link memLimit} as parameters for the + * derivation). + * + * 3. Client use kek to decrypt the master key from {@link encryptedKey} and + * {@link keyDecryptionNonce}. + */ + encryptedKey: string; + /** + * The nonce used during the encryption of the master key. + * + * Base 64 encoded. + * + * @see {@link encryptedKey}. + */ + keyDecryptionNonce: string; + /** + * The salt used during the derivation of the kek. + * + * Base 64 encoded. + * + * See: [Note: Key encryption key]. + */ + kekSalt: string; + /** + * The operation limit used during the derivation of the kek. + * + * The {@link opsLimit} and {@link memLimit} are complementary parameters + * that define the amount of work done by the key derivation function. See + * the {@link deriveKey}, {@link deriveSensitiveKey} and + * {@link deriveInteractiveKey} functions for more detail about them. + * + * See: [Note: Key encryption key]. + */ + opsLimit: number; + /** + * The memory limit used during the derivation of the kek. + * + * See {@link opsLimit} for more details. + */ + memLimit: number; + /** + * The user's public key (part of their public-key keypair, the other half + * being the {@link encryptedSecretKey}). + * + * Base 64 encoded. + */ + publicKey: string; + /** + * The user's private key (part of their public-key keypair, the other half + * being the {@link publicKey}) encrypted with their master key. + * + * Base 64 encoded. + */ + encryptedSecretKey: string; + /** + * The nonce used during the encryption of {@link encryptedSecretKey}. + */ + secretKeyDecryptionNonce: string; + /** + * The user's master key after being encrypted with their recovery key. + * + * Base 64 encoded. + * + * This allows the user to recover their master key if they forget their + * passphrase but still have their recovery key. + * + * Note: This value doesn't change after being initially created. + */ + masterKeyEncryptedWithRecoveryKey?: string; + /** + * The nonce used during the encryption of + * {@link masterKeyEncryptedWithRecoveryKey}. + * + * Base 64 encoded. + */ + masterKeyDecryptionNonce?: string; + /** + * The user's recovery key after being encrypted with their master key. + * + * Base 64 encoded. + * + * Note: This value doesn't change after being initially created. + */ + recoveryKeyEncryptedWithMasterKey?: string; + /** + * The nonce used during the encryption of + * {@link recoveryKeyEncryptedWithMasterKey}. + * + * Base 64 encoded. + */ + recoveryKeyDecryptionNonce?: string; +} + +/** + * Zod schema for {@link KeyAttributes}. + */ +export const RemoteKeyAttributes = z.object({ + kekSalt: z.string(), + encryptedKey: z.string(), + keyDecryptionNonce: z.string(), + publicKey: z.string(), + encryptedSecretKey: z.string(), + secretKeyDecryptionNonce: z.string(), + memLimit: z.number(), + opsLimit: z.number(), + masterKeyEncryptedWithRecoveryKey: z + .string() + .nullish() + .transform(nullToUndefined), + masterKeyDecryptionNonce: z.string().nullish().transform(nullToUndefined), + recoveryKeyEncryptedWithMasterKey: z + .string() + .nullish() + .transform(nullToUndefined), + recoveryKeyDecryptionNonce: z.string().nullish().transform(nullToUndefined), +}); + export interface UserVerificationResponse { id: number; keyAttributes?: KeyAttributes | undefined; @@ -117,30 +270,6 @@ export const verifyEmail = async ( return EmailOrSRPAuthorizationResponse.parse(await res.json()); }; -/** - * Zod schema for {@link KeyAttributes}. - */ -export const RemoteKeyAttributes = z.object({ - kekSalt: z.string(), - encryptedKey: z.string(), - keyDecryptionNonce: z.string(), - publicKey: z.string(), - encryptedSecretKey: z.string(), - secretKeyDecryptionNonce: z.string(), - memLimit: z.number(), - opsLimit: z.number(), - masterKeyEncryptedWithRecoveryKey: z - .string() - .nullish() - .transform(nullToUndefined), - masterKeyDecryptionNonce: z.string().nullish().transform(nullToUndefined), - recoveryKeyEncryptedWithMasterKey: z - .string() - .nullish() - .transform(nullToUndefined), - recoveryKeyDecryptionNonce: z.string().nullish().transform(nullToUndefined), -}); - /** * Zod schema for response from remote on a successful user verification, either * via {@link verifyEmail} or {@link verifySRPSession}. diff --git a/web/packages/new/photos/components/gallery/helpers.ts b/web/packages/new/photos/components/gallery/helpers.ts index 81596bf6ef..226badae81 100644 --- a/web/packages/new/photos/components/gallery/helpers.ts +++ b/web/packages/new/photos/components/gallery/helpers.ts @@ -11,10 +11,10 @@ */ import { getUserRecoveryKeyB64 } from "ente-accounts/services/recovery-key"; +import type { User } from "ente-accounts/services/user"; import log from "ente-base/log"; import type { Collection } from "ente-media/collection"; import type { FamilyData } from "ente-new/photos/services/user-details"; -import type { User } from "ente-shared/user/types"; /** * Ensure that the keys in local storage are not malformed by verifying that the diff --git a/web/packages/new/photos/components/gallery/reducer.ts b/web/packages/new/photos/components/gallery/reducer.ts index c3464c7bf7..80a12f7482 100644 --- a/web/packages/new/photos/components/gallery/reducer.ts +++ b/web/packages/new/photos/components/gallery/reducer.ts @@ -1,3 +1,4 @@ +import type { User } from "ente-accounts/services/user"; import { isArchivedCollection, isPinnedCollection, @@ -10,7 +11,6 @@ import { createCollectionNameByID, isHiddenCollection, } from "ente-new/photos/services/collection"; -import type { User } from "ente-shared/user/types"; import { splitByPredicate } from "ente-utils/array"; import { t } from "i18next"; import React, { useReducer } from "react"; diff --git a/web/packages/new/photos/services/collection.ts b/web/packages/new/photos/services/collection.ts index 25aca079b0..b4d4fbeb1f 100644 --- a/web/packages/new/photos/services/collection.ts +++ b/web/packages/new/photos/services/collection.ts @@ -1,10 +1,10 @@ +import type { User } from "ente-accounts/services/user"; import { encryptBoxB64 } from "ente-base/crypto"; import { authenticatedRequestHeaders, ensureOk } from "ente-base/http"; import { apiURL } from "ente-base/origins"; import { CollectionSubType, type Collection } from "ente-media/collection"; import { type EnteFile } from "ente-media/file"; import { ItemVisibility } from "ente-media/file-metadata"; -import type { User } from "ente-shared/user/types"; import { batch } from "ente-utils/array"; /** diff --git a/web/packages/new/photos/services/export-migration.ts b/web/packages/new/photos/services/export-migration.ts index 2dc6823a64..99fb6630c0 100644 --- a/web/packages/new/photos/services/export-migration.ts +++ b/web/packages/new/photos/services/export-migration.ts @@ -3,6 +3,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ +import type { User } from "ente-accounts/services/user"; import { ensureElectron } from "ente-base/electron"; import { joinPath, nameAndExtension } from "ente-base/file-name"; import log from "ente-base/log"; @@ -20,7 +21,6 @@ import { sanitizeFilename, } from "ente-new/photos/utils/native-fs"; import { getData } from "ente-shared/storage/localStorage"; -import type { User } from "ente-shared/user/types"; import { wait } from "ente-utils/promise"; import exportService, { getCollectionIDFromFileUID, diff --git a/web/packages/shared/crypto/helpers.ts b/web/packages/shared/crypto/helpers.ts index 7cb9a5a1c8..15b4a631bd 100644 --- a/web/packages/shared/crypto/helpers.ts +++ b/web/packages/shared/crypto/helpers.ts @@ -1,8 +1,8 @@ +import type { KeyAttributes } from "ente-accounts/services/user"; import { sharedCryptoWorker } from "ente-base/crypto"; import { masterKeyFromSession } from "ente-base/session"; import { getData, setData, setLSUser } from "ente-shared/storage/localStorage"; import { type SessionKey, setKey } from "ente-shared/storage/sessionStorage"; -import type { KeyAttributes } from "ente-shared/user/types"; const LOGIN_SUB_KEY_LENGTH = 32; const LOGIN_SUB_KEY_ID = 1; diff --git a/web/packages/shared/user/types.ts b/web/packages/shared/user/types.ts deleted file mode 100644 index c0b665a935..0000000000 --- a/web/packages/shared/user/types.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * The user's various encrypted keys and their related attributes. - * - * - Attributes to derive the KEK, the (master) key encryption key. - * - Encrypted master key (with KEK) - * - Encrypted master key (with recovery key) - * - Encrypted recovery key (with master key). - * - Public key and encrypted private key (with master key). - * - * The various "key" attributes are base64 encoded representations of the - * underlying binary data. - */ -export interface KeyAttributes { - /** - * The user's master key encrypted with the key encryption key. - * - * Base 64 encoded. - * - * [Note: Key encryption key] - * - * The user's master key is encrypted with a "key encryption key" (lovingly - * called a "kek" sometimes). - * - * The kek itself is derived from the user's passphrase. - * - * 1. User enters passphrase on new device. - * - * 2. Client derives kek from this passphrase (using the {@link kekSalt}, - * {@link opsLimit} and {@link memLimit} as parameters for the - * derivation). - * - * 3. Client use kek to decrypt the master key from {@link encryptedKey} and - * {@link keyDecryptionNonce}. - */ - encryptedKey: string; - /** - * The nonce used during the encryption of the master key. - * - * Base 64 encoded. - * - * @see {@link encryptedKey}. - */ - keyDecryptionNonce: string; - /** - * The salt used during the derivation of the kek. - * - * Base 64 encoded. - * - * See: [Note: Key encryption key]. - */ - kekSalt: string; - /** - * The operation limit used during the derivation of the kek. - * - * The {@link opsLimit} and {@link memLimit} are complementary parameters - * that define the amount of work done by the key derivation function. See - * the {@link deriveKey}, {@link deriveSensitiveKey} and - * {@link deriveInteractiveKey} functions for more detail about them. - * - * See: [Note: Key encryption key]. - */ - opsLimit: number; - /** - * The memory limit used during the derivation of the kek. - * - * See {@link opsLimit} for more details. - */ - memLimit: number; - /** - * The user's public key (part of their public-key keypair, the other half - * being the {@link encryptedSecretKey}). - * - * Base 64 encoded. - */ - publicKey: string; - /** - * The user's private key (part of their public-key keypair, the other half - * being the {@link publicKey}) encrypted with their master key. - * - * Base 64 encoded. - */ - encryptedSecretKey: string; - /** - * The nonce used during the encryption of {@link encryptedSecretKey}. - */ - secretKeyDecryptionNonce: string; - /** - * The user's master key after being encrypted with their recovery key. - * - * Base 64 encoded. - * - * This allows the user to recover their master key if they forget their - * passphrase but still have their recovery key. - * - * Note: This value doesn't change after being initially created. - */ - masterKeyEncryptedWithRecoveryKey?: string; - /** - * The nonce used during the encryption of - * {@link masterKeyEncryptedWithRecoveryKey}. - * - * Base 64 encoded. - */ - masterKeyDecryptionNonce?: string; - /** - * The user's recovery key after being encrypted with their master key. - * - * Base 64 encoded. - * - * Note: This value doesn't change after being initially created. - */ - recoveryKeyEncryptedWithMasterKey?: string; - /** - * The nonce used during the encryption of - * {@link recoveryKeyEncryptedWithMasterKey}. - * - * Base 64 encoded. - */ - recoveryKeyDecryptionNonce?: string; -} - -export interface User { - id: number; - email: string; - token: string; - encryptedToken: string; - isTwoFactorEnabled: boolean; - twoFactorSessionID: string; -} From 65a892379901acdc73b52a07532e6e41fba62fb6 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 18:48:12 +0530 Subject: [PATCH 09/10] Conv --- web/apps/cast/src/services/render.ts | 14 ++++++-------- web/packages/media/file.ts | 15 +++++++-------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/web/apps/cast/src/services/render.ts b/web/apps/cast/src/services/render.ts index 60fc7d5ea2..a99dfaa74d 100644 --- a/web/apps/cast/src/services/render.ts +++ b/web/apps/cast/src/services/render.ts @@ -195,16 +195,14 @@ const decryptEnteFile = async ( pubMagicMetadata, ...restFileProps } = encryptedFile; - const fileKey = await worker.decryptB64( - encryptedKey, - keyDecryptionNonce, + const fileKey = await worker.decryptBoxB64( + { encryptedData: encryptedKey, nonce: keyDecryptionNonce }, collectionKey, ); - const fileMetadata = await worker.decryptMetadataJSON({ - encryptedDataB64: metadata.encryptedData, - decryptionHeaderB64: metadata.decryptionHeader, - keyB64: fileKey, - }); + const fileMetadata = await worker.decryptMetadataJSON_New( + metadata, + fileKey, + ); let fileMagicMetadata: FileMagicMetadata | undefined; let filePubMagicMetadata: FilePublicMagicMetadata | undefined; if (magicMetadata?.data) { diff --git a/web/packages/media/file.ts b/web/packages/media/file.ts index b42f48a6b4..bc6c3bc483 100644 --- a/web/packages/media/file.ts +++ b/web/packages/media/file.ts @@ -321,16 +321,15 @@ export async function decryptFile( pubMagicMetadata, ...restFileProps } = file; - const fileKey = await worker.decryptB64( - encryptedKey, - keyDecryptionNonce, + const fileKey = await worker.decryptBoxB64( + { encryptedData: encryptedKey, nonce: keyDecryptionNonce }, collectionKey, ); - const fileMetadata = await worker.decryptMetadataJSON({ - encryptedDataB64: metadata.encryptedData, - decryptionHeaderB64: metadata.decryptionHeader, - keyB64: fileKey, - }); + const fileMetadata = await worker.decryptMetadataJSON_New( + metadata, + fileKey, + ); + let fileMagicMetadata: FileMagicMetadata; let filePubMagicMetadata: FilePublicMagicMetadata; /* eslint-disable @typescript-eslint/no-unnecessary-condition */ From 506b915f650766cc7bb92ceee29f3cc8b369194f Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 18:59:08 +0530 Subject: [PATCH 10/10] conv --- web/packages/accounts/pages/credentials.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/web/packages/accounts/pages/credentials.tsx b/web/packages/accounts/pages/credentials.tsx index 8f95ff9559..6ea11ba5c8 100644 --- a/web/packages/accounts/pages/credentials.tsx +++ b/web/packages/accounts/pages/credentials.tsx @@ -140,14 +140,18 @@ const Page: React.FC = () => { if (kekEncryptedAttributes && keyAttributes) { removeKey("keyEncryptionKey"); const cryptoWorker = await sharedCryptoWorker(); - const kek = await cryptoWorker.decryptB64( - kekEncryptedAttributes.encryptedData, - kekEncryptedAttributes.nonce, + const kek = await cryptoWorker.decryptBoxB64( + { + encryptedData: kekEncryptedAttributes.encryptedData, + nonce: kekEncryptedAttributes.nonce, + }, kekEncryptedAttributes.key, ); - const key = await cryptoWorker.decryptB64( - keyAttributes.encryptedKey, - keyAttributes.keyDecryptionNonce, + const key = await cryptoWorker.decryptBoxB64( + { + encryptedData: keyAttributes.encryptedKey, + nonce: keyAttributes.keyDecryptionNonce, + }, kek, ); void postVerification(key, kek, keyAttributes);