1use std::{
117 borrow::Cow,
118 collections::{BTreeMap, BTreeSet},
119 pin::{Pin, pin},
120 sync::Weak,
121};
122
123use as_variant::as_variant;
124use futures_core::Stream;
125use futures_util::{StreamExt, future::try_join_all};
126#[cfg(feature = "e2e-encryption")]
127use matrix_sdk_base::deserialized_responses::UnableToDecryptReason;
128#[cfg(doc)]
129use matrix_sdk_base::{BaseClient, crypto::OlmMachine};
130use matrix_sdk_base::{
131 crypto::{
132 store::types::{RoomKeyInfo, RoomKeyWithheldInfo},
133 types::events::room::encrypted::EncryptedEvent,
134 },
135 deserialized_responses::{DecryptedRoomEvent, TimelineEvent, TimelineEventKind},
136 locks::Mutex,
137 task_monitor::BackgroundTaskHandle,
138 timer,
139};
140#[cfg(doc)]
141use matrix_sdk_common::deserialized_responses::EncryptionInfo;
142use ruma::{
143 OwnedEventId, OwnedRoomId, RoomId,
144 events::{AnySyncTimelineEvent, room::encrypted::OriginalSyncRoomEncryptedEvent},
145 push::Action,
146 serde::Raw,
147};
148use tokio::sync::{
149 broadcast::{self, Sender},
150 mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel},
151};
152use tokio_stream::wrappers::{
153 BroadcastStream, UnboundedReceiverStream, errors::BroadcastStreamRecvError,
154};
155use tracing::{info, instrument, trace, warn};
156
157#[cfg(doc)]
158use super::RoomEventCache;
159use super::{
160 EventCache, EventCacheError, EventCacheInner, EventsOrigin, RoomEventCacheGenericUpdate,
161 RoomEventCacheUpdate, TimelineVectorDiffs,
162 caches::{
163 EventLocation, event_linked_chunk::EventLinkedChunk, room::RoomEventCacheLinkedChunkUpdate,
164 },
165};
166use crate::{Client, Result, Room, encryption::backups::BackupState, room::PushContext};
167
168type SessionId<'a> = &'a str;
169type OwnedSessionId = String;
170
171type EventIdAndUtd = (OwnedEventId, Raw<AnySyncTimelineEvent>);
172type EventIdAndEvent = (OwnedEventId, DecryptedRoomEvent);
173
174#[derive(Clone)]
175pub(super) struct ResolvedUtd {
176 pub event_id: OwnedEventId,
177 decrypted_event: DecryptedRoomEvent,
178 actions: Option<Vec<Action>>,
179}
180
181#[derive(Clone)]
182pub(super) enum MaybeResolvedEvent {
183 NotYet(ResolvedUtd),
184 Resolved(TimelineEvent),
185}
186
187impl MaybeResolvedEvent {
188 pub fn try_resolve_event(self, mut unresolved_event: TimelineEvent) -> Self {
189 match self {
190 Self::NotYet(resolved_utd) => {
191 if matches!(unresolved_event.kind, TimelineEventKind::UnableToDecrypt { .. })
204 || unresolved_event.encryption_info()
205 != Some(&resolved_utd.decrypted_event.encryption_info)
206 {
207 unresolved_event.kind =
208 TimelineEventKind::Decrypted(resolved_utd.decrypted_event);
209
210 if let Some(actions) = resolved_utd.actions {
211 unresolved_event.set_push_actions(actions);
212 }
213
214 Self::Resolved(unresolved_event)
216 } else {
217 Self::NotYet(resolved_utd)
218 }
219 }
220
221 Self::Resolved(event) => Self::Resolved(event),
222 }
223 }
224
225 pub fn as_resolved(&self) -> Option<&TimelineEvent> {
226 if let Self::Resolved(event) = self { Some(event) } else { None }
227 }
228}
229
230pub(super) trait TryResolveEvents {
233 fn try_resolve_events(
234 &self,
235 event_linked_chunk: &EventLinkedChunk,
236 ) -> Cow<'_, [MaybeResolvedEvent]>;
237}
238
239impl TryResolveEvents for [MaybeResolvedEvent] {
240 fn try_resolve_events(
241 &self,
242 event_linked_chunk: &EventLinkedChunk,
243 ) -> Cow<'_, [MaybeResolvedEvent]> {
244 let mut new_resolved_events = Cow::Borrowed(self);
245
246 for (nth, resolved_event) in self.iter().enumerate() {
247 match resolved_event {
248 MaybeResolvedEvent::NotYet(resolved_utd) => {
249 if let Some((_location, event)) =
254 event_linked_chunk.find_event(&resolved_utd.event_id)
255 {
256 let new_resolved_event = MaybeResolvedEvent::NotYet(resolved_utd.clone())
257 .try_resolve_event(event);
258
259 if matches!(new_resolved_event, MaybeResolvedEvent::Resolved(_)) {
260 unsafe {
267 *new_resolved_events.to_mut().get_unchecked_mut(nth) =
268 new_resolved_event;
269 }
270 }
271 }
272 }
273
274 MaybeResolvedEvent::Resolved(_event) => {
275 }
277 }
278 }
279
280 new_resolved_events
281 }
282}
283
284#[derive(Debug, Clone)]
287pub struct DecryptionRetryRequest {
288 pub room_id: OwnedRoomId,
290 pub utd_session_ids: BTreeSet<OwnedSessionId>,
292 pub refresh_info_session_ids: BTreeSet<OwnedSessionId>,
295}
296
297#[derive(Debug, Clone)]
299pub enum RedecryptorReport {
300 ResolvedUtds {
302 room_id: OwnedRoomId,
304 events: BTreeSet<OwnedEventId>,
306 },
307 Lagging,
310 BackupAvailable,
315}
316
317pub(super) struct RedecryptorChannels {
318 utd_reporter: Sender<RedecryptorReport>,
319 pub(super) decryption_request_sender: UnboundedSender<DecryptionRetryRequest>,
320 pub(super) decryption_request_receiver:
321 Mutex<Option<UnboundedReceiver<DecryptionRetryRequest>>>,
322}
323
324impl RedecryptorChannels {
325 pub(super) fn new() -> Self {
326 let (utd_reporter, _) = broadcast::channel(100);
327 let (decryption_request_sender, decryption_request_receiver) = unbounded_channel();
328
329 Self {
330 utd_reporter,
331 decryption_request_sender,
332 decryption_request_receiver: Mutex::new(Some(decryption_request_receiver)),
333 }
334 }
335}
336
337fn filter_timeline_event_to_utd(
342 event: TimelineEvent,
343) -> Option<(OwnedEventId, Raw<AnySyncTimelineEvent>)> {
344 let event_id = event.event_id().map(ToOwned::to_owned);
345
346 let event = as_variant!(event.kind, TimelineEventKind::UnableToDecrypt { event, .. } => event);
349 event_id.zip(event)
352}
353
354fn filter_timeline_event_to_decrypted(
360 event: TimelineEvent,
361) -> Option<(OwnedEventId, DecryptedRoomEvent)> {
362 let event_id = event.event_id().map(ToOwned::to_owned);
363
364 let event = as_variant!(event.kind, TimelineEventKind::Decrypted(event) => event);
365 event_id.zip(event)
368}
369
370impl EventCacheInner {
371 async fn all_encrypted_events(
379 &self,
380 room_id: &RoomId,
381 session_id: SessionId<'_>,
382 ) -> Result<Vec<EventIdAndUtd>, EventCacheError> {
383 let caches = self.all_caches_for_room(room_id).await?;
384
385 Ok(caches
386 .all_events_of_type(Some("m.room.encrypted"), Some(session_id))
387 .await?
388 .filter_map(filter_timeline_event_to_utd)
389 .collect())
390 }
391
392 async fn all_in_memory_encrypted_events(&self) -> BTreeMap<OwnedRoomId, Vec<EventIdAndUtd>> {
395 let mut utds = BTreeMap::new();
396
397 for (room_id, caches) in self.by_room.read().await.iter() {
398 let room_utds: Vec<_> = caches
399 .all_in_memory_events()
400 .await
401 .into_iter()
402 .flatten()
403 .filter_map(filter_timeline_event_to_utd)
404 .collect();
405
406 utds.insert(room_id.to_owned(), room_utds);
407 }
408
409 utds
410 }
411
412 async fn all_decrypted_events(
413 &self,
414 room_id: &RoomId,
415 session_id: SessionId<'_>,
416 ) -> Result<Vec<EventIdAndEvent>, EventCacheError> {
417 let caches = self.all_caches_for_room(room_id).await?;
418
419 Ok(caches
420 .all_events_of_type(None, Some(session_id))
421 .await?
422 .filter_map(filter_timeline_event_to_decrypted)
423 .collect())
424 }
425
426 async fn all_in_memory_decrypted_events(&self) -> BTreeMap<OwnedRoomId, Vec<EventIdAndEvent>> {
427 let mut decrypted_events = BTreeMap::new();
428
429 for (room_id, caches) in self.by_room.read().await.iter() {
430 let room_utds: Vec<_> = caches
431 .all_in_memory_events()
432 .await
433 .into_iter()
434 .flatten()
435 .filter_map(filter_timeline_event_to_decrypted)
436 .collect();
437
438 decrypted_events.insert(room_id.to_owned(), room_utds);
439 }
440
441 decrypted_events
442 }
443
444 #[instrument(skip_all, fields(room_id))]
456 async fn on_resolved_utds(
457 &self,
458 room_id: &RoomId,
459 resolved_utds: Vec<ResolvedUtd>,
460 ) -> Result<(), EventCacheError> {
461 if resolved_utds.is_empty() {
462 trace!("No events were redecrypted or updated, nothing to replace");
463 return Ok(());
464 }
465
466 timer!("Resolving UTDs");
467
468 let event_ids: BTreeSet<_> =
469 resolved_utds.iter().map(|resolved_utd| resolved_utd.event_id.clone()).collect();
470
471 let all_caches = self.all_caches_for_room(room_id).await?;
472 let mut maybe_resolved_events = Vec::with_capacity(resolved_utds.len());
473
474 {
491 let room_cache = &all_caches.room;
492 let mut state = room_cache.state().write().await?;
493
494 let mut maybe_resolved_in_memory_events = Vec::new();
495
496 for resolved_utd in resolved_utds {
497 if let Some((location, event)) = state.find_event(&resolved_utd.event_id).await? {
499 let maybe_resolved_event =
500 MaybeResolvedEvent::NotYet(resolved_utd).try_resolve_event(event);
501
502 if matches!(location, EventLocation::Memory(_)) {
505 maybe_resolved_in_memory_events.push(maybe_resolved_event.clone());
506 }
507
508 maybe_resolved_events.push(maybe_resolved_event);
511 } else {
512 maybe_resolved_events.push(MaybeResolvedEvent::NotYet(resolved_utd));
516 }
517 }
518
519 state
521 .save_events(
522 maybe_resolved_events
523 .iter()
524 .filter_map(|resolved_event| resolved_event.as_resolved())
525 .cloned(),
526 )
527 .await?;
528
529 let timeline_event_diffs = state
531 .replace_in_memory_utds(&maybe_resolved_in_memory_events)
532 .await?
533 .unwrap_or_default();
534
535 if !timeline_event_diffs.is_empty() {
536 state.update_sender.send(
537 RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs {
538 diffs: timeline_event_diffs,
539 origin: EventsOrigin::Cache,
540 }),
541 Some(RoomEventCacheGenericUpdate { room_id: room_id.to_owned() }),
542 );
543 }
544 }
545
546 {
548 for (thread_id, thread_cache) in try_join_all(
557 all_caches.threads.read().await.iter().map(|(thread_id, thread_cache)| async {
558 Result::<_, EventCacheError>::Ok(
559 thread_cache
563 .replace_in_memory_utds(&maybe_resolved_events)
564 .await?
565 .then(|| (thread_id.clone(), thread_cache.clone())),
566 )
567 }),
568 )
569 .await?
570 .into_iter()
571 .flatten()
573 {
574 let new_thread_summary = thread_cache.update_thread_summary().await?;
575
576 all_caches.room.update_thread_summary(&thread_id, new_thread_summary)?;
577 }
578 }
579
580 if let Some(pinned_events_cache) = all_caches.pinned_events.get() {
582 pinned_events_cache.replace_in_memory_utds(&maybe_resolved_events).await?;
583 }
584
585 {
587 try_join_all(all_caches.event_focused.read().await.values().map(
593 |event_focused_cache| {
594 event_focused_cache.replace_in_memory_utds(&maybe_resolved_events)
595 },
596 ))
597 .await?;
598 }
599
600 let report =
601 RedecryptorReport::ResolvedUtds { room_id: room_id.to_owned(), events: event_ids };
602 let _ = self.redecryption_channels.utd_reporter.send(report);
603
604 Ok(())
605 }
606
607 async fn decrypt_event(
609 &self,
610 room_id: &RoomId,
611 room: Option<&Room>,
612 push_context: Option<&PushContext>,
613 event: &Raw<EncryptedEvent>,
614 ) -> Option<(DecryptedRoomEvent, Option<Vec<Action>>)> {
615 if let Some(room) = room {
616 match room
617 .decrypt_event(
618 event.cast_ref_unchecked::<OriginalSyncRoomEncryptedEvent>(),
619 push_context,
620 )
621 .await
622 {
623 Ok(maybe_decrypted) => {
624 let actions = maybe_decrypted.push_actions().map(|a| a.to_vec());
625
626 if let TimelineEventKind::Decrypted(decrypted) = maybe_decrypted.kind {
627 Some((decrypted, actions))
628 } else {
629 warn!(
630 "Failed to redecrypt an event despite receiving a room key or request to redecrypt"
631 );
632 None
633 }
634 }
635 Err(e) => {
636 warn!(
637 "Failed to redecrypt an event despite receiving a room key or request to redecrypt {e:?}"
638 );
639 None
640 }
641 }
642 } else {
643 let client = self.client().ok()?;
644 let machine = client.olm_machine().await;
645 let machine = machine.as_ref()?;
646
647 match machine.decrypt_room_event(event, room_id, client.decryption_settings()).await {
648 Ok(decrypted) => Some((decrypted, None)),
649 Err(e) => {
650 warn!(
651 "Failed to redecrypt an event despite receiving a room key or a request to redecrypt {e:?}"
652 );
653 None
654 }
655 }
656 }
657 }
658
659 #[instrument(skip_all, fields(room_id, session_id))]
662 async fn retry_decryption(
663 &self,
664 room_id: &RoomId,
665 session_id: SessionId<'_>,
666 ) -> Result<(), EventCacheError> {
667 let events = self.all_encrypted_events(room_id, session_id).await?;
669 self.retry_decryption_for_events(room_id, events).await
670 }
671
672 #[instrument(skip_all, fields(updates.linked_chunk_id))]
674 async fn retry_decryption_for_event_cache_updates(
675 &self,
676 updates: RoomEventCacheLinkedChunkUpdate,
677 ) -> Result<(), EventCacheError> {
678 let room_id = updates.linked_chunk_id.room_id();
679 let events: Vec<_> = updates
680 .updates
681 .into_iter()
682 .flat_map(|updates| updates.into_items())
683 .filter_map(filter_timeline_event_to_utd)
684 .collect();
685
686 self.retry_decryption_for_events(room_id, events).await
687 }
688
689 async fn retry_decryption_for_in_memory_events(&self) {
690 let utds = self.all_in_memory_encrypted_events().await;
691
692 for (room_id, utds) in utds.into_iter() {
693 if let Err(e) = self.retry_decryption_for_events(&room_id, utds).await {
694 warn!(%room_id, "Failed to redecrypt in-memory events {e:?}");
695 }
696 }
697 }
698
699 #[instrument(skip_all, fields(room_id, session_id))]
701 async fn retry_decryption_for_events(
702 &self,
703 room_id: &RoomId,
704 events: Vec<EventIdAndUtd>,
705 ) -> Result<(), EventCacheError> {
706 trace!("Retrying to decrypt");
707
708 if events.is_empty() {
709 trace!("No relevant events found.");
710 return Ok(());
711 }
712
713 let room = self.client().ok().and_then(|client| client.get_room(room_id));
714 let push_context =
715 if let Some(room) = &room { room.push_context().await.ok().flatten() } else { None };
716
717 let mut decrypted_events = Vec::with_capacity(events.len());
719
720 for (event_id, event) in events {
721 if let Some((decrypted_event, actions)) = self
725 .decrypt_event(
726 room_id,
727 room.as_ref(),
728 push_context.as_ref(),
729 event.cast_ref_unchecked(),
730 )
731 .await
732 {
733 decrypted_events.push(ResolvedUtd { event_id, decrypted_event, actions });
734 }
735 }
736
737 if !decrypted_events.is_empty() && tracing::level_enabled!(tracing::Level::TRACE) {
738 let event_ids: BTreeSet<_> =
739 decrypted_events.iter().map(|resolved_utd| &resolved_utd.event_id).collect();
740
741 trace!(?event_ids, "Successfully redecrypted events");
742 }
743
744 self.on_resolved_utds(room_id, decrypted_events).await?;
747
748 Ok(())
749 }
750
751 async fn update_encryption_info_for_events(
753 &self,
754 room: &Room,
755 events: Vec<EventIdAndEvent>,
756 ) -> Result<(), EventCacheError> {
757 let mut updated_events = Vec::with_capacity(events.len());
759
760 for (event_id, mut event) in events {
761 if let Some(session_id) = event.encryption_info.session_id() {
762 let new_encryption_info =
763 room.get_encryption_info(session_id, &event.encryption_info.sender).await;
764
765 if let Some(new_encryption_info) = new_encryption_info
768 && event.encryption_info != new_encryption_info
769 {
770 event.encryption_info = new_encryption_info;
771 updated_events.push(ResolvedUtd {
772 event_id,
773 decrypted_event: event,
774 actions: None,
775 });
776 }
777 }
778 }
779
780 if !updated_events.is_empty() && tracing::level_enabled!(tracing::Level::TRACE) {
781 let event_ids: BTreeSet<_> =
782 updated_events.iter().map(|resolved_utd| &resolved_utd.event_id).collect();
783
784 trace!(?event_ids, "Replacing the encryption info of some events");
785 }
786
787 self.on_resolved_utds(room.room_id(), updated_events).await
788 }
789
790 #[instrument(skip_all, fields(room_id, session_id))]
791 async fn update_encryption_info(
792 &self,
793 room_id: &RoomId,
794 session_id: SessionId<'_>,
795 ) -> Result<(), EventCacheError> {
796 trace!("Updating encryption info");
797
798 let Ok(client) = self.client() else {
799 return Ok(());
800 };
801
802 let Some(room) = client.get_room(room_id) else {
803 return Ok(());
804 };
805
806 let events = self.all_decrypted_events(room_id, session_id).await?;
808
809 if events.is_empty() {
810 trace!("No relevant events found.");
811 return Ok(());
812 }
813
814 self.update_encryption_info_for_events(&room, events).await
816 }
817
818 async fn retry_update_encryption_info_for_in_memory_events(&self) {
819 let decrypted_events = self.all_in_memory_decrypted_events().await;
820
821 for (room_id, events) in decrypted_events.into_iter() {
822 let Some(room) = self.client().ok().and_then(|c| c.get_room(&room_id)) else {
823 continue;
824 };
825
826 if let Err(e) = self.update_encryption_info_for_events(&room, events).await {
827 warn!(
828 %room_id,
829 "Failed to replace the encryption info for in-memory events {e:?}"
830 );
831 }
832 }
833 }
834
835 async fn retry_in_memory_events(&self) {
845 self.retry_decryption_for_in_memory_events().await;
846 self.retry_update_encryption_info_for_in_memory_events().await;
847 }
848}
849
850impl EventCache {
851 pub fn request_decryption(&self, request: DecryptionRetryRequest) {
891 let _ =
892 self.inner.redecryption_channels.decryption_request_sender.send(request).inspect_err(
893 |_| warn!("Requesting a decryption while the redecryption task has been shut down"),
894 );
895 }
896
897 pub fn subscribe_to_decryption_reports(
948 &self,
949 ) -> impl Stream<Item = Result<RedecryptorReport, BroadcastStreamRecvError>> {
950 BroadcastStream::new(self.inner.redecryption_channels.utd_reporter.subscribe())
951 }
952}
953
954async fn send_report_and_retry_memory_events(
955 cache: &Weak<EventCacheInner>,
956 report: RedecryptorReport,
957) -> Result<(), ()> {
958 let Some(cache) = cache.upgrade() else {
959 return Err(());
960 };
961
962 cache.retry_in_memory_events().await;
963 let _ = cache.redecryption_channels.utd_reporter.send(report);
964
965 Ok(())
966}
967
968pub(crate) struct Redecryptor {
975 _task: BackgroundTaskHandle,
976}
977
978impl Redecryptor {
979 pub(super) fn new(
984 client: &Client,
985 cache: Weak<EventCacheInner>,
986 receiver: UnboundedReceiver<DecryptionRetryRequest>,
987 linked_chunk_update_sender: &Sender<RoomEventCacheLinkedChunkUpdate>,
988 ) -> Self {
989 let linked_chunk_stream = BroadcastStream::new(linked_chunk_update_sender.subscribe());
990 let backup_state_stream = client.encryption().backups().state_stream();
991
992 let task = client
993 .task_monitor()
994 .spawn_infinite_task("event_cache::redecryptor", async {
995 let request_redecryption_stream = UnboundedReceiverStream::new(receiver);
996
997 Self::listen_for_room_keys_task(
998 cache,
999 request_redecryption_stream,
1000 linked_chunk_stream,
1001 backup_state_stream,
1002 )
1003 .await;
1004 })
1005 .abort_on_drop();
1006
1007 Self { _task: task }
1008 }
1009
1010 async fn subscribe_to_room_key_stream(
1015 cache: &Weak<EventCacheInner>,
1016 ) -> Option<(
1017 impl Stream<Item = Result<Vec<RoomKeyInfo>, BroadcastStreamRecvError>>,
1018 impl Stream<Item = Vec<RoomKeyWithheldInfo>>,
1019 )> {
1020 let event_cache = cache.upgrade()?;
1021 let client = event_cache.client().ok()?;
1022 let machine = client.olm_machine().await;
1023
1024 machine.as_ref().map(|m| {
1025 (m.store().room_keys_received_stream(), m.store().room_keys_withheld_received_stream())
1026 })
1027 }
1028
1029 async fn redecryption_loop(
1030 cache: &Weak<EventCacheInner>,
1031 decryption_request_stream: &mut Pin<&mut impl Stream<Item = DecryptionRetryRequest>>,
1032 events_stream: &mut Pin<
1033 &mut impl Stream<Item = Result<RoomEventCacheLinkedChunkUpdate, BroadcastStreamRecvError>>,
1034 >,
1035 backup_state_stream: &mut Pin<
1036 &mut impl Stream<Item = Result<BackupState, BroadcastStreamRecvError>>,
1037 >,
1038 ) -> bool {
1039 let Some((room_key_stream, withheld_stream)) =
1040 Self::subscribe_to_room_key_stream(cache).await
1041 else {
1042 return false;
1043 };
1044
1045 let mut room_key_stream = pin!(room_key_stream);
1046 let mut withheld_stream = pin!(withheld_stream);
1047
1048 loop {
1049 tokio::select! {
1050 Some(request) = decryption_request_stream.next() => {
1054 let Some(cache) = cache.upgrade() else {
1055 break false;
1056 };
1057
1058 trace!(?request, "Received a redecryption request");
1059
1060 for session_id in request.utd_session_ids {
1061 let _ = cache
1062 .retry_decryption(&request.room_id, &session_id)
1063 .await
1064 .inspect_err(|e| warn!("Error redecrypting after an explicit request was received {e:?}"));
1065 }
1066
1067 for session_id in request.refresh_info_session_ids {
1068 let _ = cache.update_encryption_info(&request.room_id, &session_id).await.inspect_err(|e|
1069 warn!(
1070 room_id = %request.room_id,
1071 session_id = session_id,
1072 "Unable to update the encryption info {e:?}",
1073 ));
1074 }
1075 }
1076 room_keys = room_key_stream.next() => {
1079 match room_keys {
1080 Some(Ok(room_keys)) => {
1081 let Some(cache) = cache.upgrade() else {
1086 break false;
1087 };
1088
1089 trace!(?room_keys, "Received new room keys");
1090
1091 for key in &room_keys {
1092 let _ = cache
1093 .retry_decryption(&key.room_id, &key.session_id)
1094 .await
1095 .inspect_err(|e| warn!("Error redecrypting {e:?}"));
1096 }
1097
1098 for key in room_keys {
1099 let _ = cache.update_encryption_info(&key.room_id, &key.session_id).await.inspect_err(|e|
1100 warn!(
1101 room_id = %key.room_id,
1102 session_id = key.session_id,
1103 "Unable to update the encryption info {e:?}",
1104 ));
1105 }
1106 },
1107 Some(Err(_)) => {
1108 warn!("The room key stream lagged, reporting the lag to our listeners");
1116
1117 if send_report_and_retry_memory_events(cache, RedecryptorReport::Lagging).await.is_err() {
1118 break false;
1119 }
1120 },
1121 None => {
1125 break true;
1126 }
1127 }
1128 }
1129 withheld_info = withheld_stream.next() => {
1130 match withheld_info {
1131 Some(infos) => {
1132 let Some(cache) = cache.upgrade() else {
1133 break false;
1134 };
1135
1136 trace!(?infos, "Received new withheld infos");
1137
1138 for RoomKeyWithheldInfo { room_id, session_id, .. } in &infos {
1139 let _ = cache.update_encryption_info(room_id, session_id).await.inspect_err(|e|
1140 warn!(
1141 room_id = %room_id,
1142 session_id = session_id,
1143 "Unable to update the encryption info {e:?}",
1144 ));
1145 }
1146 }
1147 None => break true,
1150 }
1151 }
1152 Some(event_updates) = events_stream.next() => {
1157 match event_updates {
1158 Ok(updates) => {
1159 let Some(cache) = cache.upgrade() else {
1160 break false;
1161 };
1162
1163 let linked_chunk_id = updates.linked_chunk_id.to_owned();
1164
1165 let _ = cache.retry_decryption_for_event_cache_updates(updates).await.inspect_err(|e|
1166 warn!(
1167 %linked_chunk_id,
1168 "Unable to handle UTDs from event cache updates {e:?}",
1169 )
1170 );
1171 }
1172 Err(_) => {
1173 if send_report_and_retry_memory_events(cache, RedecryptorReport::Lagging).await.is_err() {
1174 break false;
1175 }
1176 }
1177 }
1178 }
1179 Some(backup_state_update) = backup_state_stream.next() => {
1180 match backup_state_update {
1181 Ok(state) => {
1182 match state {
1183 BackupState::Unknown |
1184 BackupState::Creating |
1185 BackupState::Enabling |
1186 BackupState::Resuming |
1187 BackupState::Downloading |
1188 BackupState::Disabling => {
1189 }
1193 BackupState::Enabled => {
1194 if send_report_and_retry_memory_events(cache, RedecryptorReport::BackupAvailable).await.is_err() {
1201 break false;
1202 }
1203 }
1204 }
1205 }
1206 Err(_) => {
1207 if send_report_and_retry_memory_events(cache, RedecryptorReport::Lagging).await.is_err() {
1208 break false;
1209 }
1210 }
1211 }
1212 }
1213 else => break false,
1214 }
1215 }
1216 }
1217
1218 async fn listen_for_room_keys_task(
1219 cache: Weak<EventCacheInner>,
1220 decryption_request_stream: UnboundedReceiverStream<DecryptionRetryRequest>,
1221 events_stream: BroadcastStream<RoomEventCacheLinkedChunkUpdate>,
1222 backup_state_stream: impl Stream<Item = Result<BackupState, BroadcastStreamRecvError>>,
1223 ) {
1224 let mut decryption_request_stream = pin!(decryption_request_stream);
1228 let mut events_stream = pin!(events_stream);
1229 let mut backup_state_stream = pin!(backup_state_stream);
1230
1231 while Self::redecryption_loop(
1232 &cache,
1233 &mut decryption_request_stream,
1234 &mut events_stream,
1235 &mut backup_state_stream,
1236 )
1237 .await
1238 {
1239 info!("Regenerating the re-decryption streams");
1240
1241 if send_report_and_retry_memory_events(&cache, RedecryptorReport::Lagging)
1245 .await
1246 .is_err()
1247 {
1248 break;
1249 }
1250 }
1251
1252 info!("Shutting down the event cache redecryptor");
1253 }
1254}
1255
1256pub(super) async fn try_decrypt_in_place(event: &mut TimelineEvent, room: Option<&Room>) {
1259 if let TimelineEventKind::UnableToDecrypt { utd_info, .. } = &event.kind
1260 && let Some(room) = room
1261 && utd_info.reason == UnableToDecryptReason::Unknown
1262 {
1263 match room
1264 .decrypt_event(event.raw().cast_ref_unchecked::<OriginalSyncRoomEncryptedEvent>(), None)
1269 .await
1270 {
1271 Ok(decrypted) => *event = decrypted,
1272 Err(e) => warn!(
1273 "Failed to decrypt a bundled thread event we haven't tried to decrypt yet {e:?}"
1274 ),
1275 }
1276 }
1277}
1278
1279#[cfg(not(target_family = "wasm"))]
1280#[cfg(test)]
1281mod tests {
1282 use std::{
1283 assert_matches,
1284 collections::BTreeSet,
1285 sync::{
1286 Arc,
1287 atomic::{AtomicBool, Ordering},
1288 },
1289 time::Duration,
1290 };
1291
1292 use async_trait::async_trait;
1293 use eyeball_im::VectorDiff;
1294 use futures_util::future::join_all;
1295 use matrix_sdk_base::{
1296 cross_process_lock::CrossProcessLockGeneration,
1297 crypto::types::events::room::encrypted::EncryptedToDeviceEvent,
1298 deserialized_responses::{TimelineEventKind, UnableToDecryptReason, VerificationState},
1299 event_cache::{
1300 Event, Gap,
1301 store::{EventCacheStore, EventCacheStoreError, MemoryStore},
1302 thread::ThreadInfo,
1303 },
1304 linked_chunk::{
1305 ChunkIdentifier, ChunkIdentifierGenerator, ChunkMetadata, LinkedChunkId, Position,
1306 RawChunk, Update,
1307 },
1308 locks::Mutex,
1309 sleep::sleep,
1310 store::StoreConfig,
1311 };
1312 use matrix_sdk_common::{cross_process_lock::CrossProcessLockConfig, executor::spawn};
1313 use matrix_sdk_test::{
1314 JoinedRoomBuilder, SyncResponseBuilder, async_test, event_factory::EventFactory,
1315 };
1316 use ruma::{
1317 EventId, OwnedEventId, RoomId, RoomVersionId, UserId, device_id, event_id,
1318 events::{
1319 AnySyncTimelineEvent, MessageLikeEventContent,
1320 relation::{RelationType, Thread},
1321 room::message::{
1322 AddMentions, ReplyMetadata, ReplyWithinThread, RoomMessageEventContent,
1323 },
1324 },
1325 room_id,
1326 serde::Raw,
1327 user_id,
1328 };
1329 use serde_json::json;
1330 use strass::assert_let;
1331 use tokio::sync::oneshot::{self, Sender};
1332 use tracing::{Instrument, info};
1333 use wiremock::{Request, Respond, ResponseTemplate};
1334
1335 use crate::{
1336 Client, assert_let_timeout,
1337 encryption::EncryptionSettings,
1338 event_cache::{
1339 DecryptionRetryRequest, RoomEventCacheGenericUpdate, RoomEventCacheUpdate,
1340 TimelineVectorDiffs,
1341 },
1342 test_utils::mocks::MatrixMockServer,
1343 };
1344
1345 #[derive(Debug, Clone)]
1350 struct DelayingStore {
1351 memory_store: MemoryStore,
1352 delaying: Arc<AtomicBool>,
1353 foo: Arc<Mutex<Option<Sender<()>>>>,
1354 }
1355
1356 impl DelayingStore {
1357 fn new() -> Self {
1358 Self {
1359 memory_store: MemoryStore::new(),
1360 delaying: AtomicBool::new(true).into(),
1361 foo: Arc::new(Mutex::new(None)),
1362 }
1363 }
1364
1365 async fn stop_delaying(&self) {
1366 let (sender, receiver) = oneshot::channel();
1367
1368 {
1369 *self.foo.lock() = Some(sender);
1370 }
1371
1372 self.delaying.store(false, Ordering::SeqCst);
1373
1374 receiver.await.expect("We should be able to receive a response")
1375 }
1376 }
1377
1378 #[cfg_attr(target_family = "wasm", async_trait(?Send))]
1379 #[cfg_attr(not(target_family = "wasm"), async_trait)]
1380 impl EventCacheStore for DelayingStore {
1381 type Error = EventCacheStoreError;
1382
1383 async fn close(&self) -> Result<(), EventCacheStoreError> {
1384 self.memory_store.close().await
1385 }
1386
1387 async fn reopen(&self) -> Result<(), EventCacheStoreError> {
1388 self.memory_store.reopen().await
1389 }
1390
1391 async fn try_take_leased_lock(
1392 &self,
1393 lease_duration_ms: u32,
1394 key: &str,
1395 holder: &str,
1396 ) -> Result<Option<CrossProcessLockGeneration>, Self::Error> {
1397 self.memory_store.try_take_leased_lock(lease_duration_ms, key, holder).await
1398 }
1399
1400 async fn handle_linked_chunk_updates(
1401 &self,
1402 linked_chunk_id: LinkedChunkId<'_>,
1403 updates: Vec<Update<Event, Gap>>,
1404 ) -> Result<(), Self::Error> {
1405 while self.delaying.load(Ordering::SeqCst) {
1411 sleep(Duration::from_millis(10)).await;
1412 }
1413
1414 let sender = self.foo.lock().take();
1415 let ret = self.memory_store.handle_linked_chunk_updates(linked_chunk_id, updates).await;
1416
1417 if let Some(sender) = sender {
1418 sender.send(()).expect("We should be able to notify the other side that we're done with the storage operation");
1419 }
1420
1421 ret
1422 }
1423
1424 async fn load_all_chunks(
1425 &self,
1426 linked_chunk_id: LinkedChunkId<'_>,
1427 ) -> Result<Vec<RawChunk<Event, Gap>>, Self::Error> {
1428 self.memory_store.load_all_chunks(linked_chunk_id).await
1429 }
1430
1431 async fn load_all_chunks_metadata(
1432 &self,
1433 linked_chunk_id: LinkedChunkId<'_>,
1434 ) -> Result<Vec<ChunkMetadata>, Self::Error> {
1435 self.memory_store.load_all_chunks_metadata(linked_chunk_id).await
1436 }
1437
1438 async fn load_last_chunk(
1439 &self,
1440 linked_chunk_id: LinkedChunkId<'_>,
1441 ) -> Result<(Option<RawChunk<Event, Gap>>, ChunkIdentifierGenerator), Self::Error> {
1442 self.memory_store.load_last_chunk(linked_chunk_id).await
1443 }
1444
1445 async fn load_previous_chunk(
1446 &self,
1447 linked_chunk_id: LinkedChunkId<'_>,
1448 before_chunk_identifier: ChunkIdentifier,
1449 ) -> Result<Option<RawChunk<Event, Gap>>, Self::Error> {
1450 self.memory_store.load_previous_chunk(linked_chunk_id, before_chunk_identifier).await
1451 }
1452
1453 async fn load_thread_info(
1454 &self,
1455 room_id: &RoomId,
1456 thread_id: &EventId,
1457 insert_default_if_missing: bool,
1458 ) -> Result<Option<ThreadInfo>, Self::Error> {
1459 self.memory_store.load_thread_info(room_id, thread_id, insert_default_if_missing).await
1460 }
1461
1462 async fn update_thread_info(
1463 &self,
1464 room_id: &RoomId,
1465 thread_id: &EventId,
1466 thread_info: &ThreadInfo,
1467 ) -> Result<(), Self::Error> {
1468 self.memory_store.update_thread_info(room_id, thread_id, thread_info).await
1469 }
1470
1471 async fn clear_all_events(&self, room_id: Option<&RoomId>) -> Result<(), Self::Error> {
1472 self.memory_store.clear_all_events(room_id).await
1473 }
1474
1475 async fn filter_duplicated_events(
1476 &self,
1477 linked_chunk_id: LinkedChunkId<'_>,
1478 events: Vec<OwnedEventId>,
1479 ) -> Result<Vec<(OwnedEventId, Position)>, Self::Error> {
1480 self.memory_store.filter_duplicated_events(linked_chunk_id, events).await
1481 }
1482
1483 async fn find_event(
1484 &self,
1485 room_id: &RoomId,
1486 event_id: &EventId,
1487 ) -> Result<Option<Event>, Self::Error> {
1488 self.memory_store.find_event(room_id, event_id).await
1489 }
1490
1491 async fn find_event_relations(
1492 &self,
1493 room_id: &RoomId,
1494 event_id: &EventId,
1495 filters: Option<&[RelationType]>,
1496 ) -> Result<Vec<(Event, Option<Position>)>, Self::Error> {
1497 self.memory_store.find_event_relations(room_id, event_id, filters).await
1498 }
1499
1500 async fn get_room_events(
1501 &self,
1502 room_id: &RoomId,
1503 event_type: Option<&str>,
1504 session_id: Option<&str>,
1505 ) -> Result<Vec<Event>, Self::Error> {
1506 self.memory_store.get_room_events(room_id, event_type, session_id).await
1507 }
1508
1509 async fn save_event(&self, room_id: &RoomId, event: Event) -> Result<(), Self::Error> {
1510 self.memory_store.save_event(room_id, event).await
1511 }
1512
1513 async fn optimize(&self) -> Result<(), Self::Error> {
1514 self.memory_store.optimize().await
1515 }
1516
1517 async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1518 self.memory_store.get_size().await
1519 }
1520 }
1521
1522 async fn set_up_clients(
1523 room_id: &RoomId,
1524 alice_enables_cross_signing: bool,
1525 use_delayed_store: bool,
1526 ) -> (Client, Client, MatrixMockServer, Option<DelayingStore>) {
1527 let alice_span = tracing::info_span!("alice");
1528 let bob_span = tracing::info_span!("bob");
1529
1530 let alice_user_id = user_id!("@alice:localhost");
1531 let alice_device_id = device_id!("ALICEDEVICE");
1532 let bob_user_id = user_id!("@bob:localhost");
1533 let bob_device_id = device_id!("BOBDEVICE");
1534
1535 let matrix_mock_server = MatrixMockServer::new().await;
1536 matrix_mock_server.mock_crypto_endpoints_preset().await;
1537
1538 let encryption_settings = EncryptionSettings {
1539 auto_enable_cross_signing: alice_enables_cross_signing,
1540 ..Default::default()
1541 };
1542
1543 let alice = matrix_mock_server
1546 .client_builder_for_crypto_end_to_end(alice_user_id, alice_device_id)
1547 .on_builder(|builder| {
1548 builder
1549 .with_enable_share_history_on_invite(true)
1550 .with_encryption_settings(encryption_settings)
1551 })
1552 .build()
1553 .instrument(alice_span.clone())
1554 .await;
1555
1556 let encryption_settings =
1557 EncryptionSettings { auto_enable_cross_signing: true, ..Default::default() };
1558
1559 let (store_config, store) = if use_delayed_store {
1560 let store = DelayingStore::new();
1561
1562 (
1563 StoreConfig::new(CrossProcessLockConfig::multi_process(
1564 "delayed_store_event_cache_test",
1565 ))
1566 .event_cache_store(store.clone()),
1567 Some(store),
1568 )
1569 } else {
1570 (
1571 StoreConfig::new(CrossProcessLockConfig::multi_process(
1572 "normal_store_event_cache_test",
1573 )),
1574 None,
1575 )
1576 };
1577
1578 let bob = matrix_mock_server
1579 .client_builder_for_crypto_end_to_end(bob_user_id, bob_device_id)
1580 .on_builder(|builder| {
1581 builder
1582 .with_enable_share_history_on_invite(true)
1583 .with_encryption_settings(encryption_settings)
1584 .store_config(store_config)
1585 })
1586 .build()
1587 .instrument(bob_span.clone())
1588 .await;
1589
1590 matrix_mock_server.exchange_e2ee_identities(&alice, &bob).await;
1592
1593 let event_factory = EventFactory::new().room(room_id).sender(alice_user_id);
1594
1595 let room_builder = JoinedRoomBuilder::new(room_id)
1597 .add_state_event(event_factory.create(alice_user_id, RoomVersionId::V1))
1598 .add_state_event(event_factory.room_encryption());
1599
1600 matrix_mock_server
1601 .mock_sync()
1602 .ok_and_run(&alice, |builder| {
1603 builder.add_joined_room(room_builder.clone());
1604 })
1605 .instrument(alice_span)
1606 .await;
1607
1608 matrix_mock_server
1609 .mock_sync()
1610 .ok_and_run(&bob, |builder| {
1611 builder.add_joined_room(room_builder);
1612 })
1613 .instrument(bob_span)
1614 .await;
1615
1616 let member_factory = EventFactory::new().room(room_id);
1619 matrix_mock_server
1620 .mock_get_members()
1621 .ok(vec![
1622 member_factory.member(alice_user_id).into_raw(),
1623 member_factory.member(bob_user_id).into_raw(),
1624 ])
1625 .mount()
1626 .await;
1627
1628 (alice, bob, matrix_mock_server, store)
1629 }
1630
1631 #[async_test]
1632 async fn test_redecryptor() {
1633 let room_id = room_id!("!test:localhost");
1634
1635 let (alice, bob, matrix_mock_server, _) = set_up_clients(room_id, true, false).await;
1636
1637 let (event, room_key) = send_encrypted(
1638 &matrix_mock_server,
1639 &alice,
1640 room_id,
1641 event_id!("$some_id"),
1642 RoomMessageEventContent::text_plain("It's a secret to everybody"),
1643 )
1644 .await;
1645
1646 let event_cache = bob.event_cache();
1649 let (room_cache, _) = event_cache
1650 .room(room_id)
1651 .await
1652 .expect("We should be able to get to the event cache for a specific room");
1653
1654 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1655 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1656
1657 bob.inner
1660 .base_client
1661 .regenerate_olm(None)
1662 .await
1663 .expect("We should be able to regenerate the Olm machine");
1664
1665 sync_room(
1667 &matrix_mock_server,
1668 &bob,
1669 JoinedRoomBuilder::new(room_id).add_timeline_event(event),
1670 )
1671 .await;
1672
1673 assert_let_timeout!(
1676 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1677 subscriber.recv()
1678 );
1679
1680 assert_eq!(diffs.len(), 1);
1683 assert_let!(VectorDiff::Append { values } = &diffs[0]);
1684 assert_eq!(values.len(), 1);
1685 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1686
1687 assert_let_timeout!(
1688 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1689 );
1690 assert_eq!(expected_room_id, room_id);
1691 assert!(generic_stream.is_empty());
1692
1693 sync_room_keys(&matrix_mock_server, &bob, &[room_key]).await;
1695
1696 assert_let_timeout!(
1698 Duration::from_secs(1),
1699 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1700 subscriber.recv()
1701 );
1702
1703 assert_eq!(diffs.len(), 1);
1705 assert_let!(VectorDiff::Set { index, value } = &diffs[0]);
1706 assert_eq!(*index, 0);
1707 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1708
1709 assert_let_timeout!(
1710 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1711 );
1712 assert_eq!(expected_room_id, room_id);
1713 assert!(generic_stream.is_empty());
1714 }
1715
1716 #[async_test]
1717 async fn test_redecryptor_updating_encryption_info() {
1718 let bob_span = tracing::info_span!("bob");
1719
1720 let room_id = room_id!("!test:localhost");
1721
1722 let (alice, bob, matrix_mock_server, _) = set_up_clients(room_id, false, false).await;
1723
1724 let (event, room_key) = send_encrypted(
1725 &matrix_mock_server,
1726 &alice,
1727 room_id,
1728 event_id!("$some_id"),
1729 RoomMessageEventContent::text_plain("It's a secret to everybody"),
1730 )
1731 .await;
1732
1733 let event_cache = bob.event_cache();
1736 let (room_cache, _) = event_cache
1737 .room(room_id)
1738 .instrument(bob_span.clone())
1739 .await
1740 .expect("We should be able to get to the event cache for a specific room");
1741
1742 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1743 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1744
1745 sync_room(
1747 &matrix_mock_server,
1748 &bob,
1749 JoinedRoomBuilder::new(room_id).add_timeline_event(event),
1750 )
1751 .instrument(bob_span.clone())
1752 .await;
1753
1754 assert_let_timeout!(
1757 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1758 subscriber.recv()
1759 );
1760
1761 assert_eq!(diffs.len(), 1);
1764 assert_let!(VectorDiff::Append { values } = &diffs[0]);
1765 assert_eq!(values.len(), 1);
1766 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1767
1768 assert_let_timeout!(
1769 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1770 );
1771 assert_eq!(expected_room_id, room_id);
1772 assert!(generic_stream.is_empty());
1773
1774 sync_room_keys(&matrix_mock_server, &bob, &[room_key]).instrument(bob_span.clone()).await;
1776
1777 assert_let_timeout!(
1779 Duration::from_secs(1),
1780 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1781 subscriber.recv()
1782 );
1783
1784 assert_eq!(diffs.len(), 1);
1786 assert_let!(VectorDiff::Set { index: 0, value } = &diffs[0]);
1787 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1788
1789 let encryption_info = value.encryption_info().unwrap();
1790 assert_matches!(&encryption_info.verification_state, VerificationState::Unverified(_));
1791
1792 assert_let_timeout!(
1793 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1794 );
1795 assert_eq!(expected_room_id, room_id);
1796 assert!(generic_stream.is_empty());
1797
1798 let session_id = encryption_info.session_id().unwrap().to_owned();
1799 let alice_user_id = alice.user_id().unwrap();
1800
1801 alice
1803 .encryption()
1804 .bootstrap_cross_signing(None)
1805 .await
1806 .expect("Alice should be able to create the cross-signing keys");
1807
1808 bob.update_tracked_users_for_testing([alice_user_id]).instrument(bob_span.clone()).await;
1809 matrix_mock_server
1810 .mock_sync()
1811 .ok_and_run(&bob, |builder| {
1812 builder.add_change_device(alice_user_id);
1813 })
1814 .instrument(bob_span.clone())
1815 .await;
1816
1817 bob.event_cache().request_decryption(DecryptionRetryRequest {
1818 room_id: room_id.into(),
1819 utd_session_ids: BTreeSet::new(),
1820 refresh_info_session_ids: BTreeSet::from([session_id]),
1821 });
1822
1823 assert_let_timeout!(
1826 Duration::from_secs(1),
1827 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1828 subscriber.recv()
1829 );
1830
1831 assert_eq!(diffs.len(), 1);
1832 assert_let!(VectorDiff::Set { index: 0, value } = &diffs[0]);
1833 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1834 let encryption_info = value.encryption_info().unwrap();
1835
1836 assert_matches!(
1837 &encryption_info.verification_state,
1838 VerificationState::Unverified(_),
1839 "The event should now know about the identity but still be unverified"
1840 );
1841
1842 assert_let_timeout!(
1843 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1844 );
1845 assert_eq!(expected_room_id, room_id);
1846 assert!(generic_stream.is_empty());
1847 }
1848
1849 #[async_test]
1850 async fn test_event_is_redecrypted_even_if_key_arrives_while_event_processing() {
1851 let room_id = room_id!("!test:localhost");
1852
1853 let (alice, bob, matrix_mock_server, delayed_store) =
1854 set_up_clients(room_id, true, true).await;
1855
1856 let delayed_store = delayed_store.unwrap();
1857
1858 let (event, room_key) = send_encrypted(
1859 &matrix_mock_server,
1860 &alice,
1861 room_id,
1862 event_id!("$some_id"),
1863 RoomMessageEventContent::text_plain("It's a secret to everybody"),
1864 )
1865 .await;
1866
1867 let event_cache = bob.event_cache();
1868
1869 let (room_cache, _) = event_cache
1871 .room(room_id)
1872 .await
1873 .expect("We should be able to get to the event cache for a specific room");
1874
1875 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1876 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1877
1878 struct Responder<'a> {
1880 sync_response_builder: Mutex<(usize, SyncResponseBuilder)>,
1881 room_id: &'a RoomId,
1882 event: Raw<AnySyncTimelineEvent>,
1883 room_key: Raw<EncryptedToDeviceEvent>,
1884 }
1885
1886 impl<'a> Responder<'a> {
1887 fn new(
1888 room_id: &'a RoomId,
1889 event: Raw<AnySyncTimelineEvent>,
1890 room_key: Raw<EncryptedToDeviceEvent>,
1891 ) -> Self {
1892 Self {
1893 sync_response_builder: Mutex::new((0, SyncResponseBuilder::new())),
1894 room_id,
1895 event,
1896 room_key,
1897 }
1898 }
1899 }
1900
1901 impl<'a> Respond for Responder<'a> {
1902 fn respond(&self, _request: &Request) -> ResponseTemplate {
1903 let (nth_sync, sync_response_builder) = &mut *self.sync_response_builder.lock();
1904
1905 match nth_sync {
1906 0 => {
1908 *nth_sync = 1;
1909 ResponseTemplate::new(200).set_body_json(
1910 sync_response_builder
1911 .add_joined_room(
1912 JoinedRoomBuilder::new(self.room_id)
1913 .add_timeline_event(self.event.clone()),
1914 )
1915 .build_json_sync_response(),
1916 )
1917 }
1918
1919 1 => {
1921 *nth_sync = 2;
1922 ResponseTemplate::new(200).set_body_json(
1923 sync_response_builder
1924 .add_to_device_event(self.room_key.deserialize_as().unwrap())
1925 .build_json_sync_response(),
1926 )
1927 }
1928
1929 _ => panic!("`/sync` is called once too much"),
1930 }
1931 }
1932 }
1933
1934 let mock = matrix_mock_server
1935 .mock_sync()
1936 .respond_with(Responder::new(room_id, event, room_key))
1937 .mount_as_scoped()
1938 .await;
1939
1940 let sync_room = spawn({
1941 let bob = bob.clone();
1942
1943 async move {
1946 let _ = bob.sync_once(Default::default()).await.unwrap();
1947 }
1948 });
1949
1950 let sync_room_keys = spawn({
1951 let bob = bob.clone();
1952
1953 async move {
1957 sleep(Duration::from_secs(1)).await;
1959
1960 let _ = bob.sync_once(Default::default()).await.unwrap();
1961
1962 sleep(Duration::from_millis(100)).await;
1964 }
1965 });
1966
1967 let delay = spawn({
1968 async move {
1971 sleep(Duration::from_secs(2)).await;
1972 info!("Stopping the delay");
1973 delayed_store.stop_delaying().await;
1974 }
1975 });
1976
1977 assert!(
1978 join_all([sync_room, sync_room_keys, delay]).await.into_iter().all(|res| res.is_ok()),
1979 "all tasks should succeed"
1980 );
1981
1982 drop(mock);
1983
1984 assert_let_timeout!(
1990 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1991 subscriber.recv()
1992 );
1993
1994 assert_eq!(diffs.len(), 1);
1997 assert_let!(VectorDiff::Append { values } = &diffs[0]);
1998 assert_eq!(values.len(), 1);
1999 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
2000
2001 assert_let_timeout!(
2003 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
2004 );
2005 assert_eq!(expected_room_id, room_id);
2006
2007 assert_let_timeout!(
2009 Duration::from_secs(1),
2010 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
2011 subscriber.recv()
2012 );
2013
2014 assert_eq!(diffs.len(), 1);
2016 assert_let!(VectorDiff::Set { index, value } = &diffs[0]);
2017 assert_eq!(*index, 0);
2018 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
2019
2020 assert_let_timeout!(
2022 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
2023 );
2024 assert_eq!(expected_room_id, room_id);
2025 assert!(generic_stream.is_empty());
2026 }
2027
2028 async fn send_encrypted(
2034 matrix_mock_server: &MatrixMockServer,
2035 client: &Client,
2036 room_id: &RoomId,
2037 event_id: &EventId,
2038 content: impl MessageLikeEventContent,
2039 ) -> (Raw<AnySyncTimelineEvent>, Raw<EncryptedToDeviceEvent>) {
2040 let user_id = client.user_id().unwrap();
2041 let room = client.get_room(room_id).unwrap();
2042
2043 let (event_receiver, mock) =
2044 matrix_mock_server.mock_room_send().ok_with_capture(event_id, user_id);
2045 let _send_guard = mock.mock_once().mount_as_scoped().await;
2048 let (_to_device_guard, room_key) =
2049 matrix_mock_server.mock_capture_put_to_device(user_id).await;
2050
2051 room.send(content).await.unwrap();
2052
2053 (event_receiver.await.unwrap(), room_key.await)
2054 }
2055
2056 fn with_bundled_thread(
2058 root: &Raw<AnySyncTimelineEvent>,
2059 child: &Raw<AnySyncTimelineEvent>,
2060 ) -> Raw<AnySyncTimelineEvent> {
2061 let mut root: serde_json::Value = root.deserialize_as().unwrap();
2062 root["unsigned"] = json!({
2063 "m.relations": {
2064 "m.thread": {
2065 "latest_event": child,
2066 "count": 1,
2067 "current_user_participated": false,
2068 },
2069 },
2070 });
2071 Raw::new(&root).unwrap().cast_unchecked()
2072 }
2073
2074 async fn sync_room_keys(
2076 matrix_mock_server: &MatrixMockServer,
2077 client: &Client,
2078 room_keys: &[Raw<EncryptedToDeviceEvent>],
2079 ) {
2080 matrix_mock_server
2081 .mock_sync()
2082 .ok_and_run(client, |builder| {
2083 for room_key in room_keys {
2084 builder.add_to_device_event(room_key.deserialize_as().unwrap());
2085 }
2086 })
2087 .await;
2088 sleep(Duration::from_millis(100)).await;
2090 }
2091
2092 async fn sync_room(
2094 matrix_mock_server: &MatrixMockServer,
2095 client: &Client,
2096 room: JoinedRoomBuilder,
2097 ) {
2098 matrix_mock_server
2099 .mock_sync()
2100 .ok_and_run(client, |builder| {
2101 builder.add_joined_room(room);
2102 })
2103 .await;
2104 sleep(Duration::from_millis(200)).await;
2106 }
2107
2108 async fn get_cached_timeline_event_kind(
2111 client: &Client,
2112 room_id: &RoomId,
2113 event_id: &EventId,
2114 ) -> Option<TimelineEventKind> {
2115 client
2116 .get_room(room_id)
2117 .unwrap()
2118 .load_or_fetch_event(event_id, None)
2119 .await
2120 .map(|event| event.kind)
2121 .ok()
2123 }
2124
2125 fn make_thread_reply_event_content(
2127 root_id: &EventId,
2128 sender: &UserId,
2129 ) -> RoomMessageEventContent {
2130 RoomMessageEventContent::text_plain("In the thread").make_for_thread(
2131 ReplyMetadata::new(
2132 root_id,
2133 sender,
2134 Some(&Thread::plain(root_id.to_owned(), root_id.to_owned())),
2135 ),
2136 ReplyWithinThread::No,
2137 AddMentions::No,
2138 )
2139 }
2140
2141 #[async_test]
2144 async fn test_thread_reply_in_timeline_after_key() {
2145 let room_id = room_id!("!test:localhost");
2146 let root_id = event_id!("$root");
2147 let reply_id = event_id!("$reply");
2148
2149 let (alice, bob, server, _) = set_up_clients(room_id, true, false).await;
2151 let alice_id = alice.user_id().unwrap();
2152
2153 let (root, root_key) = send_encrypted(
2155 &server,
2156 &alice,
2157 room_id,
2158 root_id,
2159 RoomMessageEventContent::text_plain("Root"),
2160 )
2161 .await;
2162
2163 alice.get_room(room_id).unwrap().discard_room_key().await.unwrap();
2165
2166 let (reply, reply_key) = send_encrypted(
2169 &server,
2170 &alice,
2171 room_id,
2172 reply_id,
2173 make_thread_reply_event_content(root_id, alice_id),
2174 )
2175 .await;
2176
2177 sync_room_keys(&server, &bob, &[root_key, reply_key]).await;
2179 sync_room(&server, &bob, JoinedRoomBuilder::new(room_id).add_timeline_bulk([root, reply]))
2180 .await;
2181
2182 assert_matches!(
2185 get_cached_timeline_event_kind(&bob, room_id, root_id).await,
2186 Some(TimelineEventKind::Decrypted { .. })
2187 );
2188 assert_matches!(
2189 get_cached_timeline_event_kind(&bob, room_id, reply_id).await,
2190 Some(TimelineEventKind::Decrypted { .. })
2191 );
2192 }
2193
2194 #[async_test]
2197 async fn test_bundled_thread_reply_after_key_decryptable_root() {
2198 let room_id = room_id!("!test:localhost");
2199 let root_id = event_id!("$root");
2200 let reply_id = event_id!("$reply");
2201
2202 let (alice, bob, server, _) = set_up_clients(room_id, true, false).await;
2204 let alice_id = alice.user_id().unwrap();
2205
2206 let (root, root_key) = send_encrypted(
2208 &server,
2209 &alice,
2210 room_id,
2211 root_id,
2212 RoomMessageEventContent::text_plain("Root"),
2213 )
2214 .await;
2215
2216 alice.get_room(room_id).unwrap().discard_room_key().await.unwrap();
2218
2219 let (reply, reply_key) = send_encrypted(
2222 &server,
2223 &alice,
2224 room_id,
2225 reply_id,
2226 make_thread_reply_event_content(root_id, alice_id),
2227 )
2228 .await;
2229
2230 sync_room_keys(&server, &bob, &[root_key, reply_key]).await;
2233 sync_room(
2234 &server,
2235 &bob,
2236 JoinedRoomBuilder::new(room_id)
2238 .add_timeline_event(with_bundled_thread(&root, &reply))
2239 .set_timeline_limited()
2240 .set_timeline_prev_batch("prev_batch"),
2241 )
2242 .await;
2243
2244 assert_matches!(
2247 get_cached_timeline_event_kind(&bob, room_id, root_id).await,
2248 Some(TimelineEventKind::Decrypted { .. })
2249 );
2250 assert_matches!(
2251 get_cached_timeline_event_kind(&bob, room_id, reply_id).await,
2252 Some(TimelineEventKind::Decrypted { .. })
2253 );
2254 }
2255
2256 #[async_test]
2259 async fn test_bundled_thread_reply_key_arrives_later() {
2260 let room_id = room_id!("!test:localhost");
2261 let root_id = event_id!("$root");
2262 let reply_id = event_id!("$reply");
2263
2264 let (alice, bob, server, _) = set_up_clients(room_id, true, false).await;
2266 let alice_id = alice.user_id().unwrap();
2267
2268 let (root, root_key) = send_encrypted(
2270 &server,
2271 &alice,
2272 room_id,
2273 root_id,
2274 RoomMessageEventContent::text_plain("Root"),
2275 )
2276 .await;
2277
2278 alice.get_room(room_id).unwrap().discard_room_key().await.unwrap();
2280
2281 let (reply, reply_key) = send_encrypted(
2284 &server,
2285 &alice,
2286 room_id,
2287 reply_id,
2288 make_thread_reply_event_content(root_id, alice_id),
2289 )
2290 .await;
2291
2292 sync_room_keys(&server, &bob, &[root_key]).await;
2295 sync_room(
2296 &server,
2297 &bob,
2298 JoinedRoomBuilder::new(room_id)
2300 .add_timeline_event(with_bundled_thread(&root, &reply))
2301 .set_timeline_limited()
2302 .set_timeline_prev_batch("prev_batch"),
2303 )
2304 .await;
2305
2306 assert_matches!(
2309 get_cached_timeline_event_kind(&bob, room_id, root_id).await,
2310 Some(TimelineEventKind::Decrypted { .. })
2311 );
2312 assert_let!(
2315 Some(TimelineEventKind::UnableToDecrypt { utd_info, .. }) =
2316 get_cached_timeline_event_kind(&bob, room_id, reply_id).await
2317 );
2318 assert_matches!(
2319 utd_info.reason,
2320 UnableToDecryptReason::MissingMegolmSession { withheld_code: None }
2321 );
2322
2323 sync_room_keys(&server, &bob, &[reply_key]).await;
2325
2326 assert_matches!(
2328 get_cached_timeline_event_kind(&bob, room_id, reply_id).await,
2329 Some(TimelineEventKind::Decrypted { .. })
2330 );
2331 }
2332
2333 #[async_test]
2336 async fn test_bundled_thread_reply_root_key_arrives_later() {
2337 let room_id = room_id!("!test:localhost");
2338 let root_id = event_id!("$root");
2339 let reply_id = event_id!("$reply");
2340
2341 let (alice, bob, server, _) = set_up_clients(room_id, true, false).await;
2343 let alice_id = alice.user_id().unwrap();
2344
2345 let (root, root_key) = send_encrypted(
2347 &server,
2348 &alice,
2349 room_id,
2350 root_id,
2351 RoomMessageEventContent::text_plain("Root"),
2352 )
2353 .await;
2354
2355 alice.get_room(room_id).unwrap().discard_room_key().await.unwrap();
2357
2358 let (reply, reply_key) = send_encrypted(
2361 &server,
2362 &alice,
2363 room_id,
2364 reply_id,
2365 make_thread_reply_event_content(root_id, alice_id),
2366 )
2367 .await;
2368
2369 sync_room_keys(&server, &bob, &[reply_key]).await;
2372 sync_room(
2373 &server,
2374 &bob,
2375 JoinedRoomBuilder::new(room_id)
2377 .add_timeline_event(with_bundled_thread(&root, &reply))
2378 .set_timeline_limited()
2379 .set_timeline_prev_batch("prev_batch"),
2380 )
2381 .await;
2382
2383 assert_matches!(
2390 get_cached_timeline_event_kind(&bob, room_id, root_id).await,
2391 Some(TimelineEventKind::UnableToDecrypt { .. })
2392 );
2393 assert_matches!(
2394 get_cached_timeline_event_kind(&bob, room_id, reply_id).await,
2395 Some(TimelineEventKind::Decrypted { .. })
2396 );
2397
2398 sync_room_keys(&server, &bob, &[root_key]).await;
2400
2401 assert_matches!(
2404 get_cached_timeline_event_kind(&bob, room_id, root_id).await,
2405 Some(TimelineEventKind::Decrypted { .. })
2406 );
2407 assert_matches!(
2408 get_cached_timeline_event_kind(&bob, room_id, reply_id).await,
2409 Some(TimelineEventKind::Decrypted { .. })
2410 );
2411 }
2412}