Transfer contact verification state during device pairing

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>
This commit is contained in:
Filip
2026-06-15 20:00:43 +02:00
parent 20f006cf5e
commit 6da7515d1e

View File

@@ -1568,6 +1568,23 @@ class ChatClient:
self._cache_key = derive_self_encryption_key(ed_priv) self._cache_key = derive_self_encryption_key(ed_priv)
self._local_key = derive_local_storage_key(ed_priv) self._local_key = derive_local_storage_key(ed_priv)
self._load_verification_stores() self._load_verification_stores()
# Import verification state transferred from the authorizing
# device (optional — absent when paired from an older client)
vc_raw = keys_data.get("verified_contacts")
if vc_raw:
try:
self._verified_contacts = json.loads(vc_raw)
_save_verified_contacts(email, self._verified_contacts, self._local_key)
except (json.JSONDecodeError, TypeError):
pass
kik_raw = keys_data.get("known_identity_keys")
if kik_raw:
try:
self._known_identity_keys = json.loads(kik_raw)
_save_known_identity_keys(email, self._known_identity_keys, self._local_key)
except (json.JSONDecodeError, TypeError):
pass
self._pairing_temp_private_key = None self._pairing_temp_private_key = None
self._pairing_fingerprint = "" self._pairing_fingerprint = ""
self._pairing_code = "" self._pairing_code = ""
@@ -1618,6 +1635,14 @@ class ChatClient:
"identity_private": serialize_ed25519_private_raw(self.identity_private).hex(), "identity_private": serialize_ed25519_private_raw(self.identity_private).hex(),
} }
# Carry the TOFU registry + manual verifications so a contact verified on
# this device stays verified on the new one (these stores are local and
# would otherwise start empty). Receivers ignore unknown fields.
if self._verified_contacts:
keys_data["verified_contacts"] = json.dumps(self._verified_contacts)
if self._known_identity_keys:
keys_data["known_identity_keys"] = json.dumps(self._known_identity_keys)
# Send keys to the new device first. Re-encrypting history can take a # Send keys to the new device first. Re-encrypting history can take a
# while on large accounts; doing it before pairing_send can make a valid # while on large accounts; doing it before pairing_send can make a valid
# code expire during authorization. # code expire during authorization.