fix(reauth): wrong master pw re-prompts inline instead of closing
Setting a PIN, enabling Quick Unlock, and generating a recovery key all closed the reauth modal and showed a toast on the first wrong master password — no retry. Export already looped inline; the others didn't. Extracted that loop into reauthLoop(message): re-prompts with an inline error + attempt count (5 tries), honours the 429 lockout, returns the verified password or null. All four sensitive-action flows now share it, so a mistyped master password keeps the modal up to try again. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+4
-33
@@ -791,39 +791,10 @@ async function doExport() {
|
||||
// Step 1: reauth — verifies the human in front of the screen is the
|
||||
// vault owner before we hand them every plaintext password. Defense
|
||||
// against a stranger reaching the open laptop and exfiltrating data.
|
||||
// Up to 5 retries with inline error in the modal — beyond that the
|
||||
// server-side rate limiter takes over (429 with retry_after).
|
||||
let lastError = null;
|
||||
let attempts = 0;
|
||||
const MAX_ATTEMPTS = 5;
|
||||
let reauthed = false;
|
||||
while (!reauthed) {
|
||||
const masterPwd = await askReauth(
|
||||
'Enter your master password to start an encrypted export.',
|
||||
{ error: lastError });
|
||||
if (!masterPwd) return; // user cancelled
|
||||
try {
|
||||
const verifier = await computeVerifier(
|
||||
masterPwd, state.salt, state.kdfIterations || 100000, state.hashAlgo, state.argon2Params);
|
||||
await api('/reauth', {
|
||||
method: 'POST',
|
||||
headers: authHeaders({ 'Content-Type': 'application/json' }),
|
||||
body: JSON.stringify({ verifier: verifier }),
|
||||
});
|
||||
reauthed = true;
|
||||
} catch (err) {
|
||||
if (err.status === 429 && err.body && err.body.retry_after) {
|
||||
return toast('Account locked. Try again in ' +
|
||||
Math.ceil(err.body.retry_after / 60) + ' min', 'warning');
|
||||
}
|
||||
attempts++;
|
||||
if (attempts >= MAX_ATTEMPTS) {
|
||||
return toast('Too many wrong attempts — try again later', 'error');
|
||||
}
|
||||
lastError = 'Wrong master password. Attempt ' +
|
||||
attempts + ' / ' + MAX_ATTEMPTS + '.';
|
||||
}
|
||||
}
|
||||
// reauthLoop re-prompts inline (up to 5 tries) then defers to the
|
||||
// server rate limiter; null = cancelled or capped (already toasted).
|
||||
if (!(await reauthLoop('Enter your master password to start an encrypted export.')))
|
||||
return;
|
||||
|
||||
// Step 2: ask for an INDEPENDENT export password. Decoupled from the
|
||||
// master pw so a master-pw change later doesn't invalidate the backup,
|
||||
|
||||
Reference in New Issue
Block a user