The current message handling uses the double-ratchet's internal counter (wire.n) for decryption, but doesn't enforce message ordering:
-
Counter used for decryption only: The wire.n counter is passed to ratchet.decrypt() but:
- No check that messages arrive in increasing counter order
- Out-of-order delivery (possible on lossy networks/I2P) would silently decrypt out-of-order
-
Timestamp only for display: Messages use unix timestamp for display, NOT for ordering:
- Two messages sent at the same second could reorder in the UI
- Timestamp is added CLIENT-SIDE on receive, not sent by the peer
- If clock skew exists between peers, ordering appears wrong to each side
-
Frontend sorting: Messages in ChatWindow.tsx just render state.messages in array order. If the backend pushes out-of-order messages, they appear in wrong order.
Examples of failure:
- Peer A sends msg1 (counter=1), msg2 (counter=2)
- Network reorders: Peer B receives msg2, then msg1
- Backend pushes them in order received → UI shows msg2 before msg1
- Both peers think the other side is confused
Proposed solution:
- Add explicit sequence numbers to the message protocol
- Enforce or detect out-of-order delivery
- Buffer and reorder messages, or signal warning to user
- Consider adding sender-provided timestamps (encrypted in message) for consistency check
The current message handling uses the double-ratchet's internal counter (wire.n) for decryption, but doesn't enforce message ordering:
Counter used for decryption only: The
wire.ncounter is passed to ratchet.decrypt() but:Timestamp only for display: Messages use unix timestamp for display, NOT for ordering:
Frontend sorting: Messages in ChatWindow.tsx just render state.messages in array order. If the backend pushes out-of-order messages, they appear in wrong order.
Examples of failure:
Proposed solution: