From 51276e932056d728d227893426710d5fb96a3d06 Mon Sep 17 00:00:00 2001 From: Septias Date: Sat, 2 Nov 2024 09:53:02 +0100 Subject: [PATCH] add alias handling Revert "add alias handling" This reverts commit 5f7ca4ff9afcd02feff74601a5412bcd4a07b211. add alias handling add test improvements only do it for single chats comment out test clippy improve test remove unused function revert change to stockstr don't take mut refs fixes simplify move outwards --- src/chat.rs | 58 +++++++++++++++++++++++++++ src/contact.rs | 8 +++- src/receive_imf.rs | 98 +++++++++++++++++++++++++--------------------- 3 files changed, 119 insertions(+), 45 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index e33a7d7a5..2fb20634d 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -4711,6 +4711,7 @@ impl Context { #[cfg(test)] mod tests { use super::*; + use crate::chat; use crate::chatlist::get_archived_cnt; use crate::constants::{DC_GCL_ARCHIVED_ONLY, DC_GCL_NO_SPECIALS}; use crate::headerdef::HeaderDef; @@ -7696,4 +7697,61 @@ mod tests { Ok(()) } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_reply_with_alias() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + + // Alice sends a message to Bob + let alice_bob_chat = alice.create_chat(&bob).await; + let alice_msg = alice.send_text(alice_bob_chat.id, "Hello Bob!").await; + let msg = alice_msg.load_from_db().await; + bob.recv_msg(&alice_msg).await; + + // Bob replies using an alias email address + let alias_email = "bob.alias@example.org"; + let reply_imf = format!( + "From: Bob Alias <{}>\r\n\ + To: {}\r\n\ + In-Reply-To: <{}>\r\n\ + Message-ID: \r\n\ + \r\n\ + Hi Alice, this is Bob's alias.", + alias_email, + alice.get_primary_self_addr().await?, + msg.rfc724_mid + ); + + // Alice receives the raw message + let received = receive_imf(&alice, reply_imf.as_bytes(), false) + .await? + .unwrap(); + + // The message should appear in the existing 1:1 chat between Alice and Bob + assert_eq!(received.chat_id, alice_bob_chat.id); + + let msg = Message::load_from_db(&alice, received.msg_ids[0]).await?; + assert_eq!(msg.text, "Hi Alice, this is Bob's alias."); + + // Alias is displayed in chat + assert_eq!( + msg.param.get(Param::OverrideSenderDisplayname).unwrap(), + "Bob Alias" + ); + + // Chat remains 1:1 + let contacts = chat::get_chat_contacts(&alice, alice_bob_chat.id) + .await + .unwrap(); + assert_eq!(contacts, vec![ContactId::new(10)]); + + // Following messages still go to 1:1 chat + let sent = alice.send_text(alice_bob_chat.id, "Hello again!").await; + let msg = Message::load_from_db(&alice, sent.sender_msg_id).await?; + assert_eq!(msg.chat_id, alice_bob_chat.id); + + Ok(()) + } } diff --git a/src/contact.rs b/src/contact.rs index 1fa2bea6b..ed8dde353 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -3239,7 +3239,13 @@ Until the false-positive is fixed: "bob@example.net sent a message from another device." ); - let msg = tcm.send_recv(alice, bob, "Unencrypted").await; + let msg = tcm + .send_recv( + alice, + bob, + "[This message is not encrypted. See 'Info' for more details]", + ) + .await; assert_eq!(msg.get_showpadlock(), false); Ok(()) diff --git a/src/receive_imf.rs b/src/receive_imf.rs index e7fdb81c3..f778aa396 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -842,6 +842,7 @@ async fn add_parts( } } + // Lookup or create adhoc group chat. if chat_id.is_none() { if let Some((new_chat_id, new_chat_id_blocked)) = lookup_chat_or_create_adhoc_group( context, @@ -966,52 +967,55 @@ async fn add_parts( ); } } + } + } - // Check if the message was sent with verified encryption and set the protection of - // the 1:1 chat accordingly. - let chat = match is_partial_download.is_none() - && mime_parser.get_header(HeaderDef::SecureJoin).is_none() - && !is_mdn - { - true => Some(Chat::load_from_db(context, chat_id).await?) - .filter(|chat| chat.typ == Chattype::Single), - false => None, + if let Some(chat_id) = chat_id { + let contact = Contact::get_by_id(context, from_id).await?; + // Check if the message was sent with verified encryption and set the protection of + // the 1:1 chat accordingly. + let chat = match is_partial_download.is_none() + && mime_parser.get_header(HeaderDef::SecureJoin).is_none() + && !is_mdn + { + true => Some(Chat::load_from_db(context, chat_id).await?) + .filter(|chat| chat.typ == Chattype::Single), + false => None, + }; + if let Some(chat) = chat { + debug_assert!(chat.typ == Chattype::Single); + let mut new_protection = match verified_encryption { + VerifiedEncryption::Verified => ProtectionStatus::Protected, + VerifiedEncryption::NotVerified(_) => ProtectionStatus::Unprotected, }; - if let Some(chat) = chat { - debug_assert!(chat.typ == Chattype::Single); - let mut new_protection = match verified_encryption { - VerifiedEncryption::Verified => ProtectionStatus::Protected, - VerifiedEncryption::NotVerified(_) => ProtectionStatus::Unprotected, - }; - if chat.protected != ProtectionStatus::Unprotected - && new_protection == ProtectionStatus::Unprotected - // `chat.protected` must be maintained regardless of the `Config::VerifiedOneOnOneChats`. - // That's why the config is checked here, and not above. - && context.get_config_bool(Config::VerifiedOneOnOneChats).await? - { - new_protection = ProtectionStatus::ProtectionBroken; - } - if chat.protected != new_protection { - // The message itself will be sorted under the device message since the device - // message is `MessageState::InNoticed`, which means that all following - // messages are sorted under it. - chat_id - .set_protection( - context, - new_protection, - mime_parser.timestamp_sent, - Some(from_id), - ) - .await?; - } - if let Some(peerstate) = &mime_parser.peerstate { - restore_protection = new_protection != ProtectionStatus::Protected - && peerstate.prefer_encrypt == EncryptPreference::Mutual - // Check that the contact still has the Autocrypt key same as the - // verified key, see also `Peerstate::is_using_verified_key()`. - && contact.is_verified(context).await?; - } + if chat.protected != ProtectionStatus::Unprotected + && new_protection == ProtectionStatus::Unprotected + // `chat.protected` must be maintained regardless of the `Config::VerifiedOneOnOneChats`. + // That's why the config is checked here, and not above. + && context.get_config_bool(Config::VerifiedOneOnOneChats).await? + { + new_protection = ProtectionStatus::ProtectionBroken; + } + if chat.protected != new_protection { + // The message itself will be sorted under the device message since the device + // message is `MessageState::InNoticed`, which means that all following + // messages are sorted under it. + chat_id + .set_protection( + context, + new_protection, + mime_parser.timestamp_sent, + Some(from_id), + ) + .await?; + } + if let Some(peerstate) = &mime_parser.peerstate { + restore_protection = new_protection != ProtectionStatus::Protected + && peerstate.prefer_encrypt == EncryptPreference::Mutual + // Check that the contact still has the Autocrypt key same as the + // verified key, see also `Peerstate::is_using_verified_key()`. + && contact.is_verified(context).await?; } } } @@ -1805,7 +1809,13 @@ async fn lookup_chat_by_reply( // If this was a private message just to self, it was probably a private reply. // It should not go into the group then, but into the private chat. - if is_probably_private_reply(context, to_ids, from_id, mime_parser, parent_chat.id).await? { + if parent_chat.get_type() != Chattype::Single + && is_probably_private_reply(context, to_ids, from_id, mime_parser, parent_chat.id).await? + { + return Ok(None); + } + + if parent_chat.is_protected() || mime_parser.decrypting_failed { return Ok(None); }