mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
[nip46] Stop connection teardown from wiping ALL saved remote-signer sessions
Switching from a NIP-46 account to another account (e.g. an nsec account) failed to switch BACK with "No remote signer session is stored on this device." Root cause: disconnectRemoteSigner() defaults to keepStored:false and calls the no-argument clearStoredNip46Session(), which removed the entire per-account v2 map (bitvid:nip46:sessions:v2) — deleting EVERY saved account's session, not just a teardown of the live connection. Four nip46Connector connect/handshake-error paths call the same no-arg clear, so any connect hiccup also nuked all sessions. Fix: the no-argument clearStoredNip46Session() now clears ONLY the legacy v1 "last-connected" default slot and leaves the per-account v2 map intact. A specific account is still forgotten via clearStoredNip46Session(pubkey) (unchanged), so removing one account is unaffected while switching between saved NIP-46 accounts survives connection teardown. Spec correction: the prior test asserted the buggy "no-arg clear wipes everything"; replaced with the corrected behavior + a switch-away/switch-back regression. Test: tests/nip46-multi-account.test.mjs (7). Lint + build green. NOTE: this prevents future wipes; a session already deleted by the bug must be reconnected once (Login → remote signer) — after which switching persists. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
3df398d7ad
commit
6bf2cf26fd
2 files changed
+28
-11
No files matched your search
@@ -582,16 +582,18 @@ export function clearStoredNip46Session(pubkey) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No target pubkey: clear ONLY the legacy v1 "last connected" default slot.
|
||||
// We must NOT wipe the per-account v2 map here — the no-arg callers are all
|
||||
// connection teardown / connect-error paths (disconnectRemoteSigner, handshake
|
||||
// failures). Wiping the whole map deleted EVERY saved account's remote-signer
|
||||
// session, so after switching away (e.g. to an nsec account) you could no longer
|
||||
// switch back to a NIP-46 account ("No remote signer session is stored on this
|
||||
// device"). A specific account is forgotten via clearStoredNip46Session(pubkey).
|
||||
try {
|
||||
storage.removeItem(NIP46_SESSION_STORAGE_KEY);
|
||||
} catch (error) {
|
||||
// ignore cleanup issues
|
||||
}
|
||||
try {
|
||||
storage.removeItem(NIP46_SESSIONS_MAP_STORAGE_KEY);
|
||||
} catch (error) {
|
||||
// ignore cleanup issues
|
||||
}
|
||||
}
|
||||
|
||||
export function decodeNpubToHex(npub) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// NIP-46 accounts silently reconnected the wrong one (or failed).
|
||||
//
|
||||
// test_integrity_note:
|
||||
// change_type: ["new_tests"]
|
||||
// change_type: ["new_tests", "spec_correction"]
|
||||
// scenarios:
|
||||
// - id: SCN-nip46-multi-account-storage
|
||||
// given: "two NIP-46 accounts each persist a stored session"
|
||||
@@ -93,15 +93,30 @@ test("no-arg read returns the last-connected account as the default", () => {
|
||||
assert.equal(readStoredNip46Session().remotePubkey, REMOTE_B);
|
||||
});
|
||||
|
||||
test("no-arg clear wipes every stored session (logout)", () => {
|
||||
// spec_correction: the previous test asserted "no-arg clear wipes every stored
|
||||
// session (logout)". That encoded a bug: the no-arg clear is invoked from
|
||||
// connection-teardown / connect-error paths (disconnectRemoteSigner, handshake
|
||||
// failures) — NOT only an explicit logout. Wiping the whole per-account map there
|
||||
// deleted EVERY saved account's session, so switching away from a NIP-46 account
|
||||
// (e.g. to an nsec account) then made switching back fail with "No remote signer
|
||||
// session is stored on this device." Correct behavior: no-arg clear drops only the
|
||||
// legacy v1 "last-connected" default; per-account v2 sessions survive. Forgetting a
|
||||
// specific account uses the targeted clearStoredNip46Session(pubkey) (tested above).
|
||||
test("no-arg clear drops the legacy v1 default but KEEPS per-account v2 sessions", () => {
|
||||
writeStoredNip46SessionSync(session(USER_A, REMOTE_A, "wss://a.example"));
|
||||
writeStoredNip46SessionSync(session(USER_B, REMOTE_B, "wss://b.example"));
|
||||
|
||||
clearStoredNip46Session();
|
||||
clearStoredNip46Session(); // e.g. tearing down the live connection on a switch
|
||||
|
||||
assert.deepEqual(listStoredNip46SessionPubkeys(), []);
|
||||
assert.equal(readStoredNip46Session(USER_A), null);
|
||||
assert.equal(readStoredNip46Session(), null);
|
||||
// Both accounts remain reconnectable — switching back to either still works.
|
||||
assert.deepEqual(
|
||||
listStoredNip46SessionPubkeys().sort(),
|
||||
[USER_A, USER_B].sort(),
|
||||
);
|
||||
assert.equal(readStoredNip46Session(USER_A).remotePubkey, REMOTE_A);
|
||||
assert.equal(readStoredNip46Session(USER_B).remotePubkey, REMOTE_B);
|
||||
// The legacy single-slot default is gone (no ambiguous "last connected").
|
||||
assert.equal(localStorage.getItem(NIP46_SESSION_STORAGE_KEY), null);
|
||||
});
|
||||
|
||||
test("a legacy v1 single-slot session migrates into the per-pubkey map", () => {
|
||||
|
||||
Reference in new issue
Block a user