Scaffold more infra

This commit is contained in:
Manav Rathi
2025-06-06 15:37:33 +05:30
parent 63830b798b
commit 37c0fa1cd6
2 changed files with 76 additions and 4 deletions

View File

@@ -39,10 +39,15 @@ export async function decryptAndStoreToken(
}
}
// We encrypt the masterKey, with an intermediate key derived from the
// passphrase (with Interactive mem and ops limits) to avoid saving it to local
// storage in plain text. This means that on the web user will always have to
// enter their passphrase to access their masterKey.
/**
* Encrypt the user's masterKey with an intermediate kek (key encryption key)
* derived from the passphrase (with interactive mem and ops limits) to avoid
* saving it to local storage in plain text.
*
* This means that on the web user will always have to enter their passphrase to
* access their masterKey when repopening the app in a new tab (on desktop we
* can use OS storage, see [Note: Safe storage and interactive KEK attributes]).
*/
export async function generateAndSaveIntermediateKeyAttributes(
passphrase: string,
existingKeyAttributes: KeyAttributes,

View File

@@ -1,5 +1,9 @@
import { getToken } from "ente-shared/storage/localStorage/helpers";
import { z } from "zod/v4";
import { decryptBox, decryptBoxBytes, encryptBox, generateKey } from "./crypto";
import { isDevBuild } from "./env";
import log from "./log";
import { getAuthToken } from "./token";
/**
* Remove all data stored in session storage (data tied to the browser tab).
@@ -100,6 +104,69 @@ const saveKeyInSessionStore = async (keyName: string, keyData: string) => {
);
};
/**
* If we're running in the context of the desktop app, then read the master key
* from the OS safe storage and put it into the session storage (if it is not
* already present there).
*
* [Note: Safe storage and interactive KEK attributes]
*
* In the electron app we have the option of using the OS's safe storage (if
* available) to store the master key so that the user does not have to reenter
* their password each time they open the app.
*
* Such an ability is not present on browsers currently, so we need to ask the
* user for their password to derive the KEK for decrypting their master key
* each time they open the app in a new time (See: [Note: Key encryption key]).
*
* However, the default KEK parameters are not suitable for such frequent
* interactive usage. So for the user's convenience, we also derive an new (so
* called "intermediate") KEK using parameters suitable for interactive usage.
* This KEK is not saved to remote, it is only maintained locally.
*
* In either case, eventually we want the encrypted key to be available in the
* session for decrypting the user's files etc. In the web case, the page where
* the user reenters their password will put it there, while on desktop
* (assuming the key has already been saved to the OS safe storage), this
* {@link updateSessionFromElectronSafeStorageIfNeeded} function will do it.
*/
export const updateSessionFromElectronSafeStorageIfNeeded = async () => {
const electron = globalThis.electron;
if (!electron) return;
if (haveCredentialsInSession()) return;
let masterKey: string | undefined;
try {
masterKey = await electron.masterKeyB64();
} catch (e) {
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);
}
};
/**
* Return true if we both have the user's master key in session storage, and
* their auth token in KV DB.
*/
export const haveAuthenticatedSession = async () => {
if (!(await masterKeyFromSession())) return false;
const lsToken = getToken();
const kvToken = await getAuthToken();
// TODO: To avoid changing old behaviour, this currently relies on the token
// from local storage. Both should be the same though, so it throws an error
// on dev build (tag: Migration).
if (isDevBuild) {
if (lsToken != kvToken)
throw new Error("Local storage and indexed DB mismatch");
}
return !!lsToken;
};
/**
* Return the decrypted user's key encryption key ("kek") from session storage
* if present, otherwise return `undefined`.