matrix_sdk_base/response_processors/
latest_event.rs1use matrix_sdk_common::deserialized_responses::TimelineEvent;
16use matrix_sdk_crypto::{DecryptionSettings, RoomEventDecryptionResult};
17use ruma::{events::AnySyncTimelineEvent, serde::Raw, RoomId};
18
19use super::{e2ee::E2EE, verification, Context};
20use crate::{
21 latest_event::{is_suitable_for_latest_event, LatestEvent, PossibleLatestEvent},
22 Result, Room,
23};
24
25pub async fn decrypt_from_rooms(
32 context: &mut Context,
33 rooms: Vec<Room>,
34 e2ee: E2EE<'_>,
35) -> Result<()> {
36 if e2ee.olm_machine.is_none() {
39 return Ok(());
40 }
41
42 for room in rooms {
43 if let Some((found, found_index)) = find_suitable_and_decrypt(&room, &e2ee).await {
47 room.on_latest_event_decrypted(
48 found,
49 found_index,
50 &mut context.state_changes,
51 &mut context.room_info_notable_updates,
52 );
53 }
54 }
55
56 Ok(())
57}
58
59async fn find_suitable_and_decrypt(
60 room: &Room,
61 e2ee: &E2EE<'_>,
62) -> Option<(Box<LatestEvent>, usize)> {
63 let enc_events = room.latest_encrypted_events();
64 let power_levels = room.power_levels().await.ok();
65 let power_levels_info = Some(room.own_user_id()).zip(power_levels.as_ref());
66
67 for (i, event) in enc_events.iter().enumerate().rev() {
69 let decrypt_sync_room_event =
73 Box::pin(decrypt_sync_room_event(event, e2ee, room.room_id()));
74
75 if let Ok(decrypted) = decrypt_sync_room_event.await {
76 if let Ok(any_sync_event) = decrypted.raw().deserialize() {
78 match is_suitable_for_latest_event(&any_sync_event, power_levels_info) {
80 PossibleLatestEvent::YesRoomMessage(_)
81 | PossibleLatestEvent::YesPoll(_)
82 | PossibleLatestEvent::YesCallInvite(_)
83 | PossibleLatestEvent::YesCallNotify(_)
84 | PossibleLatestEvent::YesSticker(_)
85 | PossibleLatestEvent::YesKnockedStateEvent(_) => {
86 return Some((Box::new(LatestEvent::new(decrypted)), i));
87 }
88 _ => (),
89 }
90 }
91 }
92 }
93
94 None
95}
96
97async fn decrypt_sync_room_event(
107 event: &Raw<AnySyncTimelineEvent>,
108 e2ee: &E2EE<'_>,
109 room_id: &RoomId,
110) -> Result<TimelineEvent> {
111 let decryption_settings =
112 DecryptionSettings { sender_device_trust_requirement: e2ee.decryption_trust_requirement };
113
114 let event = match e2ee
115 .olm_machine
116 .expect("An `OlmMachine` is expected")
117 .try_decrypt_room_event(event.cast_ref(), room_id, &decryption_settings)
118 .await?
119 {
120 RoomEventDecryptionResult::Decrypted(decrypted) => {
121 let event = TimelineEvent::from_decrypted(decrypted, None);
123
124 if let Ok(sync_timeline_event) = event.raw().deserialize() {
125 verification::process_if_relevant(&sync_timeline_event, e2ee.clone(), room_id)
126 .await?;
127 }
128
129 event
130 }
131
132 RoomEventDecryptionResult::UnableToDecrypt(utd_info) => {
133 TimelineEvent::from_utd(event.clone(), utd_info)
134 }
135 };
136
137 Ok(event)
138}
139
140#[cfg(test)]
141mod tests {
142 use matrix_sdk_test::{
143 async_test, event_factory::EventFactory, JoinedRoomBuilder, SyncResponseBuilder,
144 };
145 use ruma::{event_id, events::room::member::MembershipState, room_id, user_id};
146
147 use super::{decrypt_from_rooms, Context, E2EE};
148 use crate::{room::RoomInfoNotableUpdateReasons, test_utils::logged_in_base_client};
149
150 #[async_test]
151 async fn test_when_there_are_no_latest_encrypted_events_decrypting_them_does_nothing() {
152 let user_id = user_id!("@u:u.to");
154 let room_id = room_id!("!r:u.to");
155
156 let client = logged_in_base_client(Some(user_id)).await;
157
158 let mut sync_builder = SyncResponseBuilder::new();
159
160 let response = sync_builder
161 .add_joined_room(
162 JoinedRoomBuilder::new(room_id).add_timeline_event(
163 EventFactory::new()
164 .member(user_id)
165 .display_name("Alice")
166 .membership(MembershipState::Join)
167 .event_id(event_id!("$1")),
168 ),
169 )
170 .build_sync_response();
171 client.receive_sync_response(response).await.unwrap();
172
173 let room = client.get_room(room_id).expect("Just-created room not found!");
174
175 assert!(room.latest_encrypted_events().is_empty());
177 assert!(room.latest_event().is_none());
178
179 let mut context = Context::default();
181
182 decrypt_from_rooms(
183 &mut context,
184 vec![room.clone()],
185 E2EE::new(
186 client.olm_machine().await.as_ref(),
187 client.decryption_trust_requirement,
188 client.handle_verification_events,
189 ),
190 )
191 .await
192 .unwrap();
193
194 assert!(room.latest_encrypted_events().is_empty());
196 assert!(room.latest_event().is_none());
197 assert!(context.state_changes.room_infos.is_empty());
198 assert!(!context
199 .room_info_notable_updates
200 .get(room_id)
201 .copied()
202 .unwrap_or_default()
203 .contains(RoomInfoNotableUpdateReasons::LATEST_EVENT));
204 }
205}