Skip to content

Added privacy check to ensure the reader's sendReadReceipts setting i… - #417

Merged
codebestia merged 3 commits into
codebestia:mainfrom
johdanike:fix/read-receipts-privacy-cursor
Jul 30, 2026
Merged

Added privacy check to ensure the reader's sendReadReceipts setting i…#417
codebestia merged 3 commits into
codebestia:mainfrom
johdanike:fix/read-receipts-privacy-cursor

Conversation

@johdanike

@johdanike johdanike commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR resolves #339 by addressing three critical gaps in the message_read handler. Previously, read receipts were broadcasted unconditionally (ignoring user privacy settings), the read cursor could be accidentally rolled back by stale network requests, and per-device read states were completely ignored. This update secures the read receipt pipeline to be privacy-respecting, strictly monotonic, and device-accurate.

Changes Made

  • Privacy Check: The handler now queries the reading user's sendReadReceipts preference. If disabled, the local state is updated but the broadcast event is safely suppressed.
  • Monotonic Cursor Guard: conversationMembers.lastReadMessageId is now guarded. The update evaluates whether the incoming message ID is actually newer than the current cursor; if it is an older/stale ID, the update is treated as a no-op and rejected safely.
  • Per-Device readAt Stamping: The handler now correctly writes the timestamp to the readAt column in messageEnvelopes for the reading device's own envelope rows, accurately capturing per-device consumption up to the read point.
  • Testing: Added new test suites covering the privacy flag suppression, the rejection of backwards cursor updates, and the successful database persistence of the readAt field.

Acceptance Criteria Met

  • message_read checks the reading user's sendReadReceipts setting before broadcasting.
  • lastReadMessageId only ever advances — backwards updates are rejected/no-op'd.
  • messageEnvelopes.readAt is stamped for the reading device's own envelope rows up to the read point.
  • Tests cover: privacy-disabled suppresses broadcast, backwards update rejected, readAt persisted per envelope.

Closes #339

- Updated the conversation list handler to map preview messages through serializeConversation.
- Applied serializeMessage to ensure the preview shape matches the GET /:id response.
- Prevented the accidental leakage of plaintext content fields in the raw conversation object.
- Added explicit tests asserting the list response contains no plaintext fields.
- Verified in tests that the preview message perfectly matches the standard ciphertext-safe shape.

Closes codebestia#338
- Added privacy check to ensure the reader's sendReadReceipts setting is true before broadcasting.
- Implemented a monotonic cursor guard to ensure lastReadMessageId only ever advances forward.
- Updated the handler to stamp messageEnvelopes.readAt for the reader's device envelopes.
- Ignored backwards cursor updates to prevent stale read receipts from regressing state.
- Added comprehensive tests covering the privacy toggle, backwards rejection, and readAt persistence.

Closes codebestia#339
@johdanike
johdanike force-pushed the fix/read-receipts-privacy-cursor branch from 1bc7195 to 721c30b Compare July 29, 2026 13:58
@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@johdanike Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@codebestia
codebestia merged commit c4653bf into codebestia:main Jul 30, 2026
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.

Read receipts: privacy check, monotonic cursor guard, per-device readAt

2 participants