Fix ephemeral timer rollback protection

Implement get_previous_message() that only looks for the last
Message-ID in the References: header instead of using
get_parent_message() which falls back to using other Message-IDs from
References and In-Reply-To field.
This commit is contained in:
link2xt
2021-09-19 03:36:49 +00:00
parent b07e20b955
commit 085a899de2

View File

@@ -872,19 +872,17 @@ async fn add_parts(
chat_id chat_id
); );
if is_dc_message == MessengerMessage::Yes if is_dc_message == MessengerMessage::Yes
&& mime_parser && get_previous_message(context, mime_parser)
.parts .await?
.get(0) .map(|p| p.ephemeral_timer)
.and_then(|part| part.param.get(Param::Quote)) == Some(ephemeral_timer)
.is_none()
&& parent.map(|p| p.ephemeral_timer) == Some(ephemeral_timer)
{ {
// The message is a Delta Chat message without a quote, so it must be a reply to the // The message is a Delta Chat message, so we know that previous message according to
// last message in the chat as seen by the sender. The timer is the same in both the // References header is the last message in the chat as seen by the sender. The timer
// received message and its parent, so we know that the sender has not seen any change // is the same in both the received message and the last message, so we know that the
// of the timer between these messages. As our timer value is different, it means the // sender has not seen any change of the timer between these messages. As our timer
// sender has not received some timer update that we have seen or sent ourselves, so we // value is different, it means the sender has not received some timer update that we
// ignore incoming timer to prevent a rollback. // have seen or sent ourselves, so we ignore incoming timer to prevent a rollback.
warn!( warn!(
context, context,
"ignoring ephemeral timer change to {:?} for chat {} to avoid rollback", "ignoring ephemeral timer change to {:?} for chat {} to avoid rollback",
@@ -2148,6 +2146,23 @@ fn set_better_msg(mime_parser: &mut MimeMessage, better_msg: impl AsRef<str>) {
} }
} }
/// Returns the last message referenced from `References` header if it is in the database.
///
/// For Delta Chat messages it is the last message in the chat of the sender.
async fn get_previous_message(
context: &Context,
mime_parser: &MimeMessage,
) -> Result<Option<Message>> {
if let Some(field) = mime_parser.get_header(HeaderDef::References) {
if let Some(rfc724mid) = parse_message_ids(field).last() {
if let Some((_, _, msg_id)) = rfc724_mid_exists(context, rfc724mid).await? {
return Ok(Some(Message::load_from_db(context, msg_id).await?));
}
}
}
Ok(None)
}
/// Given a list of Message-IDs, returns the latest message found in the database. /// Given a list of Message-IDs, returns the latest message found in the database.
async fn get_rfc724_mid_in_list(context: &Context, mid_list: &str) -> Result<Option<Message>> { async fn get_rfc724_mid_in_list(context: &Context, mid_list: &str) -> Result<Option<Message>> {
if mid_list.is_empty() { if mid_list.is_empty() {