Repository navigation
Take the reporter's copy of an MLS message as a report (GRYT-1557) - #250
Merged
Merged
Conversation
The server never has an MLS message, so chat:report now takes
mls: { senderServerUserId, text } and stores it as an unverified report
(decision 11). The reporter and the sender both have to be in the
conversation, and it can't be your own message; otherwise it answers
"Message not found", like a DM that doesn't exist. Permission, the
already-reported check and the rate limit are the same as any report.
reports:list marks those cards unverified, and server:info.mls says
reports: true. The queue groups by conversation and message id, since
an MLS id is the sender's choice and could copy a real one, and
reports:resolve narrows to the conversation it's given. A delete only
deletes and broadcasts when the server has the message.
New column: reports.unverified, 0 on every existing row.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This was referenced Sep 28, 2026
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.
The server never has an MLS message, so
chat:reportcouldn't take a report of one. It looked the id up, found nothing, and answered "Message not found". Decision 11 says the reporter's app sends its decrypted copy, marked unverified. The desktop and the phone already send it (client#715, mobile#272), and they offer Report on an MLS message only onceserver:info.mls.reportsis true. This is the server half.What changes
chat:reporttakesmls: { senderServerUserId, text }. With it, the server doesn't look the message up. It stores the copy as a report withunverified = 1, no attachments, and the sender's current nickname.report_messages, the already-reported check and the rate limit, the same as any report. They run first, so a flood is refused before any lookuptextis at most 32,000 characters andmessageIdat most 64, the content format's own limits. Too long is refused, not cut, so a moderator never reads half a messagereports:listaddsunverified: trueto those cards, and only to those.server:info.mlsaddsreports: true.Behaviour that changes for normal reports too
reports:resolvenarrowsapproveanddeleteto the conversation the client names. Both apps already send it. Without it, it resolves by id like before.deleteonly deletes, and broadcastschat:deleted, when the server actually has the message. For an MLS copy there's nothing to delete. Before, the broadcast went to every socket on the server, which for an MLS copy would have named the DM to everybody. A normal message its author already deleted also gets no broadcast now. It had nothing to remove anyway.Review-required
src/db/**is review-required, and this touches three files there:connection.ts:ALTER TABLE reports ADD COLUMN unverified INTEGER NOT NULL DEFAULT 0, behind the usualhasColumncheck. Every existing row reads as verified, which is right, since each one was copied from the server's own message.reports.ts: writes and reads the column, and makes the grouping and resolve changes above.interfaces.ts:unverified: booleanonReportRecord.The parts I'm least sure about:
hasUserReportedMessagestill matches on message id alone. The only way to hit that is reporting your own collision, so I left it.Checked
yarn test(1,794 passing),yarn test:examples,yarn build,npx eslint .(no errors; the five warnings are in files this doesn't touch), and both check scripts.mlsReports.test.ts, new, runs against a real SQLite database:report_messagesis neededserverInfo.test.tsnow expectsreports: true.Docs: Gryt-chat/docs#150, which should merge after this one.
Closes GRYT-1557. Verifiable reports, where a moderator can check the signature, are GRYT-1568.
🤖 Generated with Claude Code