diff --git a/web/packages/accounts/pages/credentials.tsx b/web/packages/accounts/pages/credentials.tsx index 14c9eaec3b..1198a37d65 100644 --- a/web/packages/accounts/pages/credentials.tsx +++ b/web/packages/accounts/pages/credentials.tsx @@ -37,13 +37,14 @@ import { import { LinkButton } from "ente-base/components/LinkButton"; import { LoadingIndicator } from "ente-base/components/loaders"; import { useBaseContext } from "ente-base/context"; -import { sharedCryptoWorker } from "ente-base/crypto"; -import type { B64EncryptionResult } from "ente-base/crypto/libsodium"; +import { decryptBox } from "ente-base/crypto"; import { clearLocalStorage } from "ente-base/local-storage"; import log from "ente-base/log"; import { haveAuthenticatedSession, saveMasterKeyInSessionAndSafeStore, + stashKeyEncryptionKeyInSessionStore, + unstashKeyEncryptionKeyFromSession, updateSessionFromElectronSafeStorageIfNeeded, } from "ente-base/session"; import { CustomError } from "ente-shared/error"; @@ -53,7 +54,6 @@ import { isFirstLogin, setIsFirstLogin, } from "ente-shared/storage/localStorage/helpers"; -import { getKey, removeKey, setKey } from "ente-shared/storage/sessionStorage"; import { t } from "i18next"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; @@ -120,8 +120,7 @@ const Page: React.FC = () => { void router.push(appHomeRoute); return; } - const kekEncryptedAttributes: B64EncryptionResult = - getKey("keyEncryptionKey"); + const kek = await unstashKeyEncryptionKeyFromSession(); const keyAttributes: KeyAttributes = getData("keyAttributes"); const srpAttributes: SRPAttributes = getData("srpAttributes"); @@ -129,26 +128,18 @@ const Page: React.FC = () => { setSessionValidityCheck(validateSession()); } - if (kekEncryptedAttributes && keyAttributes) { - removeKey("keyEncryptionKey"); - const cryptoWorker = await sharedCryptoWorker(); - const kek = await cryptoWorker.decryptBox( - { - encryptedData: kekEncryptedAttributes.encryptedData, - nonce: kekEncryptedAttributes.nonce, - }, - kekEncryptedAttributes.key, - ); - const key = await cryptoWorker.decryptBox( + if (kek && keyAttributes) { + const masterKey = await decryptBox( { encryptedData: keyAttributes.encryptedKey, nonce: keyAttributes.keyDecryptionNonce, }, kek, ); - void postVerification(key, kek, keyAttributes); + void postVerification(masterKey, kek, keyAttributes); return; } + if (keyAttributes) { if ( (!user?.token && !user?.encryptedToken) || @@ -184,7 +175,6 @@ const Page: React.FC = () => { // before we let the user in. if (sessionValidityCheck) await sessionValidityCheck; - const cryptoWorker = await sharedCryptoWorker(); const { keyAttributes, encryptedToken, @@ -200,9 +190,7 @@ const Page: React.FC = () => { setIsFirstLogin(true); if (passkeySessionID) { - const sessionKeyAttributes = - await cryptoWorker.generateKeyAndEncryptToB64(kek); - setKey("keyEncryptionKey", sessionKeyAttributes); + await stashKeyEncryptionKeyInSessionStore(kek); const user = getData("user"); await setLSUser({ ...user, @@ -219,9 +207,7 @@ const Page: React.FC = () => { openPasskeyVerificationURL({ passkeySessionID, url }); throw Error(CustomError.TWO_FACTOR_ENABLED); } else if (twoFactorSessionID) { - const sessionKeyAttributes = - await cryptoWorker.generateKeyAndEncryptToB64(kek); - setKey("keyEncryptionKey", sessionKeyAttributes); + await stashKeyEncryptionKeyInSessionStore(kek); const user = getData("user"); await setLSUser({ ...user, diff --git a/web/packages/base/session.ts b/web/packages/base/session.ts index e0ebf7ad03..9cfecd1e20 100644 --- a/web/packages/base/session.ts +++ b/web/packages/base/session.ts @@ -1,6 +1,6 @@ import { getToken } from "ente-shared/storage/localStorage/helpers"; import { z } from "zod/v4"; -import { decryptBox, decryptBoxBytes, encryptBox, generateKey } from "./crypto"; +import { decryptBox, encryptBox, generateKey } from "./crypto"; import { isDevBuild } from "./env"; import log from "./log"; import { getAuthToken } from "./token"; @@ -63,7 +63,6 @@ export const haveCredentialsInSession = () => * See also {@link ensureMasterKeyFromSession}, which is usually what we need. */ export const masterKeyFromSession = async () => { - // TODO: Same value as the deprecated getKey("encryptionKey") const value = sessionStorage.getItem("encryptionKey"); if (!value) return undefined; @@ -139,8 +138,6 @@ export const updateSessionFromElectronSafeStorageIfNeeded = async () => { log.error("Failed to read master key from safe storage", e); } if (masterKey) { - // Do not use `saveMasterKeyInSessionStore`, that will (unnecessarily) - // overwrite the OS safe storage again. await saveKeyInSessionStore("encryptionKey", masterKey); } }; @@ -178,6 +175,10 @@ export const stashKeyEncryptionKeyInSessionStore = (kek: string) => * Return the decrypted user's key encryption key ("kek") from session storage * if present, otherwise return `undefined`. * + * The key (if it was present) is also removed from session storage. + * + * @returns the previously stashed key (if any) as a base64 string. + * * [Note: Stashing KEK in session store] * * During login, if the user has set a second factor (passkey or TOTP), then we @@ -187,11 +188,10 @@ export const stashKeyEncryptionKeyInSessionStore = (kek: string) => * second factor redirect can happen to a separate accounts app altogether. * * So instead, we stash the encrypted kek in session store (using - * {@link stashKeyEncryptionKeyInSessionStore}), and after redirect, retrieve - * it (after clearing it) using {@link unstashKeyEncryptionKeyFromSession}. + * {@link stashKeyEncryptionKeyInSessionStore}), and after redirect, retrieve it + * (after clearing it) using {@link unstashKeyEncryptionKeyFromSession}. */ export const unstashKeyEncryptionKeyFromSession = async () => { - // TODO: Same value as the deprecated getKey("keyEncryptionKey") const value = sessionStorage.getItem("keyEncryptionKey"); if (!value) return undefined; @@ -200,5 +200,5 @@ export const unstashKeyEncryptionKeyFromSession = async () => { const { encryptedData, key, nonce } = SessionKeyData.parse( JSON.parse(value), ); - return decryptBoxBytes({ encryptedData, nonce }, key); + return decryptBox({ encryptedData, nonce }, key); }; diff --git a/web/packages/shared/storage/sessionStorage/index.ts b/web/packages/shared/storage/sessionStorage/index.ts deleted file mode 100644 index bc340bbbe6..0000000000 --- a/web/packages/shared/storage/sessionStorage/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type SessionKey = "encryptionKey" | "keyEncryptionKey"; - -export const setKey = (key: SessionKey, value: object) => - sessionStorage.setItem(key, JSON.stringify(value)); - -export const getKey = (key: SessionKey) => { - const value = sessionStorage.getItem(key); - return value && JSON.parse(value); -}; - -export const removeKey = (key: SessionKey) => sessionStorage.removeItem(key);