Skip to content

Commit

Permalink
fix: Never allow a message timestamp to be a lot in the future (#5249)
Browse files Browse the repository at this point in the history
We must finish what was started in
#5088.
  • Loading branch information
Hocuri authored Feb 7, 2024
1 parent fba27ff commit 11214c7
Showing 1 changed file with 44 additions and 12 deletions.
56 changes: 44 additions & 12 deletions src/mimeparser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,12 @@ impl MimeMessage {
) -> Result<Self> {
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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
}
}
Expand All @@ -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,
Expand Down Expand Up @@ -2237,6 +2232,7 @@ mod tests {
message::{Message, MessageState, MessengerMessage},
receive_imf::receive_imf,
test_utils::TestContext,
tools::time,
};

impl AvatarAction {
Expand Down Expand Up @@ -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: [email protected]\n\
From: [email protected]\n\
Date: Today, 29 February 3004 00:00:10 -800\n\
Message-ID: [email protected]\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(())
}
}

0 comments on commit 11214c7

Please sign in to comment.