diff --git a/src/mimefactory.rs b/src/mimefactory.rs index ffecedbd4..040fb2a2a 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -5,6 +5,7 @@ use std::collections::HashSet; use anyhow::{bail, ensure, Context as _, Result}; use base64::Engine as _; use chrono::TimeZone; +use email::Mailbox; use format_flowed::{format_flowed, format_flowed_quote}; use lettre_email::{Address, Header, MimeMultipartType, PartBuilder}; use tokio::fs; @@ -552,8 +553,7 @@ impl<'a> MimeFactory<'a> { // Start with Internet Message Format headers in the order of the standard example // . let from_header = Header::new_with_value("From".into(), vec![from]).unwrap(); - headers.unprotected.push(from_header.clone()); - headers.protected.push(from_header); + headers.protected.push(from_header.clone()); if let Some(sender_displayname) = &self.sender_displayname { let sender = @@ -563,8 +563,8 @@ impl<'a> MimeFactory<'a> { .push(Header::new_with_value("Sender".into(), vec![sender]).unwrap()); } headers - .unprotected - .push(Header::new_with_value("To".into(), to).unwrap()); + .protected + .push(Header::new_with_value("To".into(), to.clone()).unwrap()); let subject_str = self.subject_str(context).await?; let encoded_subject = if subject_str @@ -681,6 +681,46 @@ impl<'a> MimeFactory<'a> { encrypt_helper.should_encrypt(context, e2ee_guaranteed, &peerstates)?; let is_encrypted = should_encrypt && !force_plaintext; + if is_encrypted { + headers.unprotected.insert( + 0, + Header::new_with_value( + "To".into(), + to.into_iter() + .map(|header| match header { + Address::Mailbox(mb) => Address::Mailbox(Mailbox { + address: mb.address, + name: None, + }), + Address::Group(name, participants) => Address::new_group( + name, + participants + .into_iter() + .map(|mb| Mailbox { + address: mb.address, + name: None, + }) + .collect(), + ), + }) + .collect::>(), + ) + .unwrap(), + ); + } + if is_encrypted && verified { + headers.unprotected.insert( + 0, + Header::new_with_value( + "From".into(), + vec![Address::new_mailbox(self.from_addr.clone())], + ) + .unwrap(), + ); + } else { + headers.unprotected.insert(0, from_header); + } + let (main_part, parts) = match self.loaded { Loaded::Message { .. } => { self.render_message(context, &mut headers, &grpimage, is_encrypted) @@ -827,7 +867,6 @@ impl<'a> MimeFactory<'a> { message } else { - // Store hidden headers in the inner unencrypted message. let message = headers .hidden .into_iter() @@ -835,8 +874,6 @@ impl<'a> MimeFactory<'a> { let message = PartBuilder::new() .message_type(MimeMultipartType::Mixed) .child(message.build()); - - // Store protected headers in the outer message. let message = headers .protected .iter() diff --git a/src/mimeparser.rs b/src/mimeparser.rs index e0a1b4594..daeed966a 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -302,7 +302,7 @@ impl MimeMessage { // them in signed-only emails, but has no value currently. Self::remove_secured_headers(&mut headers); - let from = from.context("No from in message")?; + let mut from = from.context("No from in message")?; let private_keyring = load_self_secret_keyring(context).await?; let mut decryption_info = @@ -398,6 +398,7 @@ impl MimeMessage { if let (Some(inner_from), true) = (inner_from, !signatures.is_empty()) { if addr_cmp(&inner_from.addr, &from.addr) { from_is_signed = true; + from = inner_from; } else { // There is a From: header in the encrypted & // signed part, but it doesn't match the outer one. diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 06ee18441..a13ce5d79 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -860,6 +860,35 @@ async fn test_verified_member_added_reordering() -> Result<()> { Ok(()) } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_no_unencrypted_name_if_verified() -> Result<()> { + let mut tcm = TestContextManager::new(); + for verified in [false, true] { + let alice = tcm.alice().await; + let bob = tcm.bob().await; + bob.set_config(Config::Displayname, Some("Bob Smith")) + .await?; + if verified { + enable_verified_oneonone_chats(&[&bob]).await; + mark_as_verified(&bob, &alice).await; + } else { + tcm.send_recv_accept(&alice, &bob, "hi").await; + } + + let chat_id = bob.create_chat(&alice).await.id; + let msg = &bob.send_text(chat_id, "hi").await; + + assert_eq!(msg.payload.contains("Bob Smith"), !verified); + assert!(msg.payload.contains("BEGIN PGP MESSAGE")); + + let msg = alice.recv_msg(msg).await; + let contact = Contact::get_by_id(&alice, msg.from_id).await?; + + assert_eq!(Contact::get_display_name(&contact), "Bob Smith"); + } + Ok(()) +} + // ============== Helper Functions ============== async fn assert_verified(this: &TestContext, other: &TestContext, protected: ProtectionStatus) {