fix: Don't receive message if a deletion request was received before (#8143)

There's no check for `from_id` so another group member can delete the
message, but this can only happen in case of message reordering and the
problem already exists for usual messages, so we may ignore it and
overall a group represents a scope of trust.

Co-authored-by: Hocuri <hocuri@gmx.de>
This commit is contained in:
iequidoo
2026-04-25 21:19:03 -03:00
committed by GitHub
parent fa68c1f0e4
commit 6d61f7e071
3 changed files with 17 additions and 8 deletions

View File

@@ -5816,7 +5816,7 @@ async fn test_send_delete_request() -> Result<()> {
let sent2 = alice.pop_sent_msg().await; let sent2 = alice.pop_sent_msg().await;
assert_eq!(alice_chat.id.get_msg_cnt(alice).await?, E2EE_INFO_MSGS + 1); assert_eq!(alice_chat.id.get_msg_cnt(alice).await?, E2EE_INFO_MSGS + 1);
// Bob receives both messages and has nothing the end // Bob receives both messages and has nothing at the end
let bob_msg = bob.recv_msg(&sent1).await; let bob_msg = bob.recv_msg(&sent1).await;
assert_eq!(bob_msg.text, "wtf"); assert_eq!(bob_msg.text, "wtf");
assert_eq!(bob_msg.chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS + 2); assert_eq!(bob_msg.chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS + 2);
@@ -5824,6 +5824,11 @@ async fn test_send_delete_request() -> Result<()> {
bob.recv_msg_opt(&sent2).await; bob.recv_msg_opt(&sent2).await;
assert_eq!(bob_msg.chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS + 1); assert_eq!(bob_msg.chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS + 1);
// ... even if he receives messages in reverse order.
let bob2 = &tcm.bob().await;
bob2.recv_msg_opt(&sent2).await;
assert!(bob2.recv_msg_opt(&sent1).await.is_none());
// Alice has another device, and there is also nothing at the end // Alice has another device, and there is also nothing at the end
let alice2 = &tcm.alice().await; let alice2 = &tcm.alice().await;
alice2.recv_msg(&sent0).await; alice2.recv_msg(&sent0).await;

View File

@@ -529,7 +529,7 @@ impl Message {
FROM msgs m FROM msgs m
LEFT JOIN chats c ON c.id=m.chat_id LEFT JOIN chats c ON c.id=m.chat_id
LEFT JOIN msgs_mdns mdns ON mdns.msg_id=m.id LEFT JOIN msgs_mdns mdns ON mdns.msg_id=m.id
WHERE m.id=? AND chat_id!=3 WHERE m.id=? AND chat_id!=3 -- DC_CHAT_ID_TRASH
LIMIT 1", LIMIT 1",
(id,), (id,),
|row| { |row| {

View File

@@ -533,15 +533,14 @@ pub(crate) async fn receive_imf_inner(
replace_msg_id = None; replace_msg_id = None;
replace_chat_id = None; replace_chat_id = None;
} else if let Some(old_msg_id) = message::rfc724_mid_exists(context, rfc724_mid).await? { } else if let Some(old_msg_id) = message::rfc724_mid_exists(context, rfc724_mid).await? {
// This code handles the download of old partial download stub messages
// It will be removed after a transitioning period,
// after we have released a few versions with pre-messages
replace_msg_id = Some(old_msg_id); replace_msg_id = Some(old_msg_id);
replace_chat_id = if let Some(msg) = Message::load_from_db_optional(context, old_msg_id) replace_chat_id = if let Some(msg) = Message::load_from_db_optional(context, old_msg_id)
.await? .await?
.filter(|msg| msg.download_state() != DownloadState::Done) .filter(|msg| msg.download_state() != DownloadState::Done)
{ {
// The message was partially downloaded before. // This code handles the download of old partial download stub messages
// It will be removed after a transitioning period,
// after we have released a few versions with pre-messages
match mime_parser.pre_message { match mime_parser.pre_message {
PreMessageMode::Post | PreMessageMode::None => { PreMessageMode::Post | PreMessageMode::None => {
info!(context, "Message already partly in DB, replacing."); info!(context, "Message already partly in DB, replacing.");
@@ -553,8 +552,10 @@ pub(crate) async fn receive_imf_inner(
} }
} }
} else { } else {
// The message was already fully downloaded info!(
// or cannot be loaded because it is deleted. context,
"Message {rfc724_mid} is fully downloaded or deleted."
);
None None
}; };
} else { } else {
@@ -2454,6 +2455,7 @@ async fn handle_edit_delete(
let rfc724_mid_vec: Vec<&str> = rfc724_mid_list.split_whitespace().collect(); let rfc724_mid_vec: Vec<&str> = rfc724_mid_list.split_whitespace().collect();
for rfc724_mid in rfc724_mid_vec { for rfc724_mid in rfc724_mid_vec {
let rfc724_mid = rfc724_mid.trim_start_matches('<').trim_end_matches('>');
if let Some(msg_id) = message::rfc724_mid_exists(context, rfc724_mid).await? { if let Some(msg_id) = message::rfc724_mid_exists(context, rfc724_mid).await? {
if let Some(msg) = Message::load_from_db_optional(context, msg_id).await? { if let Some(msg) = Message::load_from_db_optional(context, msg_id).await? {
if msg.from_id == from_id { if msg.from_id == from_id {
@@ -2468,6 +2470,8 @@ async fn handle_edit_delete(
} }
} else { } else {
warn!(context, "Delete message: {rfc724_mid:?} not found."); warn!(context, "Delete message: {rfc724_mid:?} not found.");
// Insert a tombstone so that the message will be ignored if it arrives later within a period specified in prune_tombstones().
insert_tombstone(context, rfc724_mid).await?;
} }
} }
message::delete_msgs_locally_done(context, &msg_ids, modified_chat_ids).await?; message::delete_msgs_locally_done(context, &msg_ids, modified_chat_ids).await?;