This commit is contained in:
Manav Rathi
2025-06-06 16:58:30 +05:30
parent a1e506eb85
commit 3a127bcd8b
3 changed files with 18 additions and 43 deletions

View File

@@ -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,

View File

@@ -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);
};

View File

@@ -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);