From d7ada8affa08bf2de217d598d050d2a04ab77f87 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Fri, 14 Nov 2025 14:10:17 +0100 Subject: [PATCH 1/2] fix: Correct ordering of securejoin messages --- src/securejoin/bob.rs | 22 +++++++++++-------- .../golden/test_broadcast_joining_golden_bob | 2 +- test-data/golden/test_sync_broadcast_bob | 2 +- test-data/golden/two_group_securejoins | 4 ++-- .../golden/verified_chats_editor_reordering | 4 ++-- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/securejoin/bob.rs b/src/securejoin/bob.rs index 123dc212cd..45224fd826 100644 --- a/src/securejoin/bob.rs +++ b/src/securejoin/bob.rs @@ -123,20 +123,23 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul } } + let timestamp = smeared_time(context); match invite { QrInvite::Group { .. } => { - let joining_chat_id = joining_chat_id(context, &invite, private_chat_id).await?; + let joining_chat_id = + joining_chat_id(context, &invite, private_chat_id, timestamp).await?; let msg = stock_str::secure_join_started(context, invite.contact_id()).await; - chat::add_info_msg(context, joining_chat_id, &msg, time()).await?; + chat::add_info_msg(context, joining_chat_id, &msg, timestamp).await?; Ok(joining_chat_id) } QrInvite::Broadcast { .. } => { - let joining_chat_id = joining_chat_id(context, &invite, private_chat_id).await?; + let joining_chat_id = + joining_chat_id(context, &invite, private_chat_id, timestamp).await?; // We created the broadcast channel already, now we need to add Alice to it. if !is_contact_in_chat(context, joining_chat_id, invite.contact_id()).await? { chat::add_to_chat_contacts_table( context, - time(), + timestamp, joining_chat_id, &[invite.contact_id()], ) @@ -148,7 +151,7 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul // use the generic `Establishing guaranteed end-to-end encryption, please wait…` if !is_contact_in_chat(context, joining_chat_id, ContactId::SELF).await? { let msg = stock_str::securejoin_wait(context).await; - chat::add_info_msg(context, joining_chat_id, &msg, time()).await?; + chat::add_info_msg(context, joining_chat_id, &msg, timestamp).await?; } Ok(joining_chat_id) } @@ -162,14 +165,13 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul let ts_sort = private_chat_id .calc_sort_timestamp(context, 0, sort_to_bottom, received, incoming) .await?; - let ts_start = time(); chat::add_info_msg_with_cmd( context, private_chat_id, &stock_str::securejoin_wait(context).await, SystemMessage::SecurejoinWait, ts_sort, - Some(ts_start), + Some(timestamp), None, None, None, @@ -242,7 +244,8 @@ pub(super) async fn handle_auth_required( // so only show it when joining a group and not for a 1:1 chat or broadcast channel. let contact_id = invite.contact_id(); let msg = stock_str::secure_join_replies(context, contact_id).await; - let chat_id = joining_chat_id(context, &invite, chat_id).await?; + let timestamp = message.timestamp_sent; + let chat_id = joining_chat_id(context, &invite, chat_id, timestamp).await?; chat::add_info_msg(context, chat_id, &msg, time()).await?; } } @@ -368,6 +371,7 @@ async fn joining_chat_id( context: &Context, invite: &QrInvite, alice_chat_id: ChatId, + timestamp: i64, ) -> Result { match invite { QrInvite::Contact { .. } => Ok(alice_chat_id), @@ -391,7 +395,7 @@ async fn joining_chat_id( name, Blocked::Not, None, - smeared_time(context), + timestamp, ) .await? } diff --git a/test-data/golden/test_broadcast_joining_golden_bob b/test-data/golden/test_broadcast_joining_golden_bob index 45e7611955..99204487a0 100644 --- a/test-data/golden/test_broadcast_joining_golden_bob +++ b/test-data/golden/test_broadcast_joining_golden_bob @@ -1,6 +1,6 @@ InBroadcast#Chat#2002: My Channel [2 member(s)] Icon: e9b6c7a78aa2e4f415644f55a553e73.png -------------------------------------------------------------------------------- -Msg#2004: info (Contact#Contact#Info): Establishing guaranteed end-to-end encryption, please wait… [NOTICED][INFO] Msg#2003: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] +Msg#2004: info (Contact#Contact#Info): Establishing guaranteed end-to-end encryption, please wait… [NOTICED][INFO] Msg#2007🔒: (Contact#Contact#2001): You joined the channel. [FRESH][INFO] -------------------------------------------------------------------------------- diff --git a/test-data/golden/test_sync_broadcast_bob b/test-data/golden/test_sync_broadcast_bob index ce0c2b1dc3..6085d765b0 100644 --- a/test-data/golden/test_sync_broadcast_bob +++ b/test-data/golden/test_sync_broadcast_bob @@ -1,7 +1,7 @@ InBroadcast#Chat#2002: Channel [1 member(s)] -------------------------------------------------------------------------------- -Msg#2004: info (Contact#Contact#Info): Establishing guaranteed end-to-end encryption, please wait… [NOTICED][INFO] Msg#2003: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] +Msg#2004: info (Contact#Contact#Info): Establishing guaranteed end-to-end encryption, please wait… [NOTICED][INFO] Msg#2008🔒: (Contact#Contact#2001): You joined the channel. [FRESH][INFO] Msg#2010🔒: (Contact#Contact#2001): hi [FRESH] Msg#2011🔒: (Contact#Contact#2001): Member Me removed by alice@example.org. [FRESH][INFO] diff --git a/test-data/golden/two_group_securejoins b/test-data/golden/two_group_securejoins index 5e20c36b6c..d79e67c3c3 100644 --- a/test-data/golden/two_group_securejoins +++ b/test-data/golden/two_group_securejoins @@ -1,9 +1,9 @@ Group#Chat#6002: Group [3 member(s)] -------------------------------------------------------------------------------- +Msg#6006: info (Contact#Contact#Info): alice@example.org replied, waiting for being added to the group… [NOTICED][INFO] +Msg#6003: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] Msg#6004: info (Contact#Contact#Info): alice@example.org invited you to join this group. Waiting for the device of alice@example.org to reply… [NOTICED][INFO] -Msg#6006: info (Contact#Contact#Info): alice@example.org replied, waiting for being added to the group… [NOTICED][INFO] -Msg#6003: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] Msg#6008🔒: (Contact#Contact#6001): Member Me added by alice@example.org. [FRESH][INFO] -------------------------------------------------------------------------------- diff --git a/test-data/golden/verified_chats_editor_reordering b/test-data/golden/verified_chats_editor_reordering index 3bf488c00c..cf8638562d 100644 --- a/test-data/golden/verified_chats_editor_reordering +++ b/test-data/golden/verified_chats_editor_reordering @@ -1,10 +1,10 @@ Group#Chat#3002: Group [3 member(s)] -------------------------------------------------------------------------------- +Msg#3006: info (Contact#Contact#Info): alice@example.org replied, waiting for being added to the group… [NOTICED][INFO] +Msg#3003: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] Msg#3004: info (Contact#Contact#Info): alice@example.org invited you to join this group. Waiting for the device of alice@example.org to reply… [NOTICED][INFO] -Msg#3006: info (Contact#Contact#Info): alice@example.org replied, waiting for being added to the group… [NOTICED][INFO] -Msg#3003: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] Msg#3008🔒: (Contact#Contact#3002): [FRESH] Msg#3009: info (Contact#Contact#Info): Member bob@example.net added. [NOTICED][INFO] Msg#3010🔒: (Contact#Contact#3001): Member Me added by alice@example.org. [FRESH][INFO] From c64e4c7f8c3d67143f4c24f7ea78894989fefdee Mon Sep 17 00:00:00 2001 From: Hocuri Date: Fri, 14 Nov 2025 14:32:34 +0100 Subject: [PATCH 2/2] fix the remaining case --- src/securejoin/bob.rs | 7 +++---- test-data/golden/two_group_securejoins | 2 +- test-data/golden/verified_chats_editor_reordering | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/securejoin/bob.rs b/src/securejoin/bob.rs index 45224fd826..32a2993109 100644 --- a/src/securejoin/bob.rs +++ b/src/securejoin/bob.rs @@ -158,8 +158,7 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul QrInvite::Contact { .. } => { // For setup-contact the BobState already ensured the 1:1 chat exists because it // uses it to send the handshake messages. - // Calculate the sort timestamp before checking the chat protection status so that if we - // race with its change, we don't add our message below the protection message. + // Use calc_sort_timestamp() to make sure that the new message is the last message in the chat. let sort_to_bottom = true; let (received, incoming) = (false, false); let ts_sort = private_chat_id @@ -244,9 +243,9 @@ pub(super) async fn handle_auth_required( // so only show it when joining a group and not for a 1:1 chat or broadcast channel. let contact_id = invite.contact_id(); let msg = stock_str::secure_join_replies(context, contact_id).await; - let timestamp = message.timestamp_sent; + let timestamp = smeared_time(context); let chat_id = joining_chat_id(context, &invite, chat_id, timestamp).await?; - chat::add_info_msg(context, chat_id, &msg, time()).await?; + chat::add_info_msg(context, chat_id, &msg, timestamp).await?; } } diff --git a/test-data/golden/two_group_securejoins b/test-data/golden/two_group_securejoins index d79e67c3c3..a7a5e627f4 100644 --- a/test-data/golden/two_group_securejoins +++ b/test-data/golden/two_group_securejoins @@ -1,9 +1,9 @@ Group#Chat#6002: Group [3 member(s)] -------------------------------------------------------------------------------- -Msg#6006: info (Contact#Contact#Info): alice@example.org replied, waiting for being added to the group… [NOTICED][INFO] Msg#6003: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] Msg#6004: info (Contact#Contact#Info): alice@example.org invited you to join this group. Waiting for the device of alice@example.org to reply… [NOTICED][INFO] +Msg#6006: info (Contact#Contact#Info): alice@example.org replied, waiting for being added to the group… [NOTICED][INFO] Msg#6008🔒: (Contact#Contact#6001): Member Me added by alice@example.org. [FRESH][INFO] -------------------------------------------------------------------------------- diff --git a/test-data/golden/verified_chats_editor_reordering b/test-data/golden/verified_chats_editor_reordering index cf8638562d..288ed10555 100644 --- a/test-data/golden/verified_chats_editor_reordering +++ b/test-data/golden/verified_chats_editor_reordering @@ -1,10 +1,10 @@ Group#Chat#3002: Group [3 member(s)] -------------------------------------------------------------------------------- -Msg#3006: info (Contact#Contact#Info): alice@example.org replied, waiting for being added to the group… [NOTICED][INFO] Msg#3003: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] Msg#3004: info (Contact#Contact#Info): alice@example.org invited you to join this group. Waiting for the device of alice@example.org to reply… [NOTICED][INFO] +Msg#3006: info (Contact#Contact#Info): alice@example.org replied, waiting for being added to the group… [NOTICED][INFO] Msg#3008🔒: (Contact#Contact#3002): [FRESH] Msg#3009: info (Contact#Contact#Info): Member bob@example.net added. [NOTICED][INFO] Msg#3010🔒: (Contact#Contact#3001): Member Me added by alice@example.org. [FRESH][INFO]