When authorizing a new device, include the TOFU registry
(known_identity_keys) and manual verifications (verified_contacts) in
the encrypted pairing payload, so a contact verified on the existing
device stays verified on the newly paired one. Previously these stores
are device-local and started empty on the new device, dropping verified
status. Fields are optional and ignored by older clients; symmetric with
the iOS client.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Adopt a new X3DH session (install into self.sessions + persist) only
after the first message decrypts successfully. Previously
_process_x3dh_header saved the candidate session immediately, so a
replayed/forged X3DH header permanently overwrote a working ratchet.
- Advance the incremental-sync watermark (__last_server_ts) only across
the prefix of messages settled in the cache. An undecryptable message
(e.g. sender key not yet received) is re-fetched and retried up to
_MAX_DECRYPT_RETRIES=3 times instead of being silently lost forever.
Watermark is no longer touched on offset>0 pages and never regresses.
- Fix NameError in the proof-of-work registration path (logger ->
self._logger) and run _solve_pow in an executor so it does not block
the event loop.
- Persist the rotated RSA login key only after the server confirmed
rotate_keys; writing private.pem first bricked the account when the
request failed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- chat_core: defer one-time-prekey deletion until the first message
decrypts successfully; deleting it on load made the SPK grace-period
retry derive a wrong shared secret and lose the message permanently
- chat_core: fix get_deleted_since params (since -> since_ts) and
response field (message_ids -> deleted_ids) so incremental deletion
sync actually works
- chat_core: route keys_updated pushes into the notification queue
- server: notify contacts with keys_updated when a user uploads a new
SPK or logs in with a new device, so clients invalidate cached key
bundles instead of waiting for the TTL
- server: rate-limit download_stream like other heavy handlers
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>