fix: Back from Settings no longer lands on a delete wallet screen left by the gear #484

Merged
clawbot merged 1 commits from issue-480-delete-screen-back into next 2026-10-07 03:43:08 +02:00
4 changed files with 78 additions and 5 deletions
+6
View File
@@ -1838,6 +1838,9 @@ view would leave a wallet one click from deletion.
try again." on the error line, nothing deleted
- "I have lost my password" → **DeleteWalletLostPassword**
- "Back" → previous screen (Settings)
- Settings gear → **Settings**, whose "Back" never lands back on this
screen: leaving drops the wallet the screen was showing, so it also takes
the screen off the Back stack
#### DeleteWalletLostPassword (`delete-wallet-lost-password`)
@@ -1876,6 +1879,9 @@ view would leave a wallet one click from deletion.
selection comes back with it. The two delete screens are siblings rather
than parent and child: nothing is pushed on the way here, so both have
Settings as their Back target.
- Settings gear → **Settings**, whose "Back" never lands back on this
screen: leaving drops the wallet the screen was showing, so it also takes
the screen off the Back stack
- **Deliberately not password-gated.** A password in front of _discarding_ a
secret protects nobody: an attacker at the popup who wants the wallet gone can
uninstall the extension, so the only person such a gate stops is the owner who
+9
View File
@@ -45,6 +45,15 @@ but the review is broader than any of them.
# Completed Steps
- 2026-10-06: Back from Settings no longer lands on the delete wallet or
lost-password screen after either was left by the settings gear
([#480](https://git.eeqj.de/sneak/AutistMask/issues/480)), the defect
[#461](https://git.eeqj.de/sneak/AutistMask/issues/461) fixed for the two
secret screens. Leaving drops the screen's wallet selection, so its leave
handler now also takes it off the Back stack, as a reopened popup already
does. `tests/deleteWalletLostPassword.test.js` drives the gear and then Back
on both screens.
- 2026-10-06: `script/bootstrap` no longer reports success while node cannot
find a package listed in `dependencies` or `devDependencies` of `package.json`
([#263](https://git.eeqj.de/sneak/AutistMask/issues/263)). After the install
+22 -5
View File
@@ -49,9 +49,9 @@ function confirmKey(name) {
}
// Drop the password from the DOM and the wallet selection from the
// closure. Registered as the view-leave handler as well as run on entry,
// so the typed password does not sit in the hidden view after the user
// navigates away by any route, including the Settings gear.
// closure. Run by the view-leave handler as well as on entry, so the typed
// password does not sit in the hidden view after the user navigates away
// by any route, including the Settings gear.
function clear() {
deleteWalletIndex = null;
$("delete-wallet-password").value = "";
@@ -147,8 +147,25 @@ async function finishDelete(walletIdx) {
function init(_ctx) {
ctx = _ctx;
onViewLeave("delete-wallet-confirm", clear);
onViewLeave("delete-wallet-lost-password", clearLostPassword);
// Leaving drops the wallet selection, so each screen also comes off the
// Back stack, where the settings gear has just put it: Back from
// Settings must not land on a screen whose button can only answer "No
// wallet selected for deletion." A reopened popup drops them from the
// stack the same way (https://git.eeqj.de/sneak/AutistMask/issues/480).
onViewLeave("delete-wallet-confirm", () => {
clear();
const stack = state.viewStack;
if (stack[stack.length - 1] === "delete-wallet-confirm") {
stack.pop();
}
});
onViewLeave("delete-wallet-lost-password", () => {
clearLostPassword();
const stack = state.viewStack;
if (stack[stack.length - 1] === "delete-wallet-lost-password") {
stack.pop();
}
});
// No wipe here: goBack() routes through showView(), which runs the
// leave hook.
+41
View File
@@ -615,3 +615,44 @@ describe("the password route's confirm button", () => {
]);
});
});
// https://git.eeqj.de/sneak/AutistMask/issues/480: leaving either delete
// screen drops its wallet selection, so Back onto one showed a screen whose
// button could only answer "No wallet selected for deletion."
describe("Back from Settings after leaving by the settings gear", () => {
test("does not land on the delete screen", () => {
const { helpers, deleteWallet, state } = load();
deleteWallet.show(1);
// The settings gear: push the current view, then show Settings.
helpers.pushCurrentView();
helpers.showView("settings");
expect(state.viewStack).toEqual(["main", "settings"]);
helpers.goBack();
expect(state.currentView).not.toBe("delete-wallet-confirm");
});
test("does not land on the lost-password screen", async () => {
const { helpers, deleteWallet, state } = load();
await openLostPassword(deleteWallet, 1);
// The settings gear: push the current view, then show Settings.
helpers.pushCurrentView();
helpers.showView("settings");
expect(state.viewStack).toEqual(["main", "settings"]);
helpers.goBack();
expect(state.currentView).not.toBe(VIEW);
});
// The lost-password screen's own Back is "Back returns to the delete
// screen with its wallet still chosen", above.
test("the delete screen's own Back leaves the rest of the stack alone", async () => {
const { deleteWallet, state } = load();
deleteWallet.show(1);
await click("btn-delete-wallet-back");
expect(state.currentView).toBe("settings");
expect(state.viewStack).toEqual(["main"]);
});
});