fix: Treat only "Auto-Submitted: auto-generated" messages as bot-sent (#5213)

"Auto-Submitted: auto-replied" messages mustn't be considered as sent by either bots or non-bots,
e.g. MDNs have this header value and it's the same for bots and non-bots.
This commit is contained in:
iequidoo
2024-01-24 23:11:35 -03:00
committed by iequidoo
parent 19dce9ddfa
commit 7cf382a3b8
5 changed files with 48 additions and 10 deletions

View File

@@ -757,7 +757,7 @@ impl Message {
self.param.get_int(Param::GuaranteeE2ee).unwrap_or_default() != 0
}
/// Returns true if message is Auto-Submitted.
/// Returns true if message is auto-generated.
pub fn is_bot(&self) -> bool {
self.param.get_bool(Param::Bot).unwrap_or_default()
}

View File

@@ -117,8 +117,8 @@ pub(crate) struct MimeMessage {
/// Hop info for debugging.
pub(crate) hop_info: String,
/// Whether the contact sending this should be marked as bot.
pub(crate) is_bot: bool,
/// Whether the contact sending this should be marked as bot or non-bot.
pub(crate) is_bot: Option<bool>,
/// When the message was received, in secs since epoch.
pub(crate) timestamp_rcvd: i64,
@@ -394,9 +394,6 @@ impl MimeMessage {
}
}
// Auto-submitted is also set by holiday-notices so we also check `chat-version`
let is_bot = headers.contains_key("auto-submitted") && headers.contains_key("chat-version");
let timestamp_rcvd = smeared_time(context);
let timestamp_sent = headers
.get(HeaderDef::Date.get_headername())
@@ -431,7 +428,7 @@ impl MimeMessage {
is_mime_modified: false,
decoded_data: Vec::new(),
hop_info,
is_bot,
is_bot: None,
timestamp_rcvd,
timestamp_sent,
};
@@ -464,6 +461,13 @@ impl MimeMessage {
},
};
if parser.mdn_reports.is_empty() {
// "Auto-Submitted" is also set by holiday-notices so we also check "chat-version".
let is_bot = parser.headers.get("auto-submitted")
== Some(&"auto-generated".to_string())
&& parser.headers.contains_key("chat-version");
parser.is_bot = Some(is_bot);
}
parser.maybe_remove_bad_parts();
parser.maybe_remove_inline_mailinglist_footer();
parser.heuristically_parse_ndn(context).await;
@@ -702,7 +706,7 @@ impl MimeMessage {
self.do_add_single_part(part);
}
if self.headers.contains_key("auto-submitted") {
if self.is_bot == Some(true) {
for part in &mut self.parts {
part.param.set(Param::Bot, "1");
}
@@ -2740,6 +2744,7 @@ Chat-Version: 1.0\n\
Message-ID: <bar@example.org>\n\
To: Alice <alice@example.org>\n\
From: Bob <bob@example.org>\n\
Auto-Submitted: auto-replied\n\
Content-Type: multipart/report; report-type=disposition-notification;\n\t\
boundary=\"kJBbU58X1xeWNHgBtTbMk80M5qnV4N\"\n\
\n\
@@ -2775,6 +2780,7 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\
assert_eq!(message.parts.len(), 1);
assert_eq!(message.mdn_reports.len(), 1);
assert_eq!(message.is_bot, None);
}
/// Test parsing multiple MDNs combined in a single message.

View File

@@ -65,7 +65,7 @@ pub enum Param {
/// For Messages: the message is a reaction.
Reaction = b'x',
/// For Messages: a message with Auto-Submitted header ("bot").
/// For Messages: a message with "Auto-Submitted: auto-generated" header ("bot").
Bot = b'b',
/// For Messages: unset or 0=not forwarded,

View File

@@ -539,7 +539,9 @@ pub(crate) async fn receive_imf_inner(
.handle_reports(context, from_id, &mime_parser.parts)
.await;
from_id.mark_bot(context, mime_parser.is_bot).await?;
if let Some(is_bot) = mime_parser.is_bot {
from_id.mark_bot(context, is_bot).await?;
}
Ok(Some(received_msg))
}

View File

@@ -2684,6 +2684,36 @@ async fn test_read_receipts_dont_create_chats() -> Result<()> {
Ok(())
}
/// Test that read receipts don't unmark contacts as bots.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_read_receipts_dont_unmark_bots() -> Result<()> {
let alice = &TestContext::new_alice().await;
let bob = &TestContext::new_bob().await;
let ab_contact = alice.add_or_lookup_contact(bob).await;
ab_contact.id.mark_bot(alice, true).await?;
let alice_chat = alice.create_chat(bob).await;
// Alice sends and Bob receives a message.
bob.recv_msg(&alice.send_text(alice_chat.id, "Message").await)
.await;
let received_msg = bob.get_last_msg().await;
// Bob sends a read receipt.
let mdn_mimefactory =
crate::mimefactory::MimeFactory::from_mdn(bob, &received_msg, vec![]).await?;
let rendered_mdn = mdn_mimefactory.render(bob).await?;
let mdn_body = rendered_mdn.message;
// Alice receives the read receipt.
receive_imf(alice, mdn_body.as_bytes(), false).await?;
let msg = alice.get_last_msg_in(alice_chat.id).await;
assert_eq!(msg.state, MessageState::OutMdnRcvd);
let ab_contact = alice.add_or_lookup_contact(bob).await;
assert!(ab_contact.is_bot());
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_gmx_forwarded_msg() -> Result<()> {
let t = TestContext::new_alice().await;