Avoid exceptions for flow control

This commit is contained in:
Manav Rathi
2025-06-04 13:55:50 +05:30
parent a244140348
commit 12d84d0dbe
2 changed files with 29 additions and 17 deletions

View File

@@ -15,6 +15,9 @@ export interface VerifyMasterPasswordFormProps {
* The user whose password we're trying to verify.
*/
user: User | undefined;
/**
* The user's key attributes.
*/
keyAttributes: KeyAttributes | undefined;
/**
* A callback invoked when the form wants to get {@link KeyAttributes}.
@@ -33,6 +36,9 @@ export interface VerifyMasterPasswordFormProps {
* the provided email exists.
*/
getKeyAttributes?: (kek: string) => Promise<KeyAttributes | undefined>;
/**
* The user's SRP attributes.
*/
srpAttributes?: SRPAttributes;
/**
* The title of the submit button no the form.
@@ -42,12 +48,14 @@ export interface VerifyMasterPasswordFormProps {
* The callback invoked with the verified password, and all the other
* auxillary information that was ascertained when verifying it.
*
* @param key The user's master key obtained after decrypting it from their
* passphrase.
* @param key The user's master key obtained after decrypting it by using
* the kek derived from their passphrase.
*
* @param kek
* @param kek The key used for encrypting the user's master key.
*
* @param keyAttributes
* @param keyAttributes The user's key attributes (either those that we
* started with, or those that we fetched on the way using
* {@link getKeyAttributes}).
*
* @param passphrase The plaintext passphrase. This can be used during login
* to derive another encrypted key using interactive mem/ops limits for
@@ -104,33 +112,41 @@ export const VerifyMasterPasswordForm: React.FC<
try {
const cryptoWorker = await sharedCryptoWorker();
let kek: string;
try {
if (srpAttributes) {
if (srpAttributes) {
try {
kek = await cryptoWorker.deriveKey(
passphrase,
srpAttributes.kekSalt,
srpAttributes.opsLimit,
srpAttributes.memLimit,
);
} else if (keyAttributes) {
} 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,
);
} else
throw new Error("Both SRP and key attributes are missing");
} catch (e) {
log.error("failed to derive key", e);
throw Error(CustomError.WEAK_DEVICE);
}
} 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");
}
try {
const key = await cryptoWorker.decryptB64(
keyAttributes.encryptedKey,
@@ -150,9 +166,6 @@ export const VerifyMasterPasswordForm: React.FC<
}
log.error("failed to verify passphrase", e);
switch (e.message) {
case CustomError.WEAK_DEVICE:
setFieldError(t("weak_device_hint"));
break;
case CustomError.INCORRECT_PASSWORD:
setFieldError(t("incorrect_password"));
break;

View File

@@ -40,7 +40,6 @@ export const CustomError = {
BAD_REQUEST: "bad request",
SUBSCRIPTION_NEEDED: "subscription not present",
NOT_FOUND: "not found ",
WEAK_DEVICE: "password decryption failed on the device",
INCORRECT_PASSWORD: "incorrect password",
INCORRECT_PASSWORD_OR_NO_ACCOUNT: "incorrect password or no such account",
UPLOAD_CANCELLED: "upload cancelled",