Skip to content

fix(concord): an already-expired v2 message is refused at ingest - #94

Merged
JSKitty merged 1 commit into
VectorPrivacy:widescreenfrom
TheSeydiCharyyev:fix/v2-expired-ingest
Oct 2, 2026
Merged

JSKitty merged 1 commit into
VectorPrivacy:widescreenfrom
TheSeydiCharyyev:fix/v2-expired-ingest

Conversation

@TheSeydiCharyyev

Copy link
Copy Markdown

An already-expired message in a Concord v2 channel is no longer saved or passed to on_community_message. Closes #93.

Change

  • apply_chat_to_state, Message arm: return None when the rumor's NIP-40 expiration is already in the past. CORD-08 §3: "MUST refuse an already-expired rumor at ingest — never store it".
  • rumor::already_expired is now pub(crate), so v2 uses the same check as the DM path.

Test

an_already_expired_message_is_refused_at_ingest in community/v2/inbound.rs:

  • A rumor that expired in 2001, in a wrap without the outer expiration tag (what a member who re-wraps the seal can send).
  • persist_chat_event returns None. The event is not in the DB and not in STATE.
  • A message with a future expiry still persists as New.

Without the fix, the test fails on the None check.

Verified at 9525cf5a8ae6 + this commit, on Windows:

  • cd crates && cargo test -p vector-core: 1999 passed, 0 failed, plus the integration and doc tests.
  • cargo test -p vector-core --lib -- --ignored guarded_key: 7 passed, 0 failed.

Not covered

  • Reactions and edits that carry their own expired tag are still applied. CORD-08 §2 asks senders to tag them too, but Vector tags only messages. I can extend the check if you want it.
  • SDK and CLI hosts still do not run the sweeper (self_destruct::start_sweeper has no caller). That is a separate change.

Own sends

publish_chat writes the local echo through the same function. If the expiry passes during the publish, a headless sender (SDK) does not store its own copy. The app keeps its copy, because TauriSendCallback::on_persist saves the sent row.

Base branch

widescreen, where current work lands. The Message arm is the same on master.

CORD-08 §3 says a reader must refuse an already-expired rumor at
ingest and never store it. The DM path already drops it in rumor.rs.
The v2 Message arm now uses the same already_expired check.

The wrap's expiration tag is for relays only; readers judge by the
rumor's copy (CORD-08 §2). A wrap re-published without the outer tag
still reaches apply_chat_to_state.

Closes VectorPrivacy#93
@JSKitty JSKitty added the bug Something isn't working label Oct 2, 2026

@JSKitty JSKitty left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate the PR! This was a great catch, I'll additionally cover events such as Edits/Reactions/etc in a follow up commit, you will be included in the Release Notes for our next v0.5.0 release. 🙏 💚

@JSKitty
JSKitty merged commit 05dc1da into VectorPrivacy:widescreen Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants