Fix OPK loss on SPK-grace retry, deletion sync, add keys_updated push
- 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>
This commit is contained in:
15
server.py
15
server.py
@@ -842,6 +842,10 @@ async def handle_login_finish(msg: dict, writer: ProtocolWriter, state: dict) ->
|
||||
"ip": addr,
|
||||
"added_at": datetime.now(timezone.utc).isoformat(),
|
||||
}, exclude_writer=writer)
|
||||
# Contacts must refetch key bundles to include the new device
|
||||
if contacts:
|
||||
await _notify_users(contacts, "keys_updated", {"user_id": user_id},
|
||||
exclude_writer=writer)
|
||||
|
||||
return {"user_id": user_id, "username": user["username"], "email": user["email"],
|
||||
"device_id": device_id}
|
||||
@@ -1060,6 +1064,13 @@ async def handle_ensure_prekeys(msg: dict, session: dict, writer: ProtocolWriter
|
||||
{"count": count, "spk_created_at": spk_created_at,
|
||||
"uploaded_spk": uploaded_spk, "uploaded_otps": uploaded_otps})
|
||||
|
||||
# SPK change invalidates key bundles cached by other clients
|
||||
if uploaded_spk:
|
||||
contacts = await adb.get_user_contacts(user_id)
|
||||
if contacts:
|
||||
await _notify_users(contacts, "keys_updated", {"user_id": user_id},
|
||||
exclude_writer=writer)
|
||||
|
||||
|
||||
async def handle_rotate_keys(msg: dict, session: dict, writer: ProtocolWriter):
|
||||
if await _is_rate_limited(f"rotate_keys|{session['user_id']}", 3):
|
||||
@@ -2478,6 +2489,10 @@ async def handle_download_stream(msg: dict, session: dict, writer: ProtocolWrite
|
||||
so the client can reassemble chunks in order even if delivery is reordered.
|
||||
"""
|
||||
file_id = msg.get("file_id", "")
|
||||
if await _is_rate_limited(f"download_stream|{session['user_id']}", 30):
|
||||
await send_resp(msg, writer, "download_stream", "error",
|
||||
{"message": "Too many requests. Try later."})
|
||||
return
|
||||
result = await _validate_download(msg, session, writer, "download_stream")
|
||||
if not result:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user