base: Apply redaction to latest_event in RoomInfo when applicable

This commit is contained in:
Jonas Platte
2023-07-13 16:21:31 +02:00
committed by Jonas Platte
parent 0bb7a9de7f
commit a503dccdcd
3 changed files with 109 additions and 6 deletions

View File

@@ -336,7 +336,7 @@ impl BaseClient {
SyncRoomRedactionEvent::Original(r),
),
) => {
room_info.handle_redaction(r);
room_info.handle_redaction(r, event.event.cast_ref());
let raw_event = event.event.clone().cast();
changes.add_redaction(room.room_id(), &r.redacts, raw_event);
}

View File

@@ -23,6 +23,8 @@ use futures_util::stream::{self, StreamExt};
use matrix_sdk_common::deserialized_responses::SyncTimelineEvent;
#[cfg(all(feature = "e2e-encryption", feature = "experimental-sliding-sync"))]
use matrix_sdk_common::ring_buffer::RingBuffer;
#[cfg(feature = "experimental-sliding-sync")]
use ruma::events::AnySyncTimelineEvent;
use ruma::{
api::client::sync::sync_events::v3::RoomSummary as RumaSummary,
events::{
@@ -44,11 +46,10 @@ use ruma::{
RoomAccountDataEventType,
},
room::RoomType,
serde::Raw,
EventId, OwnedEventId, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomAliasId,
RoomId, RoomVersionId, UserId,
};
#[cfg(all(feature = "e2e-encryption", feature = "experimental-sliding-sync"))]
use ruma::{events::AnySyncTimelineEvent, serde::Raw};
use serde::{Deserialize, Serialize};
use tracing::{debug, info, instrument, warn};
@@ -851,7 +852,22 @@ impl RoomInfo {
}
/// Handle the given redaction.
pub fn handle_redaction(&mut self, event: &OriginalSyncRoomRedactionEvent) {
pub fn handle_redaction(
&mut self,
event: &OriginalSyncRoomRedactionEvent,
_raw: &Raw<OriginalSyncRoomRedactionEvent>,
) {
#[cfg(feature = "experimental-sliding-sync")]
if let Some(latest_event) = &mut self.latest_event {
if latest_event.event_id().as_deref() == Some(&*event.redacts) {
let room_version = self.base_info.room_version().unwrap_or(&RoomVersionId::V1);
match apply_redaction(&latest_event.event, _raw, room_version) {
Some(redacted) => latest_event.event = redacted,
None => self.latest_event = None,
}
}
}
self.base_info.handle_redaction(event);
}
@@ -982,6 +998,41 @@ impl RoomInfo {
}
}
#[cfg(feature = "experimental-sliding-sync")]
fn apply_redaction(
event: &Raw<AnySyncTimelineEvent>,
raw_redaction: &Raw<OriginalSyncRoomRedactionEvent>,
room_version: &RoomVersionId,
) -> Option<Raw<AnySyncTimelineEvent>> {
use ruma::canonical_json::redact_in_place;
let mut event_json = match event.deserialize_as() {
Ok(json) => json,
Err(e) => {
warn!("Failed to deserialize latest event: {e}");
return None;
}
};
let redacted_because = match raw_redaction.try_into() {
Ok(rb) => rb,
Err(e) => {
warn!("Redaction event is not valid canonical JSON: {e}");
return None;
}
};
let redact_result = redact_in_place(&mut event_json, room_version, Some(redacted_because));
if let Err(e) = redact_result {
warn!("Failed to redact latest event: {e}");
return None;
}
let raw = Raw::new(&event_json).expect("CanonicalJsonObject must be serializable");
Some(raw.cast())
}
bitflags! {
/// Room state filter as a bitset.
///

View File

@@ -452,6 +452,7 @@ mod test {
sync::{Arc, RwLock as SyncRwLock},
};
use assert_matches::assert_matches;
use matrix_sdk_common::ring_buffer::RingBuffer;
use matrix_sdk_test::async_test;
use ruma::{
@@ -462,9 +463,10 @@ mod test {
avatar::RoomAvatarEventContent,
canonical_alias::RoomCanonicalAliasEventContent,
member::{MembershipState, RoomMemberEventContent},
message::SyncRoomMessageEvent,
},
AnySyncStateEvent, AnySyncTimelineEvent, GlobalAccountDataEventContent,
StateEventContent,
AnySyncMessageLikeEvent, AnySyncStateEvent, AnySyncTimelineEvent,
GlobalAccountDataEventContent, StateEventContent,
},
mxc_uri, room_alias_id, room_id,
serde::Raw,
@@ -765,6 +767,56 @@ mod test {
assert_eq!(ev_id(client_room.latest_event()), "$idb");
}
#[async_test]
async fn cached_latest_event_can_be_redacted() {
// Given a logged-in client
let client = logged_in_client().await;
let room_id = room_id!("!r:e.uk");
let event_a = json!({
"sender": "@alice:example.com",
"type": "m.room.message",
"event_id": "$ida",
"origin_server_ts": 12344446,
"content": { "body":"A", "msgtype": "m.text" },
});
// When the sliding sync response contains a timeline
let room = room_with_timeline(&[event_a]);
let response = response_with_room(room_id, room).await;
client.process_sliding_sync(&response).await.expect("Failed to process sync");
// Then the room holds the latest event
let client_room = client.get_room(room_id).expect("No room found");
assert_eq!(ev_id(client_room.latest_event()), "$ida");
let redaction = json!({
"sender": "@alice:example.com",
"type": "m.room.redaction",
"event_id": "$idb",
"redacts": "$ida",
"origin_server_ts": 12344448,
"content": {},
});
// When a redaction for that event is received
let room = room_with_timeline(&[redaction]);
let response = response_with_room(room_id, room).await;
client.process_sliding_sync(&response).await.expect("Failed to process sync");
// Then the room still holds the latest event
let client_room = client.get_room(room_id).expect("No room found");
let latest_event = client_room.latest_event().unwrap();
assert_eq!(latest_event.event_id().unwrap(), "$ida");
// But it's now redacted
assert_matches!(
latest_event.event.deserialize().unwrap(),
AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage(
SyncRoomMessageEvent::Redacted(_)
))
);
}
#[test]
fn when_no_events_we_dont_cache_any() {
let events = &[];