diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 967500f15..739a9653f 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -208,11 +208,12 @@ impl MimeMessage { ) -> Result { let mail = mailparse::parse_mail(body)?; - let message_time = mail + let timestamp_rcvd = smeared_time(context); + let timestamp_sent = mail .headers .get_header_value(HeaderDef::Date) .and_then(|v| mailparse::dateparse(&v).ok()) - .unwrap_or_default(); + .map_or(timestamp_rcvd, |value| min(value, timestamp_rcvd + 60)); let mut hop_info = parse_receive_headers(&mail.get_headers()); let mut headers = Default::default(); @@ -279,7 +280,7 @@ impl MimeMessage { let private_keyring = load_self_secret_keyring(context).await?; let mut decryption_info = - prepare_decryption(context, &mail, &from.addr, message_time).await?; + prepare_decryption(context, &mail, &from.addr, timestamp_sent).await?; // Memory location for a possible decrypted message. let mut mail_raw = Vec::new(); @@ -325,7 +326,7 @@ impl MimeMessage { let gossip_headers = mail.headers.get_all_values("Autocrypt-Gossip"); gossiped_keys = update_gossip_peerstates( context, - message_time, + timestamp_sent, &from.addr, &recipients, gossip_headers, @@ -376,12 +377,12 @@ impl MimeMessage { // If it is not a read receipt, degrade encryption. if let (Some(peerstate), Ok(mail)) = (&mut decryption_info.peerstate, mail) { - if message_time > peerstate.last_seen_autocrypt + if timestamp_sent > peerstate.last_seen_autocrypt && mail.ctype.mimetype != "multipart/report" // Disallowing keychanges is disabled for now: // && decryption_info.dkim_results.allow_keychange { - peerstate.degrade_encryption(message_time); + peerstate.degrade_encryption(timestamp_sent); } } } @@ -395,12 +396,6 @@ impl MimeMessage { } } - let timestamp_rcvd = smeared_time(context); - let timestamp_sent = headers - .get(HeaderDef::Date.get_headername()) - .and_then(|value| mailparse::dateparse(value).ok()) - .map_or(timestamp_rcvd, |value| min(value, timestamp_rcvd + 60)); - let mut parser = MimeMessage { parts: Vec::new(), headers, @@ -2237,6 +2232,7 @@ mod tests { message::{Message, MessageState, MessengerMessage}, receive_imf::receive_imf, test_utils::TestContext, + tools::time, }; impl AvatarAction { @@ -3849,4 +3845,40 @@ Content-Disposition: reaction\n\ Ok(()) } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_time_in_future() -> Result<()> { + let alice = TestContext::new_alice().await; + + let beginning_time = time(); + + // Receive a message with a date far in the future (year 3004) + // I'm just going to assume that no one uses this code after the year 3000 + let mime_message = MimeMessage::from_bytes( + &alice, + b"To: alice@example.org\n\ + From: bob@example.net\n\ + Date: Today, 29 February 3004 00:00:10 -800\n\ + Message-ID: 56789@example.net\n\ + Subject: Meeting\n\ + Mime-Version: 1.0 (1.0)\n\ + Content-Type: text/plain; charset=utf-8\n\ + \n\ + Hi", + None, + ) + .await?; + + // We do allow the time to be in the future a bit (because of unsynchronized clocks), + // but only 60 seconds: + assert!(mime_message.decryption_info.message_time <= time() + 60); + assert!(mime_message.decryption_info.message_time >= beginning_time + 60); + assert_eq!( + mime_message.decryption_info.message_time, + mime_message.timestamp_sent + ); + assert!(mime_message.timestamp_rcvd <= time()); + + Ok(()) + } }