Skip to content

Say who is asking, and what they want signed - #46

Merged
sepehr-safari merged 1 commit into
mainfrom
approval-names-the-asker
Aug 10, 2026
Merged

Say who is asking, and what they want signed#46
sepehr-safari merged 1 commit into
mainfrom
approval-names-the-asker

Conversation

@sepehr-safari

Copy link
Copy Markdown
Contributor

An approval row read sign_event · kind 1 and stopped there. It looked exactly the same whether the request came from the user's own client or from anyone else who reached the signer, and telling those two apart is the only reason a person is in this loop at all.

Who. The row names the requester, first and last eight of their pubkey. Not the whole thing: sixty-four hex characters is not something anybody compares, and a row nobody reads is the same as no row.

What. For a sign_event, the row shows the start of the content. The kind number says what shape the event is and never what it says; approving a kind:1 without seeing its text is approving a sentence published under your name, sight unseen.

The preview is the requester's own text, so it is escaped on the way into the listing. Raw, a quote would end the JSON string and everything after it would be read as fields of that same object, which means the requester could give their own row a different method, a different kind, or somebody else's pubkey, on the very screen being used to decide about them. The client pubkey and the method need no escaping and I checked rather than assumed: one is hex, and the other has already parsed as one of seven fixed names before a policy ever sees it.

Needs nostr v0.5.0, where a policy is told which client is asking. Bumped here.

Tests. Daemon 18, GUI 21. The escaping test asserts a round trip through a real JSON parser rather than a string comparison, so it fails if the output merely looks escaped. The GUI test covers the three cases that matter: a full row, a method with nothing to preview (which must not draw an empty line), and a daemon that sent no client at all, which must say "unknown client" rather than print a misleading identity.

An approval row read "sign_event · kind 1" and stopped there. It looked
exactly the same whether the request came from the user's own client or
from anyone else who had reached the signer, and telling those two apart
is the only reason a person is in this loop.

It now names the requester, first and last of their pubkey, because
sixty-four hex characters is not something anybody compares. And for a
sign_event it shows the start of the content, because the kind number
says what SHAPE the event is and never what it says: approving a kind:1
unseen is approving a sentence published under your name.

The preview is the requester's own text, so it is escaped on the way into
the listing. Raw, a quote would end the string and everything after it
would be read as fields of that object, which means the requester could
give their own row a different method, a different kind, or somebody
else's pubkey, on the screen being used to decide about them. The client
pubkey and the method are safe as they stand: one is hex, and the other
has already parsed as one of seven fixed names before a policy sees it.

Needs nostr v0.5.0, where a policy is told which client is asking.
@sepehr-safari
sepehr-safari merged commit 0b9850c into main Aug 10, 2026
3 checks passed
@sepehr-safari
sepehr-safari deleted the approval-names-the-asker branch August 10, 2026 22:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant