Files
amethyst/commons
Claude 4676d176ec feat(nip46): live per-request + first-connect consent (Tier 1)
Wire the NIP-46 remote signer into the same interactive consent surface the
napplet/browser signer path uses, so requests that aren't pre-granted prompt
instead of silently failing.

The ledger already returns ASK for the risky operations (profile 0, contacts
3, deletion 5, decryption, DMs are excluded from REASONABLE_SIGN_KINDS; a
PARANOID app asks for everything) — the only reason it didn't work was that
authorize() treated ASK as "unauthorized". Now:

- authorize(): ALLOW proceeds, DENY refused, ASK consults an in-memory session
  grant then calls opConsent (the shared per-op dialog). The returned
  SignerOpGrant is recorded via a new NostrSignerPermissionLedger.record()
  helper (allow-for-op / until / all / deny-for-op persisted; once/session not),
  mirroring the broker. No opConsent wired → ASK fails closed (CLI/tests).
- onConnect(): first contact asks connectConsent for the trust level
  (AppConnectResult) instead of silently granting REASONABLE; Blocked/Cancelled
  reject the connection. Falls back to defaultPolicyOnConnect when no prompt.
- forget() also clears the client's in-memory session grants.

Nip46ConsentBridge (amethyst) implements the two prompts by reusing the
existing NappletConnect/NappletSignerConsent coordinators + dialogs + ledger,
building the render info from the bunker request (op label, event JSON
preview, client metadata/icon). A 120s timeout fails a stuck per-op prompt
closed so it can't wedge the signer's single-consumer loop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FHr2mu5SiHwYNR7evYUuF
2026-07-17 15:18:28 +00:00
..