From cdeca9ed9d354a3871f8d5aab5b4348dbd533ac2 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Mon, 26 Aug 2024 20:44:26 +0200 Subject: [PATCH 1/2] fix: Only include one From: header in securejoin messages (#5917) This fixes the bug that sometimes made QR scans fail. The problem was: When sorting headers into unprotected/hidden/protected, the From: header was added twice for all messages: Once into unprotected_headers and once into protected_headers. For messages that are `is_encrypted && verified || is_securejoin_message`, the display name is removed before pushing it into unprotected_headers. Later, duplicate headers are removed from unprotected_headers right before prepending unprotected_headers to the message. But since the unencrypted From: header got modified a bit when removing the display name, it's not exactly the same anymore, so it's not removed from unprotected_headers and consequently added again. --- src/mimefactory.rs | 33 ++++++++++++++++----------------- src/securejoin.rs | 2 ++ src/test_utils.rs | 32 +++++++++++++++++++++++++++++++- src/tests/verified_chats.rs | 4 ++-- 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 154c1b3fd..4469fc7d0 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -726,18 +726,18 @@ impl MimeFactory { } else if header_name == "autocrypt" { unprotected_headers.push(header.clone()); } else if header_name == "from" { - protected_headers.push(header.clone()); - if is_encrypted && verified || is_securejoin_message { - unprotected_headers.push( - Header::new_with_value( - header.name, - vec![Address::new_mailbox(self.from_addr.clone())], - ) - .unwrap(), - ); - } else { - unprotected_headers.push(header); + // Unencrypted securejoin messages should _not_ include the display name: + if is_encrypted || !is_securejoin_message { + protected_headers.push(header.clone()); } + + unprotected_headers.push( + Header::new_with_value( + header.name, + vec![Address::new_mailbox(self.from_addr.clone())], + ) + .unwrap(), + ); } else if header_name == "to" { protected_headers.push(header.clone()); if is_encrypted { @@ -902,12 +902,11 @@ impl MimeFactory { .fold(message, |message, header| message.header(header.clone())); if skip_autocrypt || !context.get_config_bool(Config::SignUnencrypted).await? { - let protected: HashSet
= HashSet::from_iter(protected_headers.into_iter()); - for h in unprotected_headers.split_off(0) { - if !protected.contains(&h) { - unprotected_headers.push(h); - } - } + // Deduplicate unprotected headers that also are in the protected headers: + let protected: HashSet<&str> = + HashSet::from_iter(protected_headers.iter().map(|h| h.name.as_str())); + unprotected_headers.retain(|h| !protected.contains(&h.name.as_str())); + message } else { let message = message.header(get_content_type_directives_header()); diff --git a/src/securejoin.rs b/src/securejoin.rs index 3f5dbca1e..fdd393e69 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -843,6 +843,7 @@ mod tests { ); let sent = bob.pop_sent_msg().await; + assert!(!sent.payload.contains("Bob Examplenet")); assert_eq!(sent.recipient(), EmailAddress::new(alice_addr).unwrap()); let msg = alice.parse_msg(&sent).await; assert!(!msg.was_encrypted()); @@ -860,6 +861,7 @@ mod tests { ); let sent = alice.pop_sent_msg().await; + assert!(!sent.payload.contains("Alice Exampleorg")); let msg = bob.parse_msg(&sent).await; assert!(msg.was_encrypted()); assert_eq!( diff --git a/src/test_utils.rs b/src/test_utils.rs index 94c23d6e7..5e0ceb44a 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -2,7 +2,7 @@ //! //! This private module is only compiled for test runs. #![allow(clippy::indexing_slicing)] -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashSet}; use std::fmt::Write; use std::ops::{Deref, DerefMut}; use std::panic; @@ -477,6 +477,36 @@ impl TestContext { update_msg_state(&self.ctx, msg_id, MessageState::OutDelivered) .await .expect("failed to update message state"); + + let payload_headers = payload.split("\r\n\r\n").next().unwrap().lines(); + let payload_header_names: Vec<_> = payload_headers + .map(|h| h.split(':').next().unwrap()) + .collect(); + + // Check that we are sending exactly one From, Subject, Date, To, Message-ID, and MIME-Version header: + for header in &[ + "From", + "Subject", + "Date", + "To", + "Message-ID", + "MIME-Version", + ] { + assert_eq!( + payload_header_names.iter().filter(|h| *h == header).count(), + 1, + "This sent email should contain the header {header} exactly 1 time:\n{payload}" + ); + } + // Check that we aren't sending any header twice: + let mut hash_set = HashSet::new(); + for header_name in payload_header_names { + assert!( + hash_set.insert(header_name), + "This sent email shouldn't contain the header {header_name} multiple times:\n{payload}" + ); + } + Some(SentMessage { payload, sender_msg_id: msg_id, diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 732047eb0..757158e34 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -881,7 +881,7 @@ async fn test_verified_member_added_reordering() -> Result<()> { } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn test_no_unencrypted_name_if_verified() -> Result<()> { +async fn test_no_unencrypted_name_if_encrypted() -> Result<()> { let mut tcm = TestContextManager::new(); for verified in [false, true] { let alice = tcm.alice().await; @@ -898,7 +898,7 @@ async fn test_no_unencrypted_name_if_verified() -> Result<()> { 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_eq!(msg.payload.contains("Bob Smith"), false); assert!(msg.payload.contains("BEGIN PGP MESSAGE")); let msg = alice.recv_msg(msg).await; From 2dd85afdc2ae8626f1cd824d713ef64ccbf07379 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 26 Aug 2024 18:53:03 +0000 Subject: [PATCH 2/2] chore(release): prepare for 1.142.10 --- CHANGELOG.md | 7 +++++++ Cargo.lock | 10 +++++----- Cargo.toml | 2 +- deltachat-ffi/Cargo.toml | 2 +- deltachat-jsonrpc/Cargo.toml | 2 +- deltachat-jsonrpc/typescript/package.json | 2 +- deltachat-repl/Cargo.toml | 2 +- deltachat-rpc-client/pyproject.toml | 2 +- deltachat-rpc-server/Cargo.toml | 2 +- deltachat-rpc-server/npm-package/package.json | 2 +- package.json | 2 +- python/pyproject.toml | 2 +- release-date.in | 2 +- 13 files changed, 23 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b35be3c6f..2546d7e2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [1.142.10] - 2024-08-26 + +### Fixes + +- Only include one From: header in securejoin messages ([#5917](https://github.com/deltachat/deltachat-core-rust/pull/5917)). + ## [1.142.9] - 2024-08-24 ### Fixes @@ -4785,3 +4791,4 @@ https://github.com/deltachat/deltachat-core-rust/pulls?q=is%3Apr+is%3Aclosed [1.142.7]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.6...v1.142.7 [1.142.8]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.7...v1.142.8 [1.142.9]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.8...v1.142.9 +[1.142.10]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.9..v1.142.10 diff --git a/Cargo.lock b/Cargo.lock index 6a5a04bc9..e65cd02f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1353,7 +1353,7 @@ dependencies = [ [[package]] name = "deltachat" -version = "1.142.9" +version = "1.142.10" dependencies = [ "ansi_term", "anyhow", @@ -1444,7 +1444,7 @@ dependencies = [ [[package]] name = "deltachat-jsonrpc" -version = "1.142.9" +version = "1.142.10" dependencies = [ "anyhow", "async-channel 2.3.1", @@ -1469,7 +1469,7 @@ dependencies = [ [[package]] name = "deltachat-repl" -version = "1.142.9" +version = "1.142.10" dependencies = [ "ansi_term", "anyhow", @@ -1484,7 +1484,7 @@ dependencies = [ [[package]] name = "deltachat-rpc-server" -version = "1.142.9" +version = "1.142.10" dependencies = [ "anyhow", "deltachat", @@ -1513,7 +1513,7 @@ dependencies = [ [[package]] name = "deltachat_ffi" -version = "1.142.9" +version = "1.142.10" dependencies = [ "anyhow", "deltachat", diff --git a/Cargo.toml b/Cargo.toml index 47d81ef23..6adcfdef9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat" -version = "1.142.9" +version = "1.142.10" edition = "2021" license = "MPL-2.0" rust-version = "1.77" diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index 2aacf84cc..a16743f3f 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat_ffi" -version = "1.142.9" +version = "1.142.10" description = "Deltachat FFI" edition = "2018" readme = "README.md" diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 785bedaba..bdd556605 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-jsonrpc" -version = "1.142.9" +version = "1.142.10" description = "DeltaChat JSON-RPC API" edition = "2021" default-run = "deltachat-jsonrpc-server" diff --git a/deltachat-jsonrpc/typescript/package.json b/deltachat-jsonrpc/typescript/package.json index 9cc6c2053..6650eb1b4 100644 --- a/deltachat-jsonrpc/typescript/package.json +++ b/deltachat-jsonrpc/typescript/package.json @@ -58,5 +58,5 @@ }, "type": "module", "types": "dist/deltachat.d.ts", - "version": "1.142.9" + "version": "1.142.10" } diff --git a/deltachat-repl/Cargo.toml b/deltachat-repl/Cargo.toml index b2c06451b..0cb80ac66 100644 --- a/deltachat-repl/Cargo.toml +++ b/deltachat-repl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-repl" -version = "1.142.9" +version = "1.142.10" license = "MPL-2.0" edition = "2021" repository = "https://github.com/deltachat/deltachat-core-rust" diff --git a/deltachat-rpc-client/pyproject.toml b/deltachat-rpc-client/pyproject.toml index ab469407e..a758b7ec8 100644 --- a/deltachat-rpc-client/pyproject.toml +++ b/deltachat-rpc-client/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "deltachat-rpc-client" -version = "1.142.9" +version = "1.142.10" description = "Python client for Delta Chat core JSON-RPC interface" classifiers = [ "Development Status :: 5 - Production/Stable", diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index 98537886a..d9cafb43b 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-rpc-server" -version = "1.142.9" +version = "1.142.10" description = "DeltaChat JSON-RPC server" edition = "2021" readme = "README.md" diff --git a/deltachat-rpc-server/npm-package/package.json b/deltachat-rpc-server/npm-package/package.json index a7e12ba45..b5a81b4aa 100644 --- a/deltachat-rpc-server/npm-package/package.json +++ b/deltachat-rpc-server/npm-package/package.json @@ -15,5 +15,5 @@ }, "type": "module", "types": "index.d.ts", - "version": "1.142.9" + "version": "1.142.10" } diff --git a/package.json b/package.json index 22929983b..df7d448bf 100644 --- a/package.json +++ b/package.json @@ -55,5 +55,5 @@ "test:mocha": "mocha node/test/test.mjs --growl --reporter=spec --bail --exit" }, "types": "node/dist/index.d.ts", - "version": "1.142.9" + "version": "1.142.10" } diff --git a/python/pyproject.toml b/python/pyproject.toml index a1dd4c08b..634f46d0f 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "deltachat" -version = "1.142.9" +version = "1.142.10" description = "Python bindings for the Delta Chat Core library using CFFI against the Rust-implemented libdeltachat" readme = "README.rst" requires-python = ">=3.7" diff --git a/release-date.in b/release-date.in index 84c5282c9..05a6be5fc 100644 --- a/release-date.in +++ b/release-date.in @@ -1 +1 @@ -2024-08-24 \ No newline at end of file +2024-08-26 \ No newline at end of file