Commit Graph
2 Commits
Author SHA1 Message Date
thePR0M3TH3ANandClaude Opus 4.8 4795d5edbd [auth] Bug pass on login/signer/session surface: 4 fixes before promotion
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]>
2026-07-02 21:59:52 -04:00
thePR0M3TH3ANandClaude Opus 4.8 8692dac671 [nostr-core] Per-account nsec key storage for multi-account switching (#48)
Move the encrypted-key store from a single slot to a per-pubkey map so
several saved nsec accounts each keep their own key on the device and the
profile switcher can move between them. Previously bitvid:sessionActor:v1
held one key (last-saved wins), so switching among saved nsec accounts
silently failed.

- sessionActor.js: new bitvid:sessionActors:v2 map keyed by pubkey (follows
  the existing bitvid:<thing>:<npub> convention). readStoredSessionActorEntry,
  persistSessionActor, clearStoredSessionActor take an optional target pubkey;
  legacy v1 slot is kept in sync as the last-saved default and migrated into
  the map on first read. IndexedDB mirror keyed per-pubkey. Adds
  listStoredSessionActorPubkeys().
- client.js: getStoredSessionActorMetadata / unlockStoredSessionActor accept a
  target pubkey; access-denial cleanup forgets only the blocked account.
- nsec provider threads expectPubkey into the unlock so a switch unlocks the
  requested account, with the expectPubkey guard as a backstop.
- authSessionCoordinator: look up the target account's stored-key metadata.

NIP-46 multi-account (single slot bitvid:nip46:session:v1) remains as a
follow-up. Tests: tests/session-actor-multi-account.test.mjs (7).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-30 22:33:03 -04:00