feat: protect Autocrypt header

This commit is contained in:
link2xt
2025-08-12 22:11:05 +00:00
committed by l
parent 9826c28581
commit 5256013615
6 changed files with 7 additions and 54 deletions

View File

@@ -389,12 +389,6 @@ pub enum Config {
/// Make all outgoing messages with Autocrypt header "multipart/signed".
SignUnencrypted,
/// Enable header protection for `Autocrypt` header.
///
/// This is an experimental setting not compatible to other MUAs
/// and older Delta Chat versions (core version <= v1.149.0).
ProtectAutocrypt,
/// Let the core save all events to the database.
/// This value is used internally to remember the MsgId of the logging xdc
#[strum(props(default = "0"))]

View File

@@ -1035,12 +1035,6 @@ impl Context {
.await?
.to_string(),
);
res.insert(
"protect_autocrypt",
self.get_config_int(Config::ProtectAutocrypt)
.await?
.to_string(),
);
res.insert(
"debug_logging",
self.get_config_int(Config::DebugLogging).await?.to_string(),

View File

@@ -964,10 +964,6 @@ impl MimeFactory {
hidden_headers.push(header.clone());
} else if is_hidden(&header_name) {
hidden_headers.push(header.clone());
} else if header_name == "autocrypt"
&& !context.get_config_bool(Config::ProtectAutocrypt).await?
{
unprotected_headers.push(header.clone());
} else if header_name == "from" {
// Unencrypted securejoin messages should _not_ include the display name:
if is_encrypted || !is_securejoin_message {

View File

@@ -666,7 +666,7 @@ async fn test_selfavatar_unencrypted_signed() {
assert_eq!(part.match_indices("From:").count(), 1);
assert_eq!(part.match_indices("Message-ID:").count(), 0);
assert_eq!(part.match_indices("Subject:").count(), 1);
assert_eq!(part.match_indices("Autocrypt:").count(), 0);
assert_eq!(part.match_indices("Autocrypt:").count(), 1);
assert_eq!(part.match_indices("Chat-User-Avatar:").count(), 0);
let part = payload.next().unwrap();
@@ -717,7 +717,7 @@ async fn test_selfavatar_unencrypted_signed() {
assert_eq!(part.match_indices("From:").count(), 1);
assert_eq!(part.match_indices("Message-ID:").count(), 0);
assert_eq!(part.match_indices("Subject:").count(), 1);
assert_eq!(part.match_indices("Autocrypt:").count(), 0);
assert_eq!(part.match_indices("Autocrypt:").count(), 1);
assert_eq!(part.match_indices("Chat-User-Avatar:").count(), 0);
let part = payload.next().unwrap();

View File

@@ -1817,39 +1817,6 @@ async fn test_take_last_header() {
);
}
async fn test_protect_autocrypt(enabled: bool) -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
let chat = alice.create_chat(bob).await;
alice
.set_config_bool(Config::ProtectAutocrypt, enabled)
.await?;
let sent = alice.send_text(chat.id, "Hello!").await;
assert_eq!(sent.payload().contains("Autocrypt: "), !enabled);
let msg = bob.recv_msg(&sent).await;
assert_eq!(msg.get_showpadlock(), true);
Ok(())
}
/// Tests that if `protect_autocrypt` is enabled,
/// `Autocrypt` header does not appear in the outer headers
/// of encrypted messages.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_protect_autocrypt_enabled() -> Result<()> {
test_protect_autocrypt(true).await
}
/// Tests that if `protect_autocrypt` is disabled,
/// `Autocrypt` header appears in the outer headers
/// of encrypted messages.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_protect_autocrypt_false() -> Result<()> {
test_protect_autocrypt(false).await
}
/// Tests that CRLF before MIME boundary
/// is not treated as the part body.
///

View File

@@ -217,10 +217,12 @@ async fn test_aeap_replay_attack() -> Result<()> {
// Fiona gets the message, replaces the From addr...
let sent = sent
.payload()
.replace("From: <alice@example.org>", "From: <fiona@example.net>")
.replace("addr=alice@example.org;", "addr=fiona@example.net;");
.replace("From: <alice@example.org>", "From: <fiona@example.net>");
sent.find("From: <fiona@example.net>").unwrap(); // Assert that it worked
sent.find("addr=fiona@example.net;").unwrap(); // Assert that it worked
// Autocrypt header is protected, nothing to replace outside.
// In the signed part we cannot replace it without breaking the signature.
assert!(!sent.contains("addr=alice@example.org;"));
tcm.section("Fiona replaced the From addr and forwards the message to Bob");
receive_imf(&bob, sent.as_bytes(), false).await?.unwrap();