Requested pre-promotion sweep of login methods, active signers, and anon session
actors. Four real bugs found and fixed:
1. Logging out could wipe EVERY saved account's remembered nsec key. The no-arg
clearStoredSessionActor() removed the whole per-account v2 map, and it was
reachable from SignerManager.logout() (non-persisted nsec cleanup) and from
the blocked-key cleanup in registerPrivateKeySigner — same bug class as the
NIP-46 session-map wipe fixed earlier. Now: the no-arg form clears only the
legacy v1 slot; logout targets the departing account (and skips entirely when
it can't name one); the blocked-key cleanup targets the blocked pubkey
(mirroring the already-targeted twin in unlockStoredSessionActor).
Spec-corrected the test that had encoded the wipe-all as intended behavior.
2. Removing a saved profile left its keys on the device. The switcher's
remove-account flow cleared NWC + the keep-unlocked cache but kept the
remembered (encrypted) nsec key and the NIP-46 session. New
client.forgetStoredAccount(pubkey) (SignerManager.forgetStoredSessionActor +
clearStoredNip46Session) forgets both WITHOUT touching the active session's
in-memory actors; wired into handleProfileLogoutRequest.
3. Logout never actually re-locked a kept-unlocked device. The forget read
detail.pubkey / this.pubkey — both already nulled by authService.logout()
(the detail only carries previousPubkey) — so the cached decrypted key
silently survived logout. Now reads previousPubkey.
4. restoreUnlockedSigner bypassed access control: a since-blacklisted account's
cached key would silently restore its signer. It now accepts a validator
(mirroring unlockStoredSessionActor), forgets the cached key on denial, and
both app-level call sites (_initAutoLogin, ensureEncryptionCapableSigner)
pass an accessControl.canAccess gate.
Also verified-safe during the pass (no action): logout's persisted-nsec keep
logic under the ephemeral session-actor overwrite; NIP-46 logout keepStored;
the ephemeral actor as a harmless extra DM-decrypt candidate; corrupt-map
recovery clears; anon blacklist-seeding now always has a signing-capable actor.
Tests: session-actor multi-account suite spec-corrected + re-verified (no-arg
clear keeps per-account keys); 57 tests across session-actor / nip46 /
unlocked-key / switch / signer-gate / feed-gate suites green. Lint + build green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>