mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Switching to a saved nsec profile silently failed: switchProfile -> requestLogin -> the
nsec provider was called with no passphrase, so it threw "secret-required" and the switch
was caught+logged with no user feedback. It never prompted for the PIN.
Now handleProfileSwitchRequest detects an nsec target and, before switching, prepares the
stored-key unlock:
- evaluateStoredNsecSwitch(meta, target) (pure) gates on a persisted nsec key for THIS
account (via getStoredSessionActorMetadata); errors clearly otherwise ("log in with its
nsec", "different account's key saved").
- showPasswordPrompt (js/ui/promptDialog.js) collects the PIN/passphrase in a styled
dialog (Promise<string|null>, stacks above modals).
- switchProfile(pubkey, { unlockStored: true, passphrase }) — authService.switchProfile
now forwards unlockStored/passphrase to requestLogin, which routes to the nsec
provider's unlockStoredSessionActor to restore the signer and activate the account.
- Wrong PIN -> "Incorrect PIN/passphrase" toast (decrypt-failed).
So NIP-07 -> nsec switching works fluently. NIP-46 switching is unchanged (follow-up to
verify/extend); multiple-nsec accounts still share one stored slot (follow-up).
Tests: tests/stored-nsec-switch.test.mjs (6), tests/password-prompt.test.mjs (6). Build +
lint clean; auth suites 25/25.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
50 lines
1.7 KiB
JavaScript
50 lines
1.7 KiB
JavaScript
// #48: switching to a saved nsec account must prompt for the PIN and unlock its stored
|
|
// key (switchProfile alone threw "secret-required"). evaluateStoredNsecSwitch is the
|
|
// pure gate: proceed to prompt when a matching stored nsec key exists; error otherwise.
|
|
|
|
import test from "node:test";
|
|
import { strict as assert } from "node:assert";
|
|
import { evaluateStoredNsecSwitch } from "../js/app/storedNsecSwitch.js";
|
|
|
|
const A = "a".repeat(64);
|
|
const B = "b".repeat(64);
|
|
const nsecMeta = (pubkey = A) => ({ hasEncryptedKey: true, pubkey, source: "nsec" });
|
|
|
|
test("prompts when a stored nsec key matches the target account", () => {
|
|
assert.deepEqual(evaluateStoredNsecSwitch(nsecMeta(A), A), { action: "prompt" });
|
|
});
|
|
|
|
test("prompts when the stored key has no pubkey to compare (can't rule it out)", () => {
|
|
assert.deepEqual(
|
|
evaluateStoredNsecSwitch({ hasEncryptedKey: true, source: "nsec" }, A),
|
|
{ action: "prompt" },
|
|
);
|
|
});
|
|
|
|
test("errors when there is no stored session at all", () => {
|
|
assert.deepEqual(evaluateStoredNsecSwitch(null, A), {
|
|
action: "error",
|
|
reason: "no-stored-key",
|
|
});
|
|
});
|
|
|
|
test("errors when the stored key isn't an nsec (e.g. left-over non-nsec metadata)", () => {
|
|
assert.deepEqual(
|
|
evaluateStoredNsecSwitch({ hasEncryptedKey: true, pubkey: A, source: "extension" }, A),
|
|
{ action: "error", reason: "no-stored-key" },
|
|
);
|
|
});
|
|
|
|
test("errors when the stored key belongs to a DIFFERENT account", () => {
|
|
assert.deepEqual(evaluateStoredNsecSwitch(nsecMeta(A), B), {
|
|
action: "error",
|
|
reason: "pubkey-mismatch",
|
|
});
|
|
});
|
|
|
|
test("case-insensitive pubkey match", () => {
|
|
assert.deepEqual(evaluateStoredNsecSwitch(nsecMeta(A.toUpperCase()), A), {
|
|
action: "prompt",
|
|
});
|
|
});
|