fix: give a wallet whose password is lost a way out, and say the password cannot be reset (closes #312)
A user who forgot their password but held their recovery phrase was permanently locked out: deletion was password-gated and re-importing the phrase was refused as a duplicate. Their only escape was destroying extension storage through browser internals, taking every other wallet with it. DeleteWallet gains an "I have lost my password" route that destroys the stored secret after the wallet's name is typed back. No password gate was added: requiring one to discard a secret protects nothing, since an attacker who wants destruction can uninstall the extension, and the only person it stops is the legitimate user who lost it. The screen is excluded from RESTORABLE_VIEWS and registers an onViewLeave cleanup. Deletion was chosen over re-import because a key wallet is duplicate-checked by address rather than xpub, so an xpub-only relaxation would leave that user still wedged; because re-import makes the user retype their recovery phrase into a live popup merely to change a password; and because it reaches no end state that delete-then-import plus scanForAddresses() does not. The attacker argument did not decide it — re-import clears the "no worse than the phrase alone" bar. All three AddWallet password hints now state the password cannot be recovered or reset and name that mode's only backup, the xprv mode correctly claiming no recovery phrase. deleteAddress.js no longer tells the user that deleting a wallet asks for a password, which this change made false. The typed confirmation collapses internal whitespace on both sides: a wallet renamed with two spaces displays with one, so the string a user could see and type could never match, making the confirmation untypable on the one screen whose purpose is un-wedging a stuck user. Measured, not reasoned, after review found the first reserve twice too large and pushing the Import button below the fold: #btn-add-wallet-confirm bottom 628.13 -> 580.13 at 360x600, scrollHeight 636 -> 600, hint box 48px identical across all three tabs and on re-entry. make check 40 suites / 828 tests, test-e2e 55/55, test-e2e-firefox 8/8.
This commit was merged in pull request #334.
This commit is contained in:
26
TODO.md
26
TODO.md
@@ -44,6 +44,32 @@ but the review is broader than any of them.
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-08-20: A forgotten password no longer wedges the wallet
|
||||
([#312](https://git.eeqj.de/sneak/AutistMask/issues/312)). Deleting a wallet
|
||||
was password-gated and importing its recovery phrase again was refused as a
|
||||
duplicate xpub, so a user who had the phrase but not the password could
|
||||
neither leave nor come back: the only way out was clearing extension storage
|
||||
through browser internals, which takes every other wallet with it.
|
||||
DeleteWallet now offers "I have lost my password", a screen that destroys the
|
||||
wallet after the user types its name back — no password, because requiring one
|
||||
to _discard_ a secret protects nobody. An attacker at the popup who wants the
|
||||
wallet gone can uninstall the extension; the only person such a gate stopped
|
||||
was the owner who forgot it. That was chosen over allowing a duplicate xpub to
|
||||
re-encrypt in place: re-import would have had to be built three times over
|
||||
(`hd` and `xprv` by xpub, `key` by address), would make the user retype the
|
||||
recovery phrase into a live popup to change a password, and reaches no state
|
||||
that delete-then-import does not already reach through `scanForAddresses()`.
|
||||
Both routes share one `finishDelete()`, so the selection repair, the
|
||||
site-permission cleanup and the `AUTISTMASK_ACTIVE_CHANGED` broadcast cannot
|
||||
diverge between them, and the new screen is excluded from `RESTORABLE_VIEWS` —
|
||||
a popup reopened by accident must not land on a button that erases key
|
||||
material. AddWallet's password hint now says, per import mode, that the
|
||||
password cannot be recovered or reset and what the only backup is; the hint
|
||||
line reserves its height so switching tabs cannot move the password fields.
|
||||
The test drives the real view against a `chrome.storage.local` stub that
|
||||
structured-clones on both `set` and `get` and asserts against the read-back,
|
||||
so it fails on the deletion of `saveState()` and not only on an in-memory
|
||||
splice.
|
||||
- 2026-08-20: `make build` can no longer hand back a debug build, and
|
||||
`script/verify-build` can no longer be satisfied by bytes the build did not
|
||||
produce ([#309](https://git.eeqj.de/sneak/AutistMask/issues/309)). The
|
||||
|
||||
Reference in New Issue
Block a user