From bda6cea0ce823807266fc68cd650528d7a776d73 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Mon, 9 Oct 2023 21:50:17 -0300 Subject: [PATCH] feat: Make gossip period configurable (#4346) This is needed to test periodic re-gossiping in existing chats. Also add a test for verified groups on that even if "member added" message is missed by a device of newly added member, after re-gossiping Autocrypt keys to the group it successfully learns these keys and marks other members as verified. --- deltachat-ffi/deltachat.h | 3 ++ python/tests/test_0_complex_or_slow.py | 67 ++++++++++++++++++++++++-- src/config.rs | 7 +++ src/context.rs | 5 +- src/mimefactory.rs | 5 +- 5 files changed, 81 insertions(+), 6 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 3c3beb448..4c235adf3 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -503,6 +503,9 @@ char* dc_get_blobdir (const dc_context_t* context); * to not mess up with non-delivery-reports or read-receipts. * 0=no limit (default). * Changes affect future messages only. + * - `gossip_period` = How often to gossip Autocrypt keys in chats with multiple recipients, in + * seconds. 2 days by default. + * This is not supposed to be changed by UIs and only used for testing. * - `ui.*` = All keys prefixed by `ui.` can be used by the user-interfaces for system-specific purposes. * The prefix should be followed by the system and maybe subsystem, * e.g. `ui.desktop.foo`, `ui.desktop.linux.bar`, `ui.android.foo`, `ui.dc40.bar`, `ui.bot.simplebot.baz`. diff --git a/python/tests/test_0_complex_or_slow.py b/python/tests/test_0_complex_or_slow.py index 0f2000034..857e1645d 100644 --- a/python/tests/test_0_complex_or_slow.py +++ b/python/tests/test_0_complex_or_slow.py @@ -539,8 +539,6 @@ def test_see_new_verified_member_after_going_online(acfactory, tmp_path, lp): assert msg_in.text == msg_out.text assert msg_in.get_sender_contact().addr == ac2_addr - ac1.set_config("bcc_self", "0") - def test_use_new_verified_group_after_going_online(acfactory, tmp_path, lp): """Another test for the bug #3836: @@ -589,4 +587,67 @@ def test_use_new_verified_group_after_going_online(acfactory, tmp_path, lp): assert msg_in.get_sender_contact().addr == ac2.get_config("addr") assert msg_in.text == msg_out.text - ac2.set_config("bcc_self", "0") + +def test_verified_group_vs_delete_server_after(acfactory, tmp_path, lp): + """Test for the issue #4346: + - User is added to a verified group. + - First device of the user downloads "member added" from the group. + - First device removes "member added" from the server. + - Some new messages are sent to the group. + - Second device comes online, receives these new messages. The result is a verified group with unverified members. + - First device re-gossips Autocrypt keys to the group. + - Now the seconds device has all members verified. + """ + ac1, ac2 = acfactory.get_online_accounts(2) + ac2_offl = acfactory.new_online_configuring_account(cloned_from=ac2) + for ac in [ac2, ac2_offl]: + ac.set_config("bcc_self", "1") + ac2.set_config("delete_server_after", "1") + ac2.set_config("gossip_period", "0") # Re-gossip in every message + acfactory.bring_accounts_online() + dir = tmp_path / "exportdir" + dir.mkdir() + ac2.export_self_keys(str(dir)) + ac2_offl.import_self_keys(str(dir)) + ac2_offl.stop_io() + + lp.sec("ac1: create verified-group QR, ac2 scans and joins") + chat1 = ac1.create_group_chat("hello", verified=True) + assert chat1.is_protected() + qr = chat1.get_join_qr() + lp.sec("ac2: start QR-code based join-group protocol") + chat2 = ac2.qr_join_chat(qr) + ac1._evtracker.wait_securejoin_inviter_progress(1000) + # Wait for "Member Me () added by ." message. + msg_in = ac2._evtracker.wait_next_incoming_message() + assert msg_in.is_system_message() + + lp.sec("ac2: waiting for 'member added' to be deleted on the server") + ac2._evtracker.get_matching("DC_EVENT_IMAP_MESSAGE_DELETED") + + lp.sec("ac1: sending 'hi' to the group") + ac2.set_config("delete_server_after", "0") + chat1.send_text("hi") + + lp.sec("ac2_offl: going online, checking the 'hi' message") + ac2_offl.start_io() + msg_in = ac2_offl._evtracker.wait_next_incoming_message() + assert not msg_in.is_system_message() + assert msg_in.text.startswith("[Sender of this message is not verified:") + ac2_offl_ac1_contact = msg_in.get_sender_contact() + assert ac2_offl_ac1_contact.addr == ac1.get_config("addr") + assert not ac2_offl_ac1_contact.is_verified() + chat2_offl = msg_in.chat + assert chat2_offl.is_protected() + + lp.sec("ac2: sending message re-gossiping Autocrypt keys") + chat2.send_text("hi2") + + lp.sec("ac2_offl: receiving message") + ev = ac2_offl._evtracker.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED") + msg_in = ac2_offl.get_message_by_id(ev.data2) + assert not msg_in.is_system_message() + assert msg_in.text == "hi2" + assert msg_in.chat == chat2_offl + assert msg_in.get_sender_contact().addr == ac2.get_config("addr") + assert ac2_offl_ac1_contact.is_verified() diff --git a/src/config.rs b/src/config.rs index 2d1a74ae3..a5704dd83 100644 --- a/src/config.rs +++ b/src/config.rs @@ -318,6 +318,13 @@ pub enum Config { /// Last message processed by the bot. LastMsgId, + + /// How often to gossip Autocrypt keys in chats with multiple recipients, in seconds. 2 days by + /// default. + /// + /// This is not supposed to be changed by UIs and only used for testing. + #[strum(props(default = "172800"))] + GossipPeriod, } impl Context { diff --git a/src/context.rs b/src/context.rs index fa6214965..210eddc0d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -754,7 +754,6 @@ impl Context { .await? .to_string(), ); - res.insert( "debug_logging", self.get_config_int(Config::DebugLogging).await?.to_string(), @@ -763,6 +762,10 @@ impl Context { "last_msg_id", self.get_config_int(Config::LastMsgId).await?.to_string(), ); + res.insert( + "gossip_period", + self.get_config_int(Config::GossipPeriod).await?.to_string(), + ); let elapsed = self.creation_time.elapsed(); res.insert("uptime", duration_to_str(elapsed.unwrap_or_default())); diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 8e3243ff4..2b37977c1 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -359,9 +359,10 @@ impl<'a> MimeFactory<'a> { async fn should_do_gossip(&self, context: &Context) -> Result { match &self.loaded { Loaded::Message { chat } => { - // beside key- and member-changes, force re-gossip every 48 hours + // beside key- and member-changes, force a periodic re-gossip. let gossiped_timestamp = chat.id.get_gossiped_timestamp(context).await?; - if time() > gossiped_timestamp + (2 * 24 * 60 * 60) { + let gossip_period = context.get_config_i64(Config::GossipPeriod).await?; + if time() >= gossiped_timestamp + gossip_period { Ok(true) } else { let cmd = self.msg.param.get_cmd();