fix: determine whether a message is an own message by looking at signature. multiple devices can temporarly have different sets of self addresses, and still need to properly recognize incoming versus outgoing messages. Disclaimer: some LLM tooling was initially involved but i went over everything by hand.

This commit is contained in:
holger krekel
2026-03-27 11:03:42 +01:00
parent 24b21c0588
commit c1b7fa4ffb
2 changed files with 54 additions and 3 deletions

View File

@@ -373,7 +373,7 @@ impl MimeMessage {
hop_info += "\n\n";
hop_info += &dkim_results.to_string();
let incoming = !context.is_self_addr(&from.addr).await?;
let from_is_not_self_addr = !context.is_self_addr(&from.addr).await?;
let mut aheader_values = mail.headers.get_all_values(HeaderDef::Autocrypt.into());
@@ -438,7 +438,7 @@ impl MimeMessage {
};
let mut autocrypt_header = None;
if incoming {
if from_is_not_self_addr {
// See `get_all_addresses_from_header()` for why we take the last valid header.
for val in aheader_values.iter().rev() {
autocrypt_header = match Aheader::from_str(val) {
@@ -469,7 +469,7 @@ impl MimeMessage {
None
};
let mut public_keyring = if incoming {
let mut public_keyring = if from_is_not_self_addr {
if let Some(autocrypt_header) = autocrypt_header {
vec![autocrypt_header.public_key]
} else {
@@ -654,6 +654,15 @@ impl MimeMessage {
.into_iter()
.last()
.map(|(fp, recipient_fps)| (fp, recipient_fps.into_iter().collect::<HashSet<_>>()));
let incoming = if let Some((ref sig_fp, _)) = signature {
sig_fp.hex() != key::self_fingerprint(context).await?
} else {
// rare case of getting a cleartext message
// so we determine 'incoming' flag by From-address
from_is_not_self_addr
};
let mut parser = MimeMessage {
parts: Vec::new(),
headers,

View File

@@ -5561,3 +5561,45 @@ async fn test_calendar_alternative() -> Result<()> {
Ok(())
}
/// Test that self-sent encrypted messages are detected as outgoing
/// via signature fingerprint, independently from From address.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_outgoing_by_signature_unknown_self_addr() -> Result<()> {
let mut tcm = TestContextManager::new();
let export_dir = tempfile::tempdir().unwrap();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
let msg = tcm.send_recv_accept(alice, bob, "hi bob").await;
msg.chat_id.accept(bob).await?;
tcm.send_recv(bob, alice, "hi alice").await;
imex(alice, ImexMode::ExportSelfKeys, export_dir.path(), None).await?;
// alice_dev2: same key, different address.
let different_from = "very@different.from";
assert!(!alice.is_self_addr(different_from).await?);
let alice_dev2 = &TestContext::new().await;
alice_dev2.configure_addr(different_from).await;
imex(
alice_dev2,
ImexMode::ImportSelfKeys,
export_dir.path(),
None,
)
.await?;
assert!(alice.get_config(Config::Addr).await?.unwrap() != different_from);
let msg = tcm.send_recv_accept(bob, alice_dev2, "hi alice_dev2").await;
let sent_msg = alice_dev2
.send_text(msg.chat_id, "hello from new device")
.await;
let msg = alice.recv_msg(&sent_msg).await;
// despite different from it's still recognized as an outgoing message
assert_eq!(msg.state, MessageState::OutDelivered);
Ok(())
}