mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-06 12:52:26 +00:00
[auth] Route reactions, blocks, subscriptions & DM send through the signer gate (#54/#57)
Fast-follows to the ensureEncryptionCapableSigner gate: every remaining signing/encryption flow now re-unlocks a reloaded nsec signer with one passphrase prompt instead of dead-ending. Each call site short-circuits ONLY on the user-driven outcomes (cancel / bad-passphrase); every other case falls through to the flow's own existing error handling, so non-nsec signers (e.g. an unresponsive NIP-07 extension) behave exactly as before. - Reactions (#54): ReactionController.handleReaction gates before the optimistic update with need:"sign" (kind-7 reactions don't need encryption) — fixes the "like/dislike does nothing" that was a rolled-back publish on a lost signer. - Blocks: handleProfileBlocklistMutation (need:"encrypt", NIP-04 mute/block lists). - Subscriptions: the channel Subscribe/Unsubscribe toggle (need:"encrypt", kind 30000). - DM send: both composers — handleSendProfileMessage and handleDmAppShellSendMessage (need:"encrypt", NIP-17/NIP-04). Reactions get the gate via a new ensureSigner callback on ReactionController; the modal flows use the services.ensureEncryptionCapableSigner already exposed. Tests: tests/reaction-signer-gate.test.mjs (3 — cancelled/bad-passphrase block publish, ok proceeds, asserts need:"sign"). Related suites (decision, DM, profile modal, switch delegators) green. Lint + build green. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
1b79ab9d09
commit
1622e85d10
7 files changed
+243
-8
No files matched your search
@@ -240,6 +240,32 @@ export class ProfileDirectMessageActions {
|
||||
return;
|
||||
}
|
||||
|
||||
// DMs are encrypted (NIP-17 gift wrap / NIP-04). A reloaded nsec session can
|
||||
// lose its in-memory key; re-unlock it with one passphrase prompt rather than
|
||||
// failing to send (TODO #57). Only user-driven outcomes stop the send; other
|
||||
// cases fall through to sendDirectMessage's own error handling.
|
||||
const ensureSigner =
|
||||
this.mainController.services?.ensureEncryptionCapableSigner;
|
||||
if (typeof ensureSigner === "function") {
|
||||
let ensured = { ok: true };
|
||||
try {
|
||||
ensured = await ensureSigner({
|
||||
pubkey: this.controller.helper.resolveActiveDmActor(),
|
||||
need: "encrypt",
|
||||
promptMessage:
|
||||
"Re-enter your PIN / passphrase to unlock your key and send messages.",
|
||||
});
|
||||
} catch (error) {
|
||||
ensured = { ok: false, reason: "ensure-failed" };
|
||||
}
|
||||
if (
|
||||
ensured &&
|
||||
(ensured.reason === "cancelled" || ensured.reason === "bad-passphrase")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const sendButton = this.controller.renderer.profileMessageSendButton;
|
||||
if (sendButton instanceof HTMLElement && "disabled" in sendButton) {
|
||||
sendButton.disabled = true;
|
||||
@@ -489,6 +515,35 @@ export class ProfileDirectMessageActions {
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-unlock a reloaded nsec signer before sending (TODO #57). Same gate as the
|
||||
// profile-modal composer; only user-driven outcomes stop the send.
|
||||
const ensureSigner =
|
||||
this.mainController.services?.ensureEncryptionCapableSigner;
|
||||
if (typeof ensureSigner === "function") {
|
||||
let ensured = { ok: true };
|
||||
try {
|
||||
ensured = await ensureSigner({
|
||||
pubkey: actor,
|
||||
need: "encrypt",
|
||||
promptMessage:
|
||||
"Re-enter your PIN / passphrase to unlock your key and send messages.",
|
||||
});
|
||||
} catch (error) {
|
||||
ensured = { ok: false, reason: "ensure-failed" };
|
||||
}
|
||||
if (
|
||||
ensured &&
|
||||
(ensured.reason === "cancelled" || ensured.reason === "bad-passphrase")
|
||||
) {
|
||||
this.controller.dmComposerState = "idle";
|
||||
await this.controller.renderer.renderDmAppShell(
|
||||
this.controller.directMessagesCache,
|
||||
{ actorPubkey: actor },
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const privacyMode =
|
||||
typeof normalizedPayload.privacyMode === "string"
|
||||
? normalizedPayload.privacyMode.trim().toLowerCase()
|
||||
|
||||
Reference in new issue
Block a user