From 12d84d0dbe4ba3de99ce93445f75cb81d2c468bc Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 4 Jun 2025 13:55:50 +0530 Subject: [PATCH] Avoid exceptions for flow control --- .../components/VerifyMasterPasswordForm.tsx | 45 ++++++++++++------- web/packages/shared/error/index.ts | 1 - 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx index 62b4c7c9aa..b6a812754f 100644 --- a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx +++ b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx @@ -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; + /** + * 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; diff --git a/web/packages/shared/error/index.ts b/web/packages/shared/error/index.ts index 348cc94676..3aa47fa01c 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 ", - 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",