1use std::{
117 borrow::Cow,
118 collections::{BTreeMap, BTreeSet},
119 pin::Pin,
120 sync::Weak,
121};
122
123use as_variant::as_variant;
124use futures_core::Stream;
125use futures_util::{StreamExt, future::try_join_all, pin_mut};
126#[cfg(doc)]
127use matrix_sdk_base::{BaseClient, crypto::OlmMachine};
128use matrix_sdk_base::{
129 crypto::{
130 store::types::{RoomKeyInfo, RoomKeyWithheldInfo},
131 types::events::room::encrypted::EncryptedEvent,
132 },
133 deserialized_responses::{DecryptedRoomEvent, TimelineEvent, TimelineEventKind},
134 locks::Mutex,
135 task_monitor::BackgroundTaskHandle,
136 timer,
137};
138#[cfg(doc)]
139use matrix_sdk_common::deserialized_responses::EncryptionInfo;
140use ruma::{
141 OwnedEventId, OwnedRoomId, RoomId,
142 events::{AnySyncTimelineEvent, room::encrypted::OriginalSyncRoomEncryptedEvent},
143 push::Action,
144 serde::Raw,
145};
146use tokio::sync::{
147 broadcast::{self, Sender},
148 mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel},
149};
150use tokio_stream::wrappers::{
151 BroadcastStream, UnboundedReceiverStream, errors::BroadcastStreamRecvError,
152};
153use tracing::{info, instrument, trace, warn};
154
155#[cfg(doc)]
156use super::RoomEventCache;
157use super::{
158 EventCache, EventCacheError, EventCacheInner, EventsOrigin, RoomEventCacheGenericUpdate,
159 RoomEventCacheUpdate, TimelineVectorDiffs,
160 caches::{
161 EventLocation, event_linked_chunk::EventLinkedChunk, room::RoomEventCacheLinkedChunkUpdate,
162 },
163};
164use crate::{Client, Result, Room, encryption::backups::BackupState, room::PushContext};
165
166type SessionId<'a> = &'a str;
167type OwnedSessionId = String;
168
169type EventIdAndUtd = (OwnedEventId, Raw<AnySyncTimelineEvent>);
170type EventIdAndEvent = (OwnedEventId, DecryptedRoomEvent);
171
172#[derive(Clone)]
173pub(super) struct ResolvedUtd {
174 pub event_id: OwnedEventId,
175 decrypted_event: DecryptedRoomEvent,
176 actions: Option<Vec<Action>>,
177}
178
179#[derive(Clone)]
180pub(super) enum MaybeResolvedEvent {
181 NotYet(ResolvedUtd),
182 Resolved(TimelineEvent),
183}
184
185impl MaybeResolvedEvent {
186 pub fn try_resolve_event(self, mut unresolved_event: TimelineEvent) -> Self {
187 match self {
188 Self::NotYet(resolved_utd) => {
189 if matches!(unresolved_event.kind, TimelineEventKind::UnableToDecrypt { .. })
200 || unresolved_event.encryption_info()
201 != Some(&resolved_utd.decrypted_event.encryption_info)
202 {
203 unresolved_event.kind =
204 TimelineEventKind::Decrypted(resolved_utd.decrypted_event);
205
206 if let Some(actions) = resolved_utd.actions {
207 unresolved_event.set_push_actions(actions);
208 }
209
210 Self::Resolved(unresolved_event)
212 } else {
213 Self::NotYet(resolved_utd)
214 }
215 }
216
217 Self::Resolved(event) => Self::Resolved(event),
218 }
219 }
220
221 pub fn as_resolved(&self) -> Option<&TimelineEvent> {
222 if let Self::Resolved(event) = self { Some(event) } else { None }
223 }
224}
225
226pub(super) trait TryResolveEvents {
229 fn try_resolve_events(
230 &self,
231 event_linked_chunk: &EventLinkedChunk,
232 ) -> Cow<'_, [MaybeResolvedEvent]>;
233}
234
235impl TryResolveEvents for [MaybeResolvedEvent] {
236 fn try_resolve_events(
237 &self,
238 event_linked_chunk: &EventLinkedChunk,
239 ) -> Cow<'_, [MaybeResolvedEvent]> {
240 let mut new_resolved_events = Cow::Borrowed(self);
241
242 for (nth, resolved_event) in self.iter().enumerate() {
243 match resolved_event {
244 MaybeResolvedEvent::NotYet(resolved_utd) => {
245 if let Some((_location, event)) =
249 event_linked_chunk.find_event(&resolved_utd.event_id)
250 {
251 let new_resolved_event = MaybeResolvedEvent::NotYet(resolved_utd.clone())
252 .try_resolve_event(event);
253
254 if matches!(new_resolved_event, MaybeResolvedEvent::Resolved(_)) {
255 unsafe {
261 *new_resolved_events.to_mut().get_unchecked_mut(nth) =
262 new_resolved_event;
263 }
264 }
265 }
266 }
267
268 MaybeResolvedEvent::Resolved(_event) => {
269 }
271 }
272 }
273
274 new_resolved_events
275 }
276}
277
278#[derive(Debug, Clone)]
281pub struct DecryptionRetryRequest {
282 pub room_id: OwnedRoomId,
284 pub utd_session_ids: BTreeSet<OwnedSessionId>,
286 pub refresh_info_session_ids: BTreeSet<OwnedSessionId>,
289}
290
291#[derive(Debug, Clone)]
293pub enum RedecryptorReport {
294 ResolvedUtds {
296 room_id: OwnedRoomId,
298 events: BTreeSet<OwnedEventId>,
300 },
301 Lagging,
304 BackupAvailable,
309}
310
311pub(super) struct RedecryptorChannels {
312 utd_reporter: Sender<RedecryptorReport>,
313 pub(super) decryption_request_sender: UnboundedSender<DecryptionRetryRequest>,
314 pub(super) decryption_request_receiver:
315 Mutex<Option<UnboundedReceiver<DecryptionRetryRequest>>>,
316}
317
318impl RedecryptorChannels {
319 pub(super) fn new() -> Self {
320 let (utd_reporter, _) = broadcast::channel(100);
321 let (decryption_request_sender, decryption_request_receiver) = unbounded_channel();
322
323 Self {
324 utd_reporter,
325 decryption_request_sender,
326 decryption_request_receiver: Mutex::new(Some(decryption_request_receiver)),
327 }
328 }
329}
330
331fn filter_timeline_event_to_utd(
336 event: TimelineEvent,
337) -> Option<(OwnedEventId, Raw<AnySyncTimelineEvent>)> {
338 let event_id = event.event_id().map(ToOwned::to_owned);
339
340 let event = as_variant!(event.kind, TimelineEventKind::UnableToDecrypt { event, .. } => event);
343 event_id.zip(event)
346}
347
348fn filter_timeline_event_to_decrypted(
354 event: TimelineEvent,
355) -> Option<(OwnedEventId, DecryptedRoomEvent)> {
356 let event_id = event.event_id().map(ToOwned::to_owned);
357
358 let event = as_variant!(event.kind, TimelineEventKind::Decrypted(event) => event);
359 event_id.zip(event)
362}
363
364impl EventCache {
365 async fn all_encrypted_events(
373 &self,
374 room_id: &RoomId,
375 session_id: SessionId<'_>,
376 ) -> Result<Vec<EventIdAndUtd>, EventCacheError> {
377 let caches = self.inner.all_caches_for_room(room_id).await?;
378
379 Ok(caches
380 .all_events_of_type(Some("m.room.encrypted"), Some(session_id))
381 .await?
382 .filter_map(filter_timeline_event_to_utd)
383 .collect())
384 }
385
386 async fn all_in_memory_encrypted_events(&self) -> BTreeMap<OwnedRoomId, Vec<EventIdAndUtd>> {
389 let mut utds = BTreeMap::new();
390
391 for (room_id, caches) in self.inner.by_room.read().await.iter() {
392 let room_utds: Vec<_> = caches
393 .all_in_memory_events()
394 .await
395 .into_iter()
396 .flatten()
397 .filter_map(filter_timeline_event_to_utd)
398 .collect();
399
400 utds.insert(room_id.to_owned(), room_utds);
401 }
402
403 utds
404 }
405
406 async fn all_decrypted_events(
407 &self,
408 room_id: &RoomId,
409 session_id: SessionId<'_>,
410 ) -> Result<Vec<EventIdAndEvent>, EventCacheError> {
411 let caches = self.inner.all_caches_for_room(room_id).await?;
412
413 Ok(caches
414 .all_events_of_type(None, Some(session_id))
415 .await?
416 .filter_map(filter_timeline_event_to_decrypted)
417 .collect())
418 }
419
420 async fn all_in_memory_decrypted_events(&self) -> BTreeMap<OwnedRoomId, Vec<EventIdAndEvent>> {
421 let mut decrypted_events = BTreeMap::new();
422
423 for (room_id, caches) in self.inner.by_room.read().await.iter() {
424 let room_utds: Vec<_> = caches
425 .all_in_memory_events()
426 .await
427 .into_iter()
428 .flatten()
429 .filter_map(filter_timeline_event_to_decrypted)
430 .collect();
431
432 decrypted_events.insert(room_id.to_owned(), room_utds);
433 }
434
435 decrypted_events
436 }
437
438 #[instrument(skip_all, fields(room_id))]
450 async fn on_resolved_utds(
451 &self,
452 room_id: &RoomId,
453 resolved_utds: Vec<ResolvedUtd>,
454 ) -> Result<(), EventCacheError> {
455 if resolved_utds.is_empty() {
456 trace!("No events were redecrypted or updated, nothing to replace");
457 return Ok(());
458 }
459
460 timer!("Resolving UTDs");
461
462 let event_ids: BTreeSet<_> =
463 resolved_utds.iter().map(|resolved_utd| resolved_utd.event_id.clone()).collect();
464
465 let all_caches = self.inner.all_caches_for_room(room_id).await?;
466 let mut maybe_resolved_events = Vec::with_capacity(resolved_utds.len());
467
468 {
483 let room_cache = &all_caches.room;
484 let mut state = room_cache.state().write().await?;
485
486 let mut maybe_resolved_in_memory_events = Vec::new();
487
488 for resolved_utd in resolved_utds {
489 if let Some((location, event)) = state.find_event(&resolved_utd.event_id).await? {
491 let maybe_resolved_event =
492 MaybeResolvedEvent::NotYet(resolved_utd).try_resolve_event(event);
493
494 if matches!(location, EventLocation::Memory(_)) {
496 maybe_resolved_in_memory_events.push(maybe_resolved_event.clone());
497 }
498
499 maybe_resolved_events.push(maybe_resolved_event);
501 } else {
502 maybe_resolved_events.push(MaybeResolvedEvent::NotYet(resolved_utd));
506 }
507 }
508
509 state
511 .save_events(
512 maybe_resolved_events
513 .iter()
514 .filter_map(|resolved_event| resolved_event.as_resolved())
515 .cloned(),
516 )
517 .await?;
518
519 let timeline_event_diffs = state
521 .replace_in_memory_utds(&maybe_resolved_in_memory_events)
522 .await?
523 .unwrap_or_default();
524
525 if !timeline_event_diffs.is_empty() {
526 state.update_sender.send(
527 RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs {
528 diffs: timeline_event_diffs,
529 origin: EventsOrigin::Cache,
530 }),
531 Some(RoomEventCacheGenericUpdate { room_id: room_id.to_owned() }),
532 );
533 }
534 }
535
536 {
538 for (thread_id, thread_cache) in try_join_all(
546 all_caches.threads.read().await.iter().map(|(thread_id, thread_cache)| async {
547 Result::<_, EventCacheError>::Ok(
548 thread_cache
551 .replace_in_memory_utds(&maybe_resolved_events)
552 .await?
553 .then(|| (thread_id.clone(), thread_cache.clone())),
554 )
555 }),
556 )
557 .await?
558 .into_iter()
559 .flatten()
561 {
562 let new_thread_summary =
563 thread_cache.state().read().await?.compute_thread_summary().await?;
564
565 all_caches.room.update_thread_summary(&thread_id, new_thread_summary).await?;
566 }
567 }
568
569 if let Some(pinned_events_cache) = all_caches.pinned_events.get() {
571 pinned_events_cache.replace_in_memory_utds(&maybe_resolved_events).await?;
572 }
573
574 {
576 try_join_all(all_caches.event_focused.read().await.values().map(
581 |event_focused_cache| {
582 event_focused_cache.replace_in_memory_utds(&maybe_resolved_events)
583 },
584 ))
585 .await?;
586 }
587
588 let report =
589 RedecryptorReport::ResolvedUtds { room_id: room_id.to_owned(), events: event_ids };
590 let _ = self.inner.redecryption_channels.utd_reporter.send(report);
591
592 Ok(())
593 }
594
595 async fn decrypt_event(
597 &self,
598 room_id: &RoomId,
599 room: Option<&Room>,
600 push_context: Option<&PushContext>,
601 event: &Raw<EncryptedEvent>,
602 ) -> Option<(DecryptedRoomEvent, Option<Vec<Action>>)> {
603 if let Some(room) = room {
604 match room
605 .decrypt_event(
606 event.cast_ref_unchecked::<OriginalSyncRoomEncryptedEvent>(),
607 push_context,
608 )
609 .await
610 {
611 Ok(maybe_decrypted) => {
612 let actions = maybe_decrypted.push_actions().map(|a| a.to_vec());
613
614 if let TimelineEventKind::Decrypted(decrypted) = maybe_decrypted.kind {
615 Some((decrypted, actions))
616 } else {
617 warn!(
618 "Failed to redecrypt an event despite receiving a room key or request to redecrypt"
619 );
620 None
621 }
622 }
623 Err(e) => {
624 warn!(
625 "Failed to redecrypt an event despite receiving a room key or request to redecrypt {e:?}"
626 );
627 None
628 }
629 }
630 } else {
631 let client = self.inner.client().ok()?;
632 let machine = client.olm_machine().await;
633 let machine = machine.as_ref()?;
634
635 match machine.decrypt_room_event(event, room_id, client.decryption_settings()).await {
636 Ok(decrypted) => Some((decrypted, None)),
637 Err(e) => {
638 warn!(
639 "Failed to redecrypt an event despite receiving a room key or a request to redecrypt {e:?}"
640 );
641 None
642 }
643 }
644 }
645 }
646
647 #[instrument(skip_all, fields(room_id, session_id))]
650 async fn retry_decryption(
651 &self,
652 room_id: &RoomId,
653 session_id: SessionId<'_>,
654 ) -> Result<(), EventCacheError> {
655 let events = self.all_encrypted_events(room_id, session_id).await?;
657 self.retry_decryption_for_events(room_id, events).await
658 }
659
660 #[instrument(skip_all, fields(updates.linked_chunk_id))]
662 async fn retry_decryption_for_event_cache_updates(
663 &self,
664 updates: RoomEventCacheLinkedChunkUpdate,
665 ) -> Result<(), EventCacheError> {
666 let room_id = updates.linked_chunk_id.room_id();
667 let events: Vec<_> = updates
668 .updates
669 .into_iter()
670 .flat_map(|updates| updates.into_items())
671 .filter_map(filter_timeline_event_to_utd)
672 .collect();
673
674 self.retry_decryption_for_events(room_id, events).await
675 }
676
677 async fn retry_decryption_for_in_memory_events(&self) {
678 let utds = self.all_in_memory_encrypted_events().await;
679
680 for (room_id, utds) in utds.into_iter() {
681 if let Err(e) = self.retry_decryption_for_events(&room_id, utds).await {
682 warn!(%room_id, "Failed to redecrypt in-memory events {e:?}");
683 }
684 }
685 }
686
687 #[instrument(skip_all, fields(room_id, session_id))]
689 async fn retry_decryption_for_events(
690 &self,
691 room_id: &RoomId,
692 events: Vec<EventIdAndUtd>,
693 ) -> Result<(), EventCacheError> {
694 trace!("Retrying to decrypt");
695
696 if events.is_empty() {
697 trace!("No relevant events found.");
698 return Ok(());
699 }
700
701 let room = self.inner.client().ok().and_then(|client| client.get_room(room_id));
702 let push_context =
703 if let Some(room) = &room { room.push_context().await.ok().flatten() } else { None };
704
705 let mut decrypted_events = Vec::with_capacity(events.len());
707
708 for (event_id, event) in events {
709 if let Some((decrypted_event, actions)) = self
712 .decrypt_event(
713 room_id,
714 room.as_ref(),
715 push_context.as_ref(),
716 event.cast_ref_unchecked(),
717 )
718 .await
719 {
720 decrypted_events.push(ResolvedUtd { event_id, decrypted_event, actions });
721 }
722 }
723
724 if !decrypted_events.is_empty() && tracing::level_enabled!(tracing::Level::TRACE) {
725 let event_ids: BTreeSet<_> =
726 decrypted_events.iter().map(|resolved_utd| &resolved_utd.event_id).collect();
727
728 trace!(?event_ids, "Successfully redecrypted events");
729 }
730
731 self.on_resolved_utds(room_id, decrypted_events).await?;
734
735 Ok(())
736 }
737
738 async fn update_encryption_info_for_events(
740 &self,
741 room: &Room,
742 events: Vec<EventIdAndEvent>,
743 ) -> Result<(), EventCacheError> {
744 let mut updated_events = Vec::with_capacity(events.len());
746
747 for (event_id, mut event) in events {
748 if let Some(session_id) = event.encryption_info.session_id() {
749 let new_encryption_info =
750 room.get_encryption_info(session_id, &event.encryption_info.sender).await;
751
752 if let Some(new_encryption_info) = new_encryption_info
754 && event.encryption_info != new_encryption_info
755 {
756 event.encryption_info = new_encryption_info;
757 updated_events.push(ResolvedUtd {
758 event_id,
759 decrypted_event: event,
760 actions: None,
761 });
762 }
763 }
764 }
765
766 if !updated_events.is_empty() && tracing::level_enabled!(tracing::Level::TRACE) {
767 let event_ids: BTreeSet<_> =
768 updated_events.iter().map(|resolved_utd| &resolved_utd.event_id).collect();
769
770 trace!(?event_ids, "Replacing the encryption info of some events");
771 }
772
773 self.on_resolved_utds(room.room_id(), updated_events).await
774 }
775
776 #[instrument(skip_all, fields(room_id, session_id))]
777 async fn update_encryption_info(
778 &self,
779 room_id: &RoomId,
780 session_id: SessionId<'_>,
781 ) -> Result<(), EventCacheError> {
782 trace!("Updating encryption info");
783
784 let Ok(client) = self.inner.client() else {
785 return Ok(());
786 };
787
788 let Some(room) = client.get_room(room_id) else {
789 return Ok(());
790 };
791
792 let events = self.all_decrypted_events(room_id, session_id).await?;
794
795 if events.is_empty() {
796 trace!("No relevant events found.");
797 return Ok(());
798 }
799
800 self.update_encryption_info_for_events(&room, events).await
802 }
803
804 async fn retry_update_encryption_info_for_in_memory_events(&self) {
805 let decrypted_events = self.all_in_memory_decrypted_events().await;
806
807 for (room_id, events) in decrypted_events.into_iter() {
808 let Some(room) = self.inner.client().ok().and_then(|c| c.get_room(&room_id)) else {
809 continue;
810 };
811
812 if let Err(e) = self.update_encryption_info_for_events(&room, events).await {
813 warn!(
814 %room_id,
815 "Failed to replace the encryption info for in-memory events {e:?}"
816 );
817 }
818 }
819 }
820
821 async fn retry_in_memory_events(&self) {
832 self.retry_decryption_for_in_memory_events().await;
833 self.retry_update_encryption_info_for_in_memory_events().await;
834 }
835
836 pub fn request_decryption(&self, request: DecryptionRetryRequest) {
877 let _ =
878 self.inner.redecryption_channels.decryption_request_sender.send(request).inspect_err(
879 |_| warn!("Requesting a decryption while the redecryption task has been shut down"),
880 );
881 }
882
883 pub fn subscribe_to_decryption_reports(
934 &self,
935 ) -> impl Stream<Item = Result<RedecryptorReport, BroadcastStreamRecvError>> {
936 BroadcastStream::new(self.inner.redecryption_channels.utd_reporter.subscribe())
937 }
938}
939
940#[inline(always)]
941fn upgrade_event_cache(cache: &Weak<EventCacheInner>) -> Option<EventCache> {
942 cache.upgrade().map(|inner| EventCache { inner })
943}
944
945async fn send_report_and_retry_memory_events(
946 cache: &Weak<EventCacheInner>,
947 report: RedecryptorReport,
948) -> Result<(), ()> {
949 let Some(cache) = upgrade_event_cache(cache) else {
950 return Err(());
951 };
952
953 cache.retry_in_memory_events().await;
954 let _ = cache.inner.redecryption_channels.utd_reporter.send(report);
955
956 Ok(())
957}
958
959pub(crate) struct Redecryptor {
966 _task: BackgroundTaskHandle,
967}
968
969impl Redecryptor {
970 pub(super) fn new(
975 client: &Client,
976 cache: Weak<EventCacheInner>,
977 receiver: UnboundedReceiver<DecryptionRetryRequest>,
978 linked_chunk_update_sender: &Sender<RoomEventCacheLinkedChunkUpdate>,
979 ) -> Self {
980 let linked_chunk_stream = BroadcastStream::new(linked_chunk_update_sender.subscribe());
981 let backup_state_stream = client.encryption().backups().state_stream();
982
983 let task = client
984 .task_monitor()
985 .spawn_infinite_task("event_cache::redecryptor", async {
986 let request_redecryption_stream = UnboundedReceiverStream::new(receiver);
987
988 Self::listen_for_room_keys_task(
989 cache,
990 request_redecryption_stream,
991 linked_chunk_stream,
992 backup_state_stream,
993 )
994 .await;
995 })
996 .abort_on_drop();
997
998 Self { _task: task }
999 }
1000
1001 async fn subscribe_to_room_key_stream(
1006 cache: &Weak<EventCacheInner>,
1007 ) -> Option<(
1008 impl Stream<Item = Result<Vec<RoomKeyInfo>, BroadcastStreamRecvError>>,
1009 impl Stream<Item = Vec<RoomKeyWithheldInfo>>,
1010 )> {
1011 let event_cache = cache.upgrade()?;
1012 let client = event_cache.client().ok()?;
1013 let machine = client.olm_machine().await;
1014
1015 machine.as_ref().map(|m| {
1016 (m.store().room_keys_received_stream(), m.store().room_keys_withheld_received_stream())
1017 })
1018 }
1019
1020 async fn redecryption_loop(
1021 cache: &Weak<EventCacheInner>,
1022 decryption_request_stream: &mut Pin<&mut impl Stream<Item = DecryptionRetryRequest>>,
1023 events_stream: &mut Pin<
1024 &mut impl Stream<Item = Result<RoomEventCacheLinkedChunkUpdate, BroadcastStreamRecvError>>,
1025 >,
1026 backup_state_stream: &mut Pin<
1027 &mut impl Stream<Item = Result<BackupState, BroadcastStreamRecvError>>,
1028 >,
1029 ) -> bool {
1030 let Some((room_key_stream, withheld_stream)) =
1031 Self::subscribe_to_room_key_stream(cache).await
1032 else {
1033 return false;
1034 };
1035
1036 pin_mut!(room_key_stream);
1037 pin_mut!(withheld_stream);
1038
1039 loop {
1040 tokio::select! {
1041 Some(request) = decryption_request_stream.next() => {
1044 let Some(cache) = upgrade_event_cache(cache) else {
1045 break false;
1046 };
1047
1048 trace!(?request, "Received a redecryption request");
1049
1050 for session_id in request.utd_session_ids {
1051 let _ = cache
1052 .retry_decryption(&request.room_id, &session_id)
1053 .await
1054 .inspect_err(|e| warn!("Error redecrypting after an explicit request was received {e:?}"));
1055 }
1056
1057 for session_id in request.refresh_info_session_ids {
1058 let _ = cache.update_encryption_info(&request.room_id, &session_id).await.inspect_err(|e|
1059 warn!(
1060 room_id = %request.room_id,
1061 session_id = session_id,
1062 "Unable to update the encryption info {e:?}",
1063 ));
1064 }
1065 }
1066 room_keys = room_key_stream.next() => {
1069 match room_keys {
1070 Some(Ok(room_keys)) => {
1071 let Some(cache) = upgrade_event_cache(cache) else {
1075 break false;
1076 };
1077
1078 trace!(?room_keys, "Received new room keys");
1079
1080 for key in &room_keys {
1081 let _ = cache
1082 .retry_decryption(&key.room_id, &key.session_id)
1083 .await
1084 .inspect_err(|e| warn!("Error redecrypting {e:?}"));
1085 }
1086
1087 for key in room_keys {
1088 let _ = cache.update_encryption_info(&key.room_id, &key.session_id).await.inspect_err(|e|
1089 warn!(
1090 room_id = %key.room_id,
1091 session_id = key.session_id,
1092 "Unable to update the encryption info {e:?}",
1093 ));
1094 }
1095 },
1096 Some(Err(_)) => {
1097 warn!("The room key stream lagged, reporting the lag to our listeners");
1104
1105 if send_report_and_retry_memory_events(cache, RedecryptorReport::Lagging).await.is_err() {
1106 break false;
1107 }
1108 },
1109 None => {
1112 break true;
1113 }
1114 }
1115 }
1116 withheld_info = withheld_stream.next() => {
1117 match withheld_info {
1118 Some(infos) => {
1119 let Some(cache) = upgrade_event_cache(cache) else {
1120 break false;
1121 };
1122
1123 trace!(?infos, "Received new withheld infos");
1124
1125 for RoomKeyWithheldInfo { room_id, session_id, .. } in &infos {
1126 let _ = cache.update_encryption_info(room_id, session_id).await.inspect_err(|e|
1127 warn!(
1128 room_id = %room_id,
1129 session_id = session_id,
1130 "Unable to update the encryption info {e:?}",
1131 ));
1132 }
1133 }
1134 None => break true,
1137 }
1138 }
1139 Some(event_updates) = events_stream.next() => {
1143 match event_updates {
1144 Ok(updates) => {
1145 let Some(cache) = upgrade_event_cache(cache) else {
1146 break false;
1147 };
1148
1149 let linked_chunk_id = updates.linked_chunk_id.to_owned();
1150
1151 let _ = cache.retry_decryption_for_event_cache_updates(updates).await.inspect_err(|e|
1152 warn!(
1153 %linked_chunk_id,
1154 "Unable to handle UTDs from event cache updates {e:?}",
1155 )
1156 );
1157 }
1158 Err(_) => {
1159 if send_report_and_retry_memory_events(cache, RedecryptorReport::Lagging).await.is_err() {
1160 break false;
1161 }
1162 }
1163 }
1164 }
1165 Some(backup_state_update) = backup_state_stream.next() => {
1166 match backup_state_update {
1167 Ok(state) => {
1168 match state {
1169 BackupState::Unknown |
1170 BackupState::Creating |
1171 BackupState::Enabling |
1172 BackupState::Resuming |
1173 BackupState::Downloading |
1174 BackupState::Disabling =>{
1175 }
1178 BackupState::Enabled => {
1179 if send_report_and_retry_memory_events(cache, RedecryptorReport::BackupAvailable).await.is_err() {
1184 break false;
1185 }
1186 }
1187 }
1188 }
1189 Err(_) => {
1190 if send_report_and_retry_memory_events(cache, RedecryptorReport::Lagging).await.is_err() {
1191 break false;
1192 }
1193 }
1194 }
1195 }
1196 else => break false,
1197 }
1198 }
1199 }
1200
1201 async fn listen_for_room_keys_task(
1202 cache: Weak<EventCacheInner>,
1203 decryption_request_stream: UnboundedReceiverStream<DecryptionRetryRequest>,
1204 events_stream: BroadcastStream<RoomEventCacheLinkedChunkUpdate>,
1205 backup_state_stream: impl Stream<Item = Result<BackupState, BroadcastStreamRecvError>>,
1206 ) {
1207 pin_mut!(decryption_request_stream);
1211 pin_mut!(events_stream);
1212 pin_mut!(backup_state_stream);
1213
1214 while Self::redecryption_loop(
1215 &cache,
1216 &mut decryption_request_stream,
1217 &mut events_stream,
1218 &mut backup_state_stream,
1219 )
1220 .await
1221 {
1222 info!("Regenerating the re-decryption streams");
1223
1224 if send_report_and_retry_memory_events(&cache, RedecryptorReport::Lagging)
1227 .await
1228 .is_err()
1229 {
1230 break;
1231 }
1232 }
1233
1234 info!("Shutting down the event cache redecryptor");
1235 }
1236}
1237
1238#[cfg(not(target_family = "wasm"))]
1239#[cfg(test)]
1240mod tests {
1241 use std::{
1242 collections::BTreeSet,
1243 sync::{
1244 Arc,
1245 atomic::{AtomicBool, Ordering},
1246 },
1247 time::Duration,
1248 };
1249
1250 use assert_matches2::assert_matches;
1251 use async_trait::async_trait;
1252 use eyeball_im::VectorDiff;
1253 use matrix_sdk_base::{
1254 cross_process_lock::CrossProcessLockGeneration,
1255 crypto::types::events::{ToDeviceEvent, room::encrypted::ToDeviceEncryptedEventContent},
1256 deserialized_responses::{TimelineEventKind, VerificationState},
1257 event_cache::{
1258 Event, Gap,
1259 store::{EventCacheStore, EventCacheStoreError, MemoryStore},
1260 },
1261 linked_chunk::{
1262 ChunkIdentifier, ChunkIdentifierGenerator, ChunkMetadata, LinkedChunkId, Position,
1263 RawChunk, Update,
1264 },
1265 locks::Mutex,
1266 sleep::sleep,
1267 store::StoreConfig,
1268 };
1269 use matrix_sdk_common::cross_process_lock::CrossProcessLockConfig;
1270 use matrix_sdk_test::{JoinedRoomBuilder, async_test, event_factory::EventFactory};
1271 use ruma::{
1272 EventId, OwnedEventId, RoomId, RoomVersionId, device_id, event_id,
1273 events::{AnySyncTimelineEvent, relation::RelationType},
1274 room_id,
1275 serde::Raw,
1276 user_id,
1277 };
1278 use serde_json::json;
1279 use tokio::sync::oneshot::{self, Sender};
1280 use tracing::{Instrument, info};
1281
1282 use crate::{
1283 Client, assert_let_timeout,
1284 encryption::EncryptionSettings,
1285 event_cache::{
1286 DecryptionRetryRequest, RoomEventCacheGenericUpdate, RoomEventCacheUpdate,
1287 TimelineVectorDiffs,
1288 },
1289 test_utils::mocks::MatrixMockServer,
1290 };
1291
1292 #[derive(Debug, Clone)]
1297 struct DelayingStore {
1298 memory_store: MemoryStore,
1299 delaying: Arc<AtomicBool>,
1300 foo: Arc<Mutex<Option<Sender<()>>>>,
1301 }
1302
1303 impl DelayingStore {
1304 fn new() -> Self {
1305 Self {
1306 memory_store: MemoryStore::new(),
1307 delaying: AtomicBool::new(true).into(),
1308 foo: Arc::new(Mutex::new(None)),
1309 }
1310 }
1311
1312 async fn stop_delaying(&self) {
1313 let (sender, receiver) = oneshot::channel();
1314
1315 {
1316 *self.foo.lock() = Some(sender);
1317 }
1318
1319 self.delaying.store(false, Ordering::SeqCst);
1320
1321 receiver.await.expect("We should be able to receive a response")
1322 }
1323 }
1324
1325 #[cfg_attr(target_family = "wasm", async_trait(?Send))]
1326 #[cfg_attr(not(target_family = "wasm"), async_trait)]
1327 impl EventCacheStore for DelayingStore {
1328 type Error = EventCacheStoreError;
1329
1330 async fn close(&self) -> Result<(), EventCacheStoreError> {
1331 self.memory_store.close().await
1332 }
1333
1334 async fn reopen(&self) -> Result<(), EventCacheStoreError> {
1335 self.memory_store.reopen().await
1336 }
1337
1338 async fn try_take_leased_lock(
1339 &self,
1340 lease_duration_ms: u32,
1341 key: &str,
1342 holder: &str,
1343 ) -> Result<Option<CrossProcessLockGeneration>, Self::Error> {
1344 self.memory_store.try_take_leased_lock(lease_duration_ms, key, holder).await
1345 }
1346
1347 async fn handle_linked_chunk_updates(
1348 &self,
1349 linked_chunk_id: LinkedChunkId<'_>,
1350 updates: Vec<Update<Event, Gap>>,
1351 ) -> Result<(), Self::Error> {
1352 while self.delaying.load(Ordering::SeqCst) {
1358 sleep(Duration::from_millis(10)).await;
1359 }
1360
1361 let sender = self.foo.lock().take();
1362 let ret = self.memory_store.handle_linked_chunk_updates(linked_chunk_id, updates).await;
1363
1364 if let Some(sender) = sender {
1365 sender.send(()).expect("We should be able to notify the other side that we're done with the storage operation");
1366 }
1367
1368 ret
1369 }
1370
1371 async fn load_all_chunks(
1372 &self,
1373 linked_chunk_id: LinkedChunkId<'_>,
1374 ) -> Result<Vec<RawChunk<Event, Gap>>, Self::Error> {
1375 self.memory_store.load_all_chunks(linked_chunk_id).await
1376 }
1377
1378 async fn load_all_chunks_metadata(
1379 &self,
1380 linked_chunk_id: LinkedChunkId<'_>,
1381 ) -> Result<Vec<ChunkMetadata>, Self::Error> {
1382 self.memory_store.load_all_chunks_metadata(linked_chunk_id).await
1383 }
1384
1385 async fn load_last_chunk(
1386 &self,
1387 linked_chunk_id: LinkedChunkId<'_>,
1388 ) -> Result<(Option<RawChunk<Event, Gap>>, ChunkIdentifierGenerator), Self::Error> {
1389 self.memory_store.load_last_chunk(linked_chunk_id).await
1390 }
1391
1392 async fn load_previous_chunk(
1393 &self,
1394 linked_chunk_id: LinkedChunkId<'_>,
1395 before_chunk_identifier: ChunkIdentifier,
1396 ) -> Result<Option<RawChunk<Event, Gap>>, Self::Error> {
1397 self.memory_store.load_previous_chunk(linked_chunk_id, before_chunk_identifier).await
1398 }
1399
1400 async fn remember_thread(
1401 &self,
1402 room_id: &RoomId,
1403 thread_id: &EventId,
1404 ) -> Result<(), Self::Error> {
1405 self.memory_store.remember_thread(room_id, thread_id).await
1406 }
1407
1408 async fn clear_all_events(&self, room_id: Option<&RoomId>) -> Result<(), Self::Error> {
1409 self.memory_store.clear_all_events(room_id).await
1410 }
1411
1412 async fn filter_duplicated_events(
1413 &self,
1414 linked_chunk_id: LinkedChunkId<'_>,
1415 events: Vec<OwnedEventId>,
1416 ) -> Result<Vec<(OwnedEventId, Position)>, Self::Error> {
1417 self.memory_store.filter_duplicated_events(linked_chunk_id, events).await
1418 }
1419
1420 async fn find_event(
1421 &self,
1422 room_id: &RoomId,
1423 event_id: &EventId,
1424 ) -> Result<Option<Event>, Self::Error> {
1425 self.memory_store.find_event(room_id, event_id).await
1426 }
1427
1428 async fn find_event_relations(
1429 &self,
1430 room_id: &RoomId,
1431 event_id: &EventId,
1432 filters: Option<&[RelationType]>,
1433 ) -> Result<Vec<(Event, Option<Position>)>, Self::Error> {
1434 self.memory_store.find_event_relations(room_id, event_id, filters).await
1435 }
1436
1437 async fn get_room_events(
1438 &self,
1439 room_id: &RoomId,
1440 event_type: Option<&str>,
1441 session_id: Option<&str>,
1442 ) -> Result<Vec<Event>, Self::Error> {
1443 self.memory_store.get_room_events(room_id, event_type, session_id).await
1444 }
1445
1446 async fn save_event(&self, room_id: &RoomId, event: Event) -> Result<(), Self::Error> {
1447 self.memory_store.save_event(room_id, event).await
1448 }
1449
1450 async fn optimize(&self) -> Result<(), Self::Error> {
1451 self.memory_store.optimize().await
1452 }
1453
1454 async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1455 self.memory_store.get_size().await
1456 }
1457 }
1458
1459 async fn set_up_clients(
1460 room_id: &RoomId,
1461 alice_enables_cross_signing: bool,
1462 use_delayed_store: bool,
1463 ) -> (Client, Client, MatrixMockServer, Option<DelayingStore>) {
1464 let alice_span = tracing::info_span!("alice");
1465 let bob_span = tracing::info_span!("bob");
1466
1467 let alice_user_id = user_id!("@alice:localhost");
1468 let alice_device_id = device_id!("ALICEDEVICE");
1469 let bob_user_id = user_id!("@bob:localhost");
1470 let bob_device_id = device_id!("BOBDEVICE");
1471
1472 let matrix_mock_server = MatrixMockServer::new().await;
1473 matrix_mock_server.mock_crypto_endpoints_preset().await;
1474
1475 let encryption_settings = EncryptionSettings {
1476 auto_enable_cross_signing: alice_enables_cross_signing,
1477 ..Default::default()
1478 };
1479
1480 let alice = matrix_mock_server
1483 .client_builder_for_crypto_end_to_end(alice_user_id, alice_device_id)
1484 .on_builder(|builder| {
1485 builder
1486 .with_enable_share_history_on_invite(true)
1487 .with_encryption_settings(encryption_settings)
1488 })
1489 .build()
1490 .instrument(alice_span.clone())
1491 .await;
1492
1493 let encryption_settings =
1494 EncryptionSettings { auto_enable_cross_signing: true, ..Default::default() };
1495
1496 let (store_config, store) = if use_delayed_store {
1497 let store = DelayingStore::new();
1498
1499 (
1500 StoreConfig::new(CrossProcessLockConfig::multi_process(
1501 "delayed_store_event_cache_test",
1502 ))
1503 .event_cache_store(store.clone()),
1504 Some(store),
1505 )
1506 } else {
1507 (
1508 StoreConfig::new(CrossProcessLockConfig::multi_process(
1509 "normal_store_event_cache_test",
1510 )),
1511 None,
1512 )
1513 };
1514
1515 let bob = matrix_mock_server
1516 .client_builder_for_crypto_end_to_end(bob_user_id, bob_device_id)
1517 .on_builder(|builder| {
1518 builder
1519 .with_enable_share_history_on_invite(true)
1520 .with_encryption_settings(encryption_settings)
1521 .store_config(store_config)
1522 })
1523 .build()
1524 .instrument(bob_span.clone())
1525 .await;
1526
1527 bob.event_cache().subscribe().expect("Bob should be able to enable the event cache");
1528
1529 matrix_mock_server.exchange_e2ee_identities(&alice, &bob).await;
1531
1532 let event_factory = EventFactory::new().room(room_id).sender(alice_user_id);
1533
1534 let room_builder = JoinedRoomBuilder::new(room_id)
1536 .add_state_event(event_factory.create(alice_user_id, RoomVersionId::V1))
1537 .add_state_event(event_factory.room_encryption());
1538
1539 matrix_mock_server
1540 .mock_sync()
1541 .ok_and_run(&alice, |builder| {
1542 builder.add_joined_room(room_builder.clone());
1543 })
1544 .instrument(alice_span)
1545 .await;
1546
1547 matrix_mock_server
1548 .mock_sync()
1549 .ok_and_run(&bob, |builder| {
1550 builder.add_joined_room(room_builder);
1551 })
1552 .instrument(bob_span)
1553 .await;
1554
1555 (alice, bob, matrix_mock_server, store)
1556 }
1557
1558 async fn prepare_room(
1559 matrix_mock_server: &MatrixMockServer,
1560 event_factory: &EventFactory,
1561 alice: &Client,
1562 bob: &Client,
1563 room_id: &RoomId,
1564 ) -> (Raw<AnySyncTimelineEvent>, Raw<ToDeviceEvent<ToDeviceEncryptedEventContent>>) {
1565 let alice_user_id = alice.user_id().unwrap();
1566 let bob_user_id = bob.user_id().unwrap();
1567
1568 let alice_member_event = event_factory.member(alice_user_id).into_raw();
1569 let bob_member_event = event_factory.member(bob_user_id).into_raw();
1570
1571 let room = alice
1572 .get_room(room_id)
1573 .expect("Alice should have access to the room now that we synced");
1574
1575 let event_type = "m.room.message";
1580 let content = json!({"body": "It's a secret to everybody", "msgtype": "m.text"});
1581
1582 let event_id = event_id!("$some_id");
1583 let (event_receiver, mock) =
1584 matrix_mock_server.mock_room_send().ok_with_capture(event_id, alice_user_id);
1585 let (_guard, room_key) = matrix_mock_server.mock_capture_put_to_device(alice_user_id).await;
1586
1587 {
1588 let _guard = mock.mock_once().mount_as_scoped().await;
1589
1590 matrix_mock_server
1591 .mock_get_members()
1592 .ok(vec![alice_member_event.clone(), bob_member_event.clone()])
1593 .mock_once()
1594 .mount()
1595 .await;
1596
1597 room.send_raw(event_type, content)
1598 .await
1599 .expect("We should be able to send an initial message");
1600 };
1601
1602 let event = event_receiver.await.expect("Alice should have sent the event by now");
1604 let room_key = room_key.await;
1605
1606 (event, room_key)
1607 }
1608
1609 #[async_test]
1610 async fn test_redecryptor() {
1611 let room_id = room_id!("!test:localhost");
1612
1613 let event_factory = EventFactory::new().room(room_id);
1614 let (alice, bob, matrix_mock_server, _) = set_up_clients(room_id, true, false).await;
1615
1616 let (event, room_key) =
1617 prepare_room(&matrix_mock_server, &event_factory, &alice, &bob, room_id).await;
1618
1619 let event_cache = bob.event_cache();
1622 let (room_cache, _) = event_cache
1623 .room(room_id)
1624 .await
1625 .expect("We should be able to get to the event cache for a specific room");
1626
1627 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1628 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1629
1630 bob.inner
1633 .base_client
1634 .regenerate_olm(None)
1635 .await
1636 .expect("We should be able to regenerate the Olm machine");
1637
1638 matrix_mock_server
1640 .mock_sync()
1641 .ok_and_run(&bob, |builder| {
1642 builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(event));
1643 })
1644 .await;
1645
1646 assert_let_timeout!(
1649 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1650 subscriber.recv()
1651 );
1652
1653 assert_eq!(diffs.len(), 1);
1656 assert_matches!(&diffs[0], VectorDiff::Append { values });
1657 assert_eq!(values.len(), 1);
1658 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1659
1660 assert_let_timeout!(
1661 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1662 );
1663 assert_eq!(expected_room_id, room_id);
1664 assert!(generic_stream.is_empty());
1665
1666 matrix_mock_server
1668 .mock_sync()
1669 .ok_and_run(&bob, |builder| {
1670 builder.add_to_device_event(
1671 room_key
1672 .deserialize_as()
1673 .expect("We should be able to deserialize the room key"),
1674 );
1675 })
1676 .await;
1677
1678 assert_let_timeout!(
1680 Duration::from_secs(1),
1681 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1682 subscriber.recv()
1683 );
1684
1685 assert_eq!(diffs.len(), 1);
1687 assert_matches!(&diffs[0], VectorDiff::Set { index, value });
1688 assert_eq!(*index, 0);
1689 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1690
1691 assert_let_timeout!(
1692 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1693 );
1694 assert_eq!(expected_room_id, room_id);
1695 assert!(generic_stream.is_empty());
1696 }
1697
1698 #[async_test]
1699 async fn test_redecryptor_updating_encryption_info() {
1700 let bob_span = tracing::info_span!("bob");
1701
1702 let room_id = room_id!("!test:localhost");
1703
1704 let event_factory = EventFactory::new().room(room_id);
1705 let (alice, bob, matrix_mock_server, _) = set_up_clients(room_id, false, false).await;
1706
1707 let (event, room_key) =
1708 prepare_room(&matrix_mock_server, &event_factory, &alice, &bob, room_id).await;
1709
1710 let event_cache = bob.event_cache();
1713 let (room_cache, _) = event_cache
1714 .room(room_id)
1715 .instrument(bob_span.clone())
1716 .await
1717 .expect("We should be able to get to the event cache for a specific room");
1718
1719 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1720 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1721
1722 matrix_mock_server
1724 .mock_sync()
1725 .ok_and_run(&bob, |builder| {
1726 builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(event));
1727 })
1728 .instrument(bob_span.clone())
1729 .await;
1730
1731 assert_let_timeout!(
1734 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1735 subscriber.recv()
1736 );
1737
1738 assert_eq!(diffs.len(), 1);
1741 assert_matches!(&diffs[0], VectorDiff::Append { values });
1742 assert_eq!(values.len(), 1);
1743 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1744
1745 assert_let_timeout!(
1746 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1747 );
1748 assert_eq!(expected_room_id, room_id);
1749 assert!(generic_stream.is_empty());
1750
1751 matrix_mock_server
1753 .mock_sync()
1754 .ok_and_run(&bob, |builder| {
1755 builder.add_to_device_event(
1756 room_key
1757 .deserialize_as()
1758 .expect("We should be able to deserialize the room key"),
1759 );
1760 })
1761 .instrument(bob_span.clone())
1762 .await;
1763
1764 assert_let_timeout!(
1766 Duration::from_secs(1),
1767 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1768 subscriber.recv()
1769 );
1770
1771 assert_eq!(diffs.len(), 1);
1773 assert_matches!(&diffs[0], VectorDiff::Set { index: 0, value });
1774 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1775
1776 let encryption_info = value.encryption_info().unwrap();
1777 assert_matches!(&encryption_info.verification_state, VerificationState::Unverified(_));
1778
1779 assert_let_timeout!(
1780 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1781 );
1782 assert_eq!(expected_room_id, room_id);
1783 assert!(generic_stream.is_empty());
1784
1785 let session_id = encryption_info.session_id().unwrap().to_owned();
1786 let alice_user_id = alice.user_id().unwrap();
1787
1788 alice
1790 .encryption()
1791 .bootstrap_cross_signing(None)
1792 .await
1793 .expect("Alice should be able to create the cross-signing keys");
1794
1795 bob.update_tracked_users_for_testing([alice_user_id]).instrument(bob_span.clone()).await;
1796 matrix_mock_server
1797 .mock_sync()
1798 .ok_and_run(&bob, |builder| {
1799 builder.add_change_device(alice_user_id);
1800 })
1801 .instrument(bob_span.clone())
1802 .await;
1803
1804 bob.event_cache().request_decryption(DecryptionRetryRequest {
1805 room_id: room_id.into(),
1806 utd_session_ids: BTreeSet::new(),
1807 refresh_info_session_ids: BTreeSet::from([session_id]),
1808 });
1809
1810 assert_let_timeout!(
1813 Duration::from_secs(1),
1814 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1815 subscriber.recv()
1816 );
1817
1818 assert_eq!(diffs.len(), 1);
1819 assert_matches!(&diffs[0], VectorDiff::Set { index: 0, value });
1820 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1821 let encryption_info = value.encryption_info().unwrap();
1822
1823 assert_matches!(
1824 &encryption_info.verification_state,
1825 VerificationState::Unverified(_),
1826 "The event should now know about the identity but still be unverified"
1827 );
1828
1829 assert_let_timeout!(
1830 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1831 );
1832 assert_eq!(expected_room_id, room_id);
1833 assert!(generic_stream.is_empty());
1834 }
1835
1836 #[async_test]
1837 async fn test_event_is_redecrypted_even_if_key_arrives_while_event_processing() {
1838 let room_id = room_id!("!test:localhost");
1839
1840 let event_factory = EventFactory::new().room(room_id);
1841 let (alice, bob, matrix_mock_server, delayed_store) =
1842 set_up_clients(room_id, true, true).await;
1843
1844 let delayed_store = delayed_store.unwrap();
1845
1846 let (event, room_key) =
1847 prepare_room(&matrix_mock_server, &event_factory, &alice, &bob, room_id).await;
1848
1849 let event_cache = bob.event_cache();
1850
1851 let (room_cache, _) = event_cache
1853 .room(room_id)
1854 .await
1855 .expect("We should be able to get to the event cache for a specific room");
1856
1857 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1858 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1859
1860 matrix_mock_server
1862 .mock_sync()
1863 .ok_and_run(&bob, |builder| {
1864 builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(event));
1865 })
1866 .await;
1867
1868 matrix_mock_server
1870 .mock_sync()
1871 .ok_and_run(&bob, |builder| {
1872 builder.add_to_device_event(
1873 room_key
1874 .deserialize_as()
1875 .expect("We should be able to deserialize the room key"),
1876 );
1877 })
1878 .await;
1879
1880 info!("Stopping the delay");
1881 delayed_store.stop_delaying().await;
1882
1883 assert_let_timeout!(
1889 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1890 subscriber.recv()
1891 );
1892
1893 assert_eq!(diffs.len(), 1);
1896 assert_matches!(&diffs[0], VectorDiff::Append { values });
1897 assert_eq!(values.len(), 1);
1898 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1899
1900 assert_let_timeout!(
1902 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1903 );
1904 assert_eq!(expected_room_id, room_id);
1905
1906 assert_let_timeout!(
1908 Duration::from_secs(1),
1909 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1910 subscriber.recv()
1911 );
1912
1913 assert_eq!(diffs.len(), 1);
1915 assert_matches!(&diffs[0], VectorDiff::Set { index, value });
1916 assert_eq!(*index, 0);
1917 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1918
1919 assert_let_timeout!(
1921 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1922 );
1923 assert_eq!(expected_room_id, room_id);
1924 assert!(generic_stream.is_empty());
1925 }
1926}