From 62ff895ce87f4a04a143ddcba2401b6e6f24c832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 15 Apr 2026 11:44:52 +0200 Subject: [PATCH] fix(latest-event): Don't apply invalid edits on the latest event --- crates/matrix-sdk/CHANGELOG.md | 2 + .../src/latest_events/latest_event/builder.rs | 46 ++++++++++++++----- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/crates/matrix-sdk/CHANGELOG.md b/crates/matrix-sdk/CHANGELOG.md index 607e6eda9..a881bcefe 100644 --- a/crates/matrix-sdk/CHANGELOG.md +++ b/crates/matrix-sdk/CHANGELOG.md @@ -123,6 +123,8 @@ All notable changes to this project will be documented in this file. ### Bugfix +- Reject invalid edits as candidates for the latest event. + ([#6454](https://github.com/matrix-org/matrix-rust-sdk/pull/6454)) - Fix an infinite loop when loading pinned events from the storage. ([#6453](https://github.com/matrix-org/matrix-rust-sdk/pull/6453)) - `beacon_info` stop events (`live: false`, [MSC3672](https://github.com/matrix-org/matrix-spec-proposals/pull/3672)) diff --git a/crates/matrix-sdk/src/latest_events/latest_event/builder.rs b/crates/matrix-sdk/src/latest_events/latest_event/builder.rs index cbeac7135..36ec17b47 100644 --- a/crates/matrix-sdk/src/latest_events/latest_event/builder.rs +++ b/crates/matrix-sdk/src/latest_events/latest_event/builder.rs @@ -19,7 +19,10 @@ use std::{ }; pub use matrix_sdk_base::latest_event::{LatestEventValue, LocalLatestEventValue}; -use matrix_sdk_base::{deserialized_responses::TimelineEvent, store::SerializableEventContent}; +use matrix_sdk_base::{ + check_validity_of_replacement_events, deserialized_responses::TimelineEvent, + store::SerializableEventContent, +}; use ruma::{ MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, TransactionId, UserId, events::{ @@ -33,7 +36,7 @@ use ruma::{ }, }, }; -use tracing::error; +use tracing::{debug, error}; use crate::{Room, event_cache::RoomEventCache, room::Invite, send_queue::RoomSendQueueUpdate}; @@ -91,16 +94,35 @@ impl Builder { // Stop! We found a suitable event! ControlFlow::Break(()) => { // Return the latest known edit of the event or the event itself if it - // hasn't been replaced. - // TODO: Here we pick the event, and if there's an edit for the event we - // pick the edit instead. - // - // We should check if the edit is valid. - event - .event_id() - .and_then(|event_id| latest_edit_for_event.get(&event_id)) - .cloned() - .or_else(|| Some(event.clone())) + // hasn't been replaced or the replacement is invalid. + if let Some(event_id) = event.event_id() + && let Some(edit) = latest_edit_for_event.get(&event_id) + { + let original = event.kind.raw(); + let original_encryption_info = event.kind.encryption_info(); + + let replacement = edit.kind.raw(); + let replacement_encryption_info = event.kind.encryption_info(); + + Some( + match check_validity_of_replacement_events( + original, + original_encryption_info.map(|e| &(**e)), + replacement, + replacement_encryption_info.map(|e| &(**e)), + ) { + Ok(_) => edit.clone(), + Err(e) => { + debug!( + "Skipping an edit of a latest event due to the replacement event being invalid: {e}" + ); + event.clone() + } + }, + ) + } else { + Some(event.clone()) + } } } })