diff --git a/src/pgp.rs b/src/pgp.rs index bcf888873..1df6d72f6 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -196,7 +196,13 @@ pub async fn pk_encrypt( hashed.push(Subpacket::critical(SubpacketData::SignatureCreationTime( chrono::Utc::now().trunc_subsecs(0), ))?); + // Test "elena" uses old Delta Chat. + let skip = private_key_for_signing.dc_fingerprint().hex() + == "B86586B6DEF437D674BFAFC02A6B2EBC633B9E82"; for key in &public_keys_for_encryption { + if skip { + break; + } let data = SubpacketData::IntendedRecipientFingerprint(key.fingerprint()); let subpkt = match private_key_for_signing.version() < KeyVersion::V6 { true => Subpacket::regular(data)?, diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 47f7c8850..bb85dc6bf 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -27,7 +27,9 @@ use crate::events::EventType; use crate::headerdef::{HeaderDef, HeaderDefMap}; use crate::imap::{GENERATED_PREFIX, markseen_on_imap_table}; use crate::key::{DcKey, Fingerprint}; -use crate::key::{load_self_public_key_opt, self_fingerprint, self_fingerprint_opt}; +use crate::key::{ + load_self_public_key, load_self_public_key_opt, self_fingerprint, self_fingerprint_opt, +}; use crate::log::{LogExt as _, warn}; use crate::message::{ self, Message, MessageState, MessengerMessage, MsgId, Viewtype, rfc724_mid_exists, @@ -386,8 +388,30 @@ async fn get_to_and_past_contact_ids( // This is an encrypted 1:1 chat. to_ids = pgp_to_ids } else { - let ids = match mime_parser.was_encrypted() { - true => { + let ids = if mime_parser.was_encrypted() { + let mut recipient_fps = mime_parser + .signature + .as_ref() + .map(|(_, recipient_fps)| recipient_fps.iter().cloned().collect::>()) + .unwrap_or_default(); + // If there are extra recipient fingerprints, it may be a non-chat "implicit + // Bcc" message. Fall back to in-chat lookup if so. + if !recipient_fps.is_empty() && recipient_fps.len() <= 2 { + let self_fp = load_self_public_key(context).await?.dc_fingerprint(); + recipient_fps.retain(|fp| *fp != self_fp); + if recipient_fps.is_empty() { + vec![Some(ContactId::SELF)] + } else { + add_or_lookup_key_contacts( + context, + &mime_parser.recipients, + &mime_parser.gossiped_keys, + &recipient_fps, + Origin::Hidden, + ) + .await? + } + } else { lookup_key_contacts_fallback_to_chat( context, &mime_parser.recipients, @@ -396,7 +420,8 @@ async fn get_to_and_past_contact_ids( ) .await? } - false => vec![], + } else { + vec![] }; if mime_parser.was_encrypted() && !ids.contains(&None) // Prefer creating PGP chats if there are any key-contacts. At least this prevents diff --git a/src/receive_imf/receive_imf_tests.rs b/src/receive_imf/receive_imf_tests.rs index 902e8681c..8209de31b 100644 --- a/src/receive_imf/receive_imf_tests.rs +++ b/src/receive_imf/receive_imf_tests.rs @@ -5111,9 +5111,9 @@ async fn test_dont_verify_by_verified_by_unknown() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_recv_outgoing_msg_before_securejoin() -> Result<()> { let mut tcm = TestContextManager::new(); - let a0 = &tcm.alice().await; - let a1 = &tcm.alice().await; let bob = &tcm.bob().await; + let a0 = &tcm.elena().await; + let a1 = &tcm.elena().await; tcm.execute_securejoin(bob, a0).await; let chat_id_a0_bob = a0.create_chat_id(bob).await; @@ -5154,14 +5154,31 @@ async fn test_recv_outgoing_msg_before_securejoin() -> Result<()> { chat_a1.why_cant_send(a1).await?, Some(CantSendReason::ContactRequest) ); + + let a0 = &tcm.alice().await; + let a1 = &tcm.alice().await; + tcm.execute_securejoin(bob, a0).await; + let chat_id_a0_bob = a0.create_chat_id(bob).await; + let sent_msg = a0.send_text(chat_id_a0_bob, "Hi").await; + bob.recv_msg(&sent_msg).await; + let msg_a1 = a1.recv_msg(&sent_msg).await; + assert!(msg_a1.get_showpadlock()); + let chat_a1 = Chat::load_from_db(a1, msg_a1.chat_id).await?; + assert_eq!(chat_a1.typ, Chattype::Single); + assert!(chat_a1.is_encrypted(a1).await?); + assert_eq!( + chat::get_chat_contacts(a1, chat_a1.id).await?, + [a1.add_or_lookup_contact_id(bob).await] + ); + assert!(chat_a1.can_send(a1).await?); Ok(()) } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_recv_outgoing_msg_before_having_key_and_after() -> Result<()> { let mut tcm = TestContextManager::new(); - let a0 = &tcm.alice().await; - let a1 = &tcm.alice().await; + let a0 = &tcm.elena().await; + let a1 = &tcm.elena().await; let bob = &tcm.bob().await; tcm.execute_securejoin(bob, a0).await; @@ -5174,9 +5191,9 @@ async fn test_recv_outgoing_msg_before_having_key_and_after() -> Result<()> { assert!(!chat_a1.is_encrypted(a1).await?); // Device a1 somehow learns Bob's key and creates the corresponding chat. However, this doesn't - // help currently because we only look up key contacts by address in a particular chat and the - // new chat isn't referenced by the received message. This should be fixed by sending and - // receiving Intended Recipient Fingerprint subpackets. + // help because we only look up key contacts by address in a particular chat and the new chat + // isn't referenced by the received message. This is fixed by sending and receiving Intended + // Recipient Fingerprint subpackets which elena doesn't send. a1.create_chat_id(bob).await; let sent_msg = a0.send_text(chat_id_a0_bob, "Hi again").await; let msg_a1 = a1.recv_msg(&sent_msg).await; diff --git a/src/test_utils.rs b/src/test_utils.rs index ad4380fdd..89adeff3b 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -117,6 +117,8 @@ impl TestContextManager { .await } + /// Returns new elena's "device". + /// Elena doesn't send Intended Recipient Fingerprint subpackets to simulate old Delta Chat. pub async fn elena(&mut self) -> TestContext { TestContext::builder() .configure_elena()