mirror of
https://github.com/chatmail/core.git
synced 2026-10-02 11:10:25 +03:00
feat: introduce keyupdate messages informing contacts about relay changes
When the published relay list changes, key-contacts are informed with an unsigned message carrying the re-signed key, encrypted to a chunk of contacts at a time. It is shaped like a receipt notification naming no message, so that cores which know nothing about keyupdates trash it as well. See the src/keyupdate.rs module docs for the design.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -86,3 +87,46 @@ def test_second_device(acf, alice_and_remote_bob) -> None:
|
||||
remote_eval("locals()['future']()")
|
||||
|
||||
assert new_account.get_config("addr") == remote_eval("bob.get_config('addr')")
|
||||
|
||||
|
||||
def test_keyupdate_against_core_2_48_march_2026(acf, alice_and_remote_bob):
|
||||
"""Test 2.48 Bob learns a new relay of Alice from a keyupdate, and is shown nothing."""
|
||||
alice, alice_contact_bob, remote_eval = alice_and_remote_bob("2.48.0")
|
||||
|
||||
def bob_sees():
|
||||
return remote_eval(
|
||||
"{'chats': len(bob.get_chatlist()),"
|
||||
" 'fresh': len(bob._rpc.get_fresh_msgs(bob.id)),"
|
||||
" 'contacts': len(bob.get_contacts()),"
|
||||
" 'alice_chat': bob._rpc.get_chat_id_by_contact_id(bob.id, bob_contact_alice.id) or 0}",
|
||||
)
|
||||
|
||||
# Keyupdates go to contacts who plausibly hold our key:
|
||||
# an accepted chat alone is not enough, a message must have flowed.
|
||||
alice_chat = alice_contact_bob.create_chat()
|
||||
alice.set_config("keyupdate_debounce", "1")
|
||||
old_addr = alice.get_config("configured_addr")
|
||||
alice_chat.send_text("hi")
|
||||
assert remote_eval("bob.wait_for_incoming_msg().get_snapshot().text") == "hi"
|
||||
before = bob_sees()
|
||||
|
||||
# Certificate merging keeps the newest direct key signature,
|
||||
# and signature timestamps have one-second resolution:
|
||||
# without waiting, the re-signed key can tie with the copy Bob holds, keeping his.
|
||||
time.sleep(2)
|
||||
alice.add_transport_from_qr(acf.get_account_qr())
|
||||
alice.bring_online()
|
||||
(new_addr,) = [t["addr"] for t in alice.list_transports() if t["addr"] != old_addr]
|
||||
|
||||
# The 2.48 core has no encryption enforcement, but the keyupdate MDN without
|
||||
# referenced message keeps it invisible; merging happens before the trashing.
|
||||
for _ in range(60):
|
||||
if new_addr in remote_eval("bob_contact_alice.get_encryption_info()"):
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
pytest.fail("Bob never received the keyupdate")
|
||||
|
||||
# It also leaves no trace: no chat with Alice, no message anywhere,
|
||||
# and no address-contact for the address it was sent from.
|
||||
assert bob_sees() == before
|
||||
|
||||
Reference in New Issue
Block a user