From 8b02a5650a0c6f4db7f113db5bf9f57f09a340c3 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Sat, 25 Jul 2026 16:22:50 +0100 Subject: [PATCH] fix(health): Fix button must not act when the switch was cancelled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vault health → Fix on entry B while the editor is open and dirty on entry A: the discard prompt appears, Cancel keeps A open — but openEntryForFix carried on regardless. It unmasked A's password to cleartext, selected it, and pulsed the Generate button (the blinking). Wrong entry, and it revealed a password the user never asked to see. openSlideOver was void, so callers couldn't tell a cancelled switch from a successful one. It now returns false when it bails (discard cancelled, entry not found) and true once the panel actually shows the requested entry; openEntryForFix checks it before touching the password field. Co-Authored-By: Claude Opus 4.8 --- js/app.health.js | 5 ++++- js/app.js | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/js/app.health.js b/js/app.health.js index 8aa55e1..8b15198 100644 --- a/js/app.health.js +++ b/js/app.health.js @@ -93,7 +93,10 @@ function healthScoreBand(score) { // dismiss. Auto-opening the generator modal hid the entry context and // forced an extra Save click — worse UX than this lighter nudge. async function openEntryForFix(entryId) { - await openSlideOver(entryId); + // Bail if the editor didn't actually switch (user cancelled the discard + // prompt): the steps below would unmask + select the password of whatever + // entry is still open, and pulse Generate on it — the wrong entry. + if (!(await openSlideOver(entryId))) return; const pwd = document.getElementById('soPassword'); if (pwd) { pwd.type = 'text'; // unmask so the user sees what they're replacing diff --git a/js/app.js b/js/app.js index 842b2ea..7349418 100644 --- a/js/app.js +++ b/js/app.js @@ -3815,9 +3815,9 @@ async function openSlideOver(id, opts) { okText: 'Discard', danger: true, }); - if (!ok) return; + if (!ok) return false; // caller must not act on a panel that didn't switch } - if (!isNew && !e) return; + if (!isNew && !e) return false; // The editor must be visible when it opens: Settings sits ABOVE the // slideover, so a hotkey (Ctrl+Shift+A) fired with Settings open left @@ -4019,6 +4019,10 @@ async function openSlideOver(id, opts) { } renderGrid(); + // true = the panel is now showing `id`. Callers that chain an action on + // the opened entry (openEntryForFix) MUST check this — a cancelled + // discard prompt leaves the previous entry in place. + return true; } // "Show history" launcher — placed below the password field for logins,