fix(cli): fold kind 40003 edits into messages get/thread, author-matched - #6474
Open
sanjay3290 wants to merge 2 commits into
Open
fix(cli): fold kind 40003 edits into messages get/thread, author-matched#6474sanjay3290 wants to merge 2 commits into
sanjay3290 wants to merge 2 commits into
Conversation
Signed-off-by: Sanjay Ramadugu <sramadugu1@gmail.com>
Signed-off-by: Sanjay Ramadugu <sramadugu1@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6388.
buzz messages editpublishes a kind40003event, the relay stores it, andmessages getnever shows it —40003was simply absent from the kinds filter.messages threadfetches it and then prints the edit and the stale original side by side.What this does
A single pure function,
apply_edits(&[Value]) -> Vec<Value>, folds each target's latest40003onto the original, drops the raw edit rows, and stampsedited_at. Bothcmd_get_messagesandcmd_get_threadcall it after their sort, so the two commands can no longer disagree. The kinds list moves intoget_message_kinds()so the filter and its test read the same code path.Semantics:
edit.pubkey == target.pubkey.created_atwins; ties break on the lexicographically larger event id.The author gate runs before ranking, not after
This is the part worth reviewing. Checking the author on the winning edit is not equivalent to checking it while building the map, and the difference is a message-suppression bug.
If ranking happens first, an attacker publishes a
40003tagging your message with acreated_atabove your genuine edit. Their forgery takes the map slot; your real edit is discarded. The author check then rejects the forgery, and the reader falls back to the original content. Anyone in the channel can blank out any edit anyone makes.A one-edit fixture cannot see this — with a single edit in the window the two placements behave identically.
hostile_edit_must_not_suppress_a_genuine_author_edituses the three-event case that distinguishes them: target(author) / edit(author, t=2000, "genuine edit") / edit(other, t=3000, "hijack"). Expected and actual is "genuine edit".Note for reviewers: the CLI edit-surfacing in the still-open #2781 has the same ordering, and no author check at all. I left the details there.
Tests
7 tests in
apply_edits_tests, written before the fix and watched fail. Deletion probes, both compiling and both producing real failures:edit_by_non_author_is_ignoredandhostile_edit_must_not_suppress_a_genuine_author_editfail.40003fromget_message_kinds()→get_messages_filter_includes_edit_kindfails.Out of scope:
messages search, tag overlay from the edit event, and any desktop-side change.Coverage limitation
apply_editsandget_message_kindsare each pinned by tests, but nothing asserts thatcmd_get_messagesandcmd_get_threadactually callapply_edits— both areasyncand do network I/O, so there is no unit-testable seam. Unwiring both call sites is caught only bydead_codeunder-D warnings; unwiring one is not caught at all. Flagging it rather than adding a mock harness for two call sites.