Repository navigation
Show a placeholder for messages this version can't process, and retain them - #2232
Merged
Merged
Conversation
…n them Messages the client positively identifies as unprocessable are now kept instead of dropped. Random decryption failures still produce nothing. - One-to-one data starting 0x00 is a newer wire format. It's retained without decrypting and raises an account-level "update" banner on Home, with no bubble, since its sender can't be known. - Decrypted content with a top-level field above 18 and nothing usable gets a placeholder bubble in an existing conversation (never a new one), incoming or outgoing for our own syncs and group messages. Previously it was rejected as an invalid message. - Raw swarm data is kept in `unsupported_message` (same schema on all clients, for the future 2.0 import), capped at 256 MB and expired with disappearing settings. An mms delete trigger keeps it in step with placeholder deletion. - Retained messages are replayed at startup after an update, replacing placeholders in place. The bubble and banner strings are hard-coded English and need adding to Crowdin.
- Push metadata `t` is already milliseconds; stop converting it, and pass the swarm expiry `z` through as the server expiry on both push paths. - No placeholder in a hidden conversation; the record is still retained and the conversation stays hidden. - Add `sender` and `sent_timestamp_ms` to `unsupported_message`, set for unknown types and NULL for the newer format. - An unsend request deletes retained records with the same sender and sent timestamp. - A failed reprocess keeps the record and stamps the version. The placeholder is detached before it's deleted, so a failed replay leaves the record in place without one. - Enforce the retention limits and reprocess on launch and on returning to the foreground; limit failures are caught and logged.
- Add unsupported_message_stats (seeded single row), kept exact by insert/delete/update triggers, and the unsupported_message_kind_id index - Count each row as length(data) + 256 against the 256 MB budget, evicting oldest newerFormat rows first in batches of up to 100 - Cap newerFormat rows at 10,000, evicting the oldest - Check the caps from the stats row after each insert, with no table scan; scheduled maintenance still removes expired rows first - Stamp newerFormat rows in one UPDATE and replay unknownType rows in pages of 50, choosing by stored kind rather than data bytes - Name the protobuf wire types in the field scan
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.
Contributor checklist
Description
Shows a placeholder for messages this client positively identifies as something it can't process, and retains the raw data so a newer version (or the future Session 2.0 database import) can process it. Matching changes: iOS session-foundation/session-ios#808, Desktop session-foundation/session-desktop#2025.
The distinction is the feature: only messages we positively identify get anything. A message that simply fails to decrypt still produces nothing, because it can't be attributed to anyone (spam, corruption or an attacker), and a bubble claims someone really sent you something.
What's detected
0x00. v1 data is protobuf, which can never start with a zero byte. It's checked before decryption, in the one-to-one namespace only. Its sender is inside the encryption and the prefix is unauthenticated, so it gets no bubble, only the banner, and its bytes are retained invisibly.Contentholds a top-level field numbered above 18 and nothing this client can use. Every number up to 18 has been assigned at some point, including 2.0'smsgId = 18. The same hand-written tag scan as the other clients runs over the decrypted bytes. Previously such content was rejected as an invalid message, because the "unknown message type" branch couldn't be reached. One-to-one and groups v2 only; communities are excluded.What the user sees
dataMessage.syncTarget) and in groups. It's only added to a conversation that already exists and is visible: never a new conversation or message request, and it never un-hides one. Placeholders only offer "delete for me". An incoming placeholder notifies with the generic "new message" text.?colorAccent) with black text at the top of Home, with a ✕ to dismiss. It's raised by a newer-format message ("Some messages can't be shown on this device…") or by an unknown type from our own other device that can't be placed ("One of your other devices is using a newer version…"). After dismissal it reappears only for a trigger at least 7 days later.Storage and replay
unsupported_message, migrationlokiV62(83). Columns are identical across iOS, Android and Desktop so the future import reads one shape.senderandsent_timestamp_msare stored for unknown types.AFTER DELETE ON mmstrigger removes a row with its placeholder, andmarkAsDeletedremoves it explicitly. Push-delivered rows now use the push's millisecond timestamp and its swarm expiry (z).Needs doing before merge
FIXME).Testing
testPlayDebugUnitTest409/409, including the new ones covering the tag scan, detection, placement, banner state, budget and expiry, deletion via the trigger, the unsend delete, and a detached row surviving placeholder deletion.assemblePlayDebugpasses.api.foojay.ioreturns 400).