Skip to content

fix(cli): normalize the pubkey a moderation action is keyed on - #5963

Closed
chessing234 wants to merge 2 commits into
block:mainfrom
chessing234:fix/cli-normalize-moderation-hex
Closed

chessing234 wants to merge 2 commits into
block:mainfrom
chessing234:fix/cli-normalize-moderation-hex

Conversation

@chessing234

Copy link
Copy Markdown
Contributor

Found by reading validate_hex64 against its own doc comment; no issue filed.

buzz moderation ban <pubkey> validates the hex and then publishes it verbatim. Paste a pubkey in uppercase — from a block explorer, a log line, a colleague's message — and the ban goes out as ["p", "ABC…"].

Nothing resolves that to the person. Relays match tag values byte for byte (filter_match_one compares event_val == filter_val), and every other producer in the tree lowercases — normalizeMentionPubkeys in the desktop's threading.ts, normalizePubkey in shared/lib/pubkey.ts. So the ban is published, acknowledged, printed as success, and applies to nobody. unban, timeout, untimeout and report resolution all share the shape.

validate_hex64's doc says it validates a "64-character lowercase hex string", but is_ascii_hexdigit accepts either case and no caller normalizes. The first commit adds parse_hex64 — validate, then return the value lowercased — and corrects that doc to say what the function actually does. The second uses it in moderation.rs. A pubkey that was already lowercase is unaffected.

Scope. There are ~55 other validate_hex64 call sites with the same latent gap, across issues, PRs, patches, reactions and social. They're separable, and each needs its own look at whether the value ends up in a tag, a URL path, or only a local comparison — I didn't want to sweep 14 files blind. Moderation is the one where the failure mode is worst: a command that reports success and silently does nothing.

Verified locally on the pinned 1.95.0 toolchain:

  • cargo test -p buzz-cli — 352 passed, 0 failed (349 before, plus the 3 new)
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • cargo fmt --all -- --check — clean

Note: I'm an outside contributor, so the workflow runs here sit at action_required until a maintainer approves them; only the DCO check reports on its own.

`validate_hex64` is documented as validating a "64-character lowercase hex
string" but accepts either case — `is_ascii_hexdigit` does. Every caller then
passes the string through unchanged.

Hex is case-insensitive to a human and byte-exact to a relay: a filter for
`#p` `abc…` does not match a tag holding `ABC…`. Add `parse_hex64`, which
validates and returns the value lowercased, for callers that put the string
on the wire, and correct the older function's doc to say what it does.

No call sites yet.

Signed-off-by: Taksh <takshkothari09@gmail.com>
`buzz moderation ban <pubkey>` validated the hex and then published it
verbatim. Paste a pubkey in uppercase — from a block explorer, a log line, a
colleague's message — and the ban goes out as `["p", "ABC…"]`.

Nothing resolves that to the person. Relays match tag values byte for byte,
and every other producer in the tree lowercases (`normalizeMentionPubkeys`,
the desktop's `normalizePubkey`), so the ban is published, acknowledged, and
silently applies to nobody. Unban, timeout, untimeout and report resolution
all share the shape.

Take the lowercased value from `parse_hex64` instead. A pubkey that was
already lowercase is unaffected.

The other ~55 `validate_hex64` call sites have the same latent gap; this one
is separable and its failure mode — a moderation action that reports success
and does nothing — is the worst of them.

Signed-off-by: Taksh <takshkothari09@gmail.com>
@chessing234
chessing234 requested a review from a team as a code owner August 15, 2026 15:27
@chessing234

Copy link
Copy Markdown
Contributor Author

closing this — i was wrong. buzz-sdk's check_pubkey_hex already returns s.to_ascii_lowercase(), and every moderation builder runs the pubkey through it before writing the p tag, so the ban goes out lowercase either way and this changed nothing. should have checked the builder before opening.

the underlying gap is real, just one layer over: the cli builds some nip-01 filters as raw json, and generic tag filters (#e, #p) are string-compared, unlike ids/authors which the relay parses into typed values. will open that separately with the call sites where it actually bites.

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