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 thread::ThreadInfo,
1261 },
1262 linked_chunk::{
1263 ChunkIdentifier, ChunkIdentifierGenerator, ChunkMetadata, LinkedChunkId, Position,
1264 RawChunk, Update,
1265 },
1266 locks::Mutex,
1267 sleep::sleep,
1268 store::StoreConfig,
1269 };
1270 use matrix_sdk_common::cross_process_lock::CrossProcessLockConfig;
1271 use matrix_sdk_test::{JoinedRoomBuilder, async_test, event_factory::EventFactory};
1272 use ruma::{
1273 EventId, OwnedEventId, RoomId, RoomVersionId, device_id, event_id,
1274 events::{AnySyncTimelineEvent, relation::RelationType},
1275 room_id,
1276 serde::Raw,
1277 user_id,
1278 };
1279 use serde_json::json;
1280 use tokio::sync::oneshot::{self, Sender};
1281 use tracing::{Instrument, info};
1282
1283 use crate::{
1284 Client, assert_let_timeout,
1285 encryption::EncryptionSettings,
1286 event_cache::{
1287 DecryptionRetryRequest, RoomEventCacheGenericUpdate, RoomEventCacheUpdate,
1288 TimelineVectorDiffs,
1289 },
1290 test_utils::mocks::MatrixMockServer,
1291 };
1292
1293 #[derive(Debug, Clone)]
1298 struct DelayingStore {
1299 memory_store: MemoryStore,
1300 delaying: Arc<AtomicBool>,
1301 foo: Arc<Mutex<Option<Sender<()>>>>,
1302 }
1303
1304 impl DelayingStore {
1305 fn new() -> Self {
1306 Self {
1307 memory_store: MemoryStore::new(),
1308 delaying: AtomicBool::new(true).into(),
1309 foo: Arc::new(Mutex::new(None)),
1310 }
1311 }
1312
1313 async fn stop_delaying(&self) {
1314 let (sender, receiver) = oneshot::channel();
1315
1316 {
1317 *self.foo.lock() = Some(sender);
1318 }
1319
1320 self.delaying.store(false, Ordering::SeqCst);
1321
1322 receiver.await.expect("We should be able to receive a response")
1323 }
1324 }
1325
1326 #[cfg_attr(target_family = "wasm", async_trait(?Send))]
1327 #[cfg_attr(not(target_family = "wasm"), async_trait)]
1328 impl EventCacheStore for DelayingStore {
1329 type Error = EventCacheStoreError;
1330
1331 async fn close(&self) -> Result<(), EventCacheStoreError> {
1332 self.memory_store.close().await
1333 }
1334
1335 async fn reopen(&self) -> Result<(), EventCacheStoreError> {
1336 self.memory_store.reopen().await
1337 }
1338
1339 async fn try_take_leased_lock(
1340 &self,
1341 lease_duration_ms: u32,
1342 key: &str,
1343 holder: &str,
1344 ) -> Result<Option<CrossProcessLockGeneration>, Self::Error> {
1345 self.memory_store.try_take_leased_lock(lease_duration_ms, key, holder).await
1346 }
1347
1348 async fn handle_linked_chunk_updates(
1349 &self,
1350 linked_chunk_id: LinkedChunkId<'_>,
1351 updates: Vec<Update<Event, Gap>>,
1352 ) -> Result<(), Self::Error> {
1353 while self.delaying.load(Ordering::SeqCst) {
1359 sleep(Duration::from_millis(10)).await;
1360 }
1361
1362 let sender = self.foo.lock().take();
1363 let ret = self.memory_store.handle_linked_chunk_updates(linked_chunk_id, updates).await;
1364
1365 if let Some(sender) = sender {
1366 sender.send(()).expect("We should be able to notify the other side that we're done with the storage operation");
1367 }
1368
1369 ret
1370 }
1371
1372 async fn load_all_chunks(
1373 &self,
1374 linked_chunk_id: LinkedChunkId<'_>,
1375 ) -> Result<Vec<RawChunk<Event, Gap>>, Self::Error> {
1376 self.memory_store.load_all_chunks(linked_chunk_id).await
1377 }
1378
1379 async fn load_all_chunks_metadata(
1380 &self,
1381 linked_chunk_id: LinkedChunkId<'_>,
1382 ) -> Result<Vec<ChunkMetadata>, Self::Error> {
1383 self.memory_store.load_all_chunks_metadata(linked_chunk_id).await
1384 }
1385
1386 async fn load_last_chunk(
1387 &self,
1388 linked_chunk_id: LinkedChunkId<'_>,
1389 ) -> Result<(Option<RawChunk<Event, Gap>>, ChunkIdentifierGenerator), Self::Error> {
1390 self.memory_store.load_last_chunk(linked_chunk_id).await
1391 }
1392
1393 async fn load_previous_chunk(
1394 &self,
1395 linked_chunk_id: LinkedChunkId<'_>,
1396 before_chunk_identifier: ChunkIdentifier,
1397 ) -> Result<Option<RawChunk<Event, Gap>>, Self::Error> {
1398 self.memory_store.load_previous_chunk(linked_chunk_id, before_chunk_identifier).await
1399 }
1400
1401 async fn load_thread_info(
1402 &self,
1403 room_id: &RoomId,
1404 thread_id: &EventId,
1405 ) -> Result<ThreadInfo, Self::Error> {
1406 self.memory_store.load_thread_info(room_id, thread_id).await
1407 }
1408
1409 async fn update_thread_info(
1410 &self,
1411 room_id: &RoomId,
1412 thread_id: &EventId,
1413 thread_info: &ThreadInfo,
1414 ) -> Result<(), Self::Error> {
1415 self.memory_store.update_thread_info(room_id, thread_id, thread_info).await
1416 }
1417
1418 async fn clear_all_events(&self, room_id: Option<&RoomId>) -> Result<(), Self::Error> {
1419 self.memory_store.clear_all_events(room_id).await
1420 }
1421
1422 async fn filter_duplicated_events(
1423 &self,
1424 linked_chunk_id: LinkedChunkId<'_>,
1425 events: Vec<OwnedEventId>,
1426 ) -> Result<Vec<(OwnedEventId, Position)>, Self::Error> {
1427 self.memory_store.filter_duplicated_events(linked_chunk_id, events).await
1428 }
1429
1430 async fn find_event(
1431 &self,
1432 room_id: &RoomId,
1433 event_id: &EventId,
1434 ) -> Result<Option<Event>, Self::Error> {
1435 self.memory_store.find_event(room_id, event_id).await
1436 }
1437
1438 async fn find_event_relations(
1439 &self,
1440 room_id: &RoomId,
1441 event_id: &EventId,
1442 filters: Option<&[RelationType]>,
1443 ) -> Result<Vec<(Event, Option<Position>)>, Self::Error> {
1444 self.memory_store.find_event_relations(room_id, event_id, filters).await
1445 }
1446
1447 async fn get_room_events(
1448 &self,
1449 room_id: &RoomId,
1450 event_type: Option<&str>,
1451 session_id: Option<&str>,
1452 ) -> Result<Vec<Event>, Self::Error> {
1453 self.memory_store.get_room_events(room_id, event_type, session_id).await
1454 }
1455
1456 async fn save_event(&self, room_id: &RoomId, event: Event) -> Result<(), Self::Error> {
1457 self.memory_store.save_event(room_id, event).await
1458 }
1459
1460 async fn optimize(&self) -> Result<(), Self::Error> {
1461 self.memory_store.optimize().await
1462 }
1463
1464 async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1465 self.memory_store.get_size().await
1466 }
1467 }
1468
1469 async fn set_up_clients(
1470 room_id: &RoomId,
1471 alice_enables_cross_signing: bool,
1472 use_delayed_store: bool,
1473 ) -> (Client, Client, MatrixMockServer, Option<DelayingStore>) {
1474 let alice_span = tracing::info_span!("alice");
1475 let bob_span = tracing::info_span!("bob");
1476
1477 let alice_user_id = user_id!("@alice:localhost");
1478 let alice_device_id = device_id!("ALICEDEVICE");
1479 let bob_user_id = user_id!("@bob:localhost");
1480 let bob_device_id = device_id!("BOBDEVICE");
1481
1482 let matrix_mock_server = MatrixMockServer::new().await;
1483 matrix_mock_server.mock_crypto_endpoints_preset().await;
1484
1485 let encryption_settings = EncryptionSettings {
1486 auto_enable_cross_signing: alice_enables_cross_signing,
1487 ..Default::default()
1488 };
1489
1490 let alice = matrix_mock_server
1493 .client_builder_for_crypto_end_to_end(alice_user_id, alice_device_id)
1494 .on_builder(|builder| {
1495 builder
1496 .with_enable_share_history_on_invite(true)
1497 .with_encryption_settings(encryption_settings)
1498 })
1499 .build()
1500 .instrument(alice_span.clone())
1501 .await;
1502
1503 let encryption_settings =
1504 EncryptionSettings { auto_enable_cross_signing: true, ..Default::default() };
1505
1506 let (store_config, store) = if use_delayed_store {
1507 let store = DelayingStore::new();
1508
1509 (
1510 StoreConfig::new(CrossProcessLockConfig::multi_process(
1511 "delayed_store_event_cache_test",
1512 ))
1513 .event_cache_store(store.clone()),
1514 Some(store),
1515 )
1516 } else {
1517 (
1518 StoreConfig::new(CrossProcessLockConfig::multi_process(
1519 "normal_store_event_cache_test",
1520 )),
1521 None,
1522 )
1523 };
1524
1525 let bob = matrix_mock_server
1526 .client_builder_for_crypto_end_to_end(bob_user_id, bob_device_id)
1527 .on_builder(|builder| {
1528 builder
1529 .with_enable_share_history_on_invite(true)
1530 .with_encryption_settings(encryption_settings)
1531 .store_config(store_config)
1532 })
1533 .build()
1534 .instrument(bob_span.clone())
1535 .await;
1536
1537 bob.event_cache().subscribe().expect("Bob should be able to enable the event cache");
1538
1539 matrix_mock_server.exchange_e2ee_identities(&alice, &bob).await;
1541
1542 let event_factory = EventFactory::new().room(room_id).sender(alice_user_id);
1543
1544 let room_builder = JoinedRoomBuilder::new(room_id)
1546 .add_state_event(event_factory.create(alice_user_id, RoomVersionId::V1))
1547 .add_state_event(event_factory.room_encryption());
1548
1549 matrix_mock_server
1550 .mock_sync()
1551 .ok_and_run(&alice, |builder| {
1552 builder.add_joined_room(room_builder.clone());
1553 })
1554 .instrument(alice_span)
1555 .await;
1556
1557 matrix_mock_server
1558 .mock_sync()
1559 .ok_and_run(&bob, |builder| {
1560 builder.add_joined_room(room_builder);
1561 })
1562 .instrument(bob_span)
1563 .await;
1564
1565 (alice, bob, matrix_mock_server, store)
1566 }
1567
1568 async fn prepare_room(
1569 matrix_mock_server: &MatrixMockServer,
1570 event_factory: &EventFactory,
1571 alice: &Client,
1572 bob: &Client,
1573 room_id: &RoomId,
1574 ) -> (Raw<AnySyncTimelineEvent>, Raw<ToDeviceEvent<ToDeviceEncryptedEventContent>>) {
1575 let alice_user_id = alice.user_id().unwrap();
1576 let bob_user_id = bob.user_id().unwrap();
1577
1578 let alice_member_event = event_factory.member(alice_user_id).into_raw();
1579 let bob_member_event = event_factory.member(bob_user_id).into_raw();
1580
1581 let room = alice
1582 .get_room(room_id)
1583 .expect("Alice should have access to the room now that we synced");
1584
1585 let event_type = "m.room.message";
1590 let content = json!({"body": "It's a secret to everybody", "msgtype": "m.text"});
1591
1592 let event_id = event_id!("$some_id");
1593 let (event_receiver, mock) =
1594 matrix_mock_server.mock_room_send().ok_with_capture(event_id, alice_user_id);
1595 let (_guard, room_key) = matrix_mock_server.mock_capture_put_to_device(alice_user_id).await;
1596
1597 {
1598 let _guard = mock.mock_once().mount_as_scoped().await;
1599
1600 matrix_mock_server
1601 .mock_get_members()
1602 .ok(vec![alice_member_event.clone(), bob_member_event.clone()])
1603 .mock_once()
1604 .mount()
1605 .await;
1606
1607 room.send_raw(event_type, content)
1608 .await
1609 .expect("We should be able to send an initial message");
1610 };
1611
1612 let event = event_receiver.await.expect("Alice should have sent the event by now");
1614 let room_key = room_key.await;
1615
1616 (event, room_key)
1617 }
1618
1619 #[async_test]
1620 async fn test_redecryptor() {
1621 let room_id = room_id!("!test:localhost");
1622
1623 let event_factory = EventFactory::new().room(room_id);
1624 let (alice, bob, matrix_mock_server, _) = set_up_clients(room_id, true, false).await;
1625
1626 let (event, room_key) =
1627 prepare_room(&matrix_mock_server, &event_factory, &alice, &bob, room_id).await;
1628
1629 let event_cache = bob.event_cache();
1632 let (room_cache, _) = event_cache
1633 .room(room_id)
1634 .await
1635 .expect("We should be able to get to the event cache for a specific room");
1636
1637 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1638 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1639
1640 bob.inner
1643 .base_client
1644 .regenerate_olm(None)
1645 .await
1646 .expect("We should be able to regenerate the Olm machine");
1647
1648 matrix_mock_server
1650 .mock_sync()
1651 .ok_and_run(&bob, |builder| {
1652 builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(event));
1653 })
1654 .await;
1655
1656 assert_let_timeout!(
1659 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1660 subscriber.recv()
1661 );
1662
1663 assert_eq!(diffs.len(), 1);
1666 assert_matches!(&diffs[0], VectorDiff::Append { values });
1667 assert_eq!(values.len(), 1);
1668 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1669
1670 assert_let_timeout!(
1671 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1672 );
1673 assert_eq!(expected_room_id, room_id);
1674 assert!(generic_stream.is_empty());
1675
1676 matrix_mock_server
1678 .mock_sync()
1679 .ok_and_run(&bob, |builder| {
1680 builder.add_to_device_event(
1681 room_key
1682 .deserialize_as()
1683 .expect("We should be able to deserialize the room key"),
1684 );
1685 })
1686 .await;
1687
1688 assert_let_timeout!(
1690 Duration::from_secs(1),
1691 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1692 subscriber.recv()
1693 );
1694
1695 assert_eq!(diffs.len(), 1);
1697 assert_matches!(&diffs[0], VectorDiff::Set { index, value });
1698 assert_eq!(*index, 0);
1699 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1700
1701 assert_let_timeout!(
1702 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1703 );
1704 assert_eq!(expected_room_id, room_id);
1705 assert!(generic_stream.is_empty());
1706 }
1707
1708 #[async_test]
1709 async fn test_redecryptor_updating_encryption_info() {
1710 let bob_span = tracing::info_span!("bob");
1711
1712 let room_id = room_id!("!test:localhost");
1713
1714 let event_factory = EventFactory::new().room(room_id);
1715 let (alice, bob, matrix_mock_server, _) = set_up_clients(room_id, false, false).await;
1716
1717 let (event, room_key) =
1718 prepare_room(&matrix_mock_server, &event_factory, &alice, &bob, room_id).await;
1719
1720 let event_cache = bob.event_cache();
1723 let (room_cache, _) = event_cache
1724 .room(room_id)
1725 .instrument(bob_span.clone())
1726 .await
1727 .expect("We should be able to get to the event cache for a specific room");
1728
1729 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1730 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1731
1732 matrix_mock_server
1734 .mock_sync()
1735 .ok_and_run(&bob, |builder| {
1736 builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(event));
1737 })
1738 .instrument(bob_span.clone())
1739 .await;
1740
1741 assert_let_timeout!(
1744 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1745 subscriber.recv()
1746 );
1747
1748 assert_eq!(diffs.len(), 1);
1751 assert_matches!(&diffs[0], VectorDiff::Append { values });
1752 assert_eq!(values.len(), 1);
1753 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1754
1755 assert_let_timeout!(
1756 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1757 );
1758 assert_eq!(expected_room_id, room_id);
1759 assert!(generic_stream.is_empty());
1760
1761 matrix_mock_server
1763 .mock_sync()
1764 .ok_and_run(&bob, |builder| {
1765 builder.add_to_device_event(
1766 room_key
1767 .deserialize_as()
1768 .expect("We should be able to deserialize the room key"),
1769 );
1770 })
1771 .instrument(bob_span.clone())
1772 .await;
1773
1774 assert_let_timeout!(
1776 Duration::from_secs(1),
1777 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1778 subscriber.recv()
1779 );
1780
1781 assert_eq!(diffs.len(), 1);
1783 assert_matches!(&diffs[0], VectorDiff::Set { index: 0, value });
1784 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1785
1786 let encryption_info = value.encryption_info().unwrap();
1787 assert_matches!(&encryption_info.verification_state, VerificationState::Unverified(_));
1788
1789 assert_let_timeout!(
1790 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1791 );
1792 assert_eq!(expected_room_id, room_id);
1793 assert!(generic_stream.is_empty());
1794
1795 let session_id = encryption_info.session_id().unwrap().to_owned();
1796 let alice_user_id = alice.user_id().unwrap();
1797
1798 alice
1800 .encryption()
1801 .bootstrap_cross_signing(None)
1802 .await
1803 .expect("Alice should be able to create the cross-signing keys");
1804
1805 bob.update_tracked_users_for_testing([alice_user_id]).instrument(bob_span.clone()).await;
1806 matrix_mock_server
1807 .mock_sync()
1808 .ok_and_run(&bob, |builder| {
1809 builder.add_change_device(alice_user_id);
1810 })
1811 .instrument(bob_span.clone())
1812 .await;
1813
1814 bob.event_cache().request_decryption(DecryptionRetryRequest {
1815 room_id: room_id.into(),
1816 utd_session_ids: BTreeSet::new(),
1817 refresh_info_session_ids: BTreeSet::from([session_id]),
1818 });
1819
1820 assert_let_timeout!(
1823 Duration::from_secs(1),
1824 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1825 subscriber.recv()
1826 );
1827
1828 assert_eq!(diffs.len(), 1);
1829 assert_matches!(&diffs[0], VectorDiff::Set { index: 0, value });
1830 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1831 let encryption_info = value.encryption_info().unwrap();
1832
1833 assert_matches!(
1834 &encryption_info.verification_state,
1835 VerificationState::Unverified(_),
1836 "The event should now know about the identity but still be unverified"
1837 );
1838
1839 assert_let_timeout!(
1840 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1841 );
1842 assert_eq!(expected_room_id, room_id);
1843 assert!(generic_stream.is_empty());
1844 }
1845
1846 #[async_test]
1847 async fn test_event_is_redecrypted_even_if_key_arrives_while_event_processing() {
1848 let room_id = room_id!("!test:localhost");
1849
1850 let event_factory = EventFactory::new().room(room_id);
1851 let (alice, bob, matrix_mock_server, delayed_store) =
1852 set_up_clients(room_id, true, true).await;
1853
1854 let delayed_store = delayed_store.unwrap();
1855
1856 let (event, room_key) =
1857 prepare_room(&matrix_mock_server, &event_factory, &alice, &bob, room_id).await;
1858
1859 let event_cache = bob.event_cache();
1860
1861 let (room_cache, _) = event_cache
1863 .room(room_id)
1864 .await
1865 .expect("We should be able to get to the event cache for a specific room");
1866
1867 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1868 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1869
1870 matrix_mock_server
1872 .mock_sync()
1873 .ok_and_run(&bob, |builder| {
1874 builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(event));
1875 })
1876 .await;
1877
1878 matrix_mock_server
1880 .mock_sync()
1881 .ok_and_run(&bob, |builder| {
1882 builder.add_to_device_event(
1883 room_key
1884 .deserialize_as()
1885 .expect("We should be able to deserialize the room key"),
1886 );
1887 })
1888 .await;
1889
1890 info!("Stopping the delay");
1891 delayed_store.stop_delaying().await;
1892
1893 assert_let_timeout!(
1899 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1900 subscriber.recv()
1901 );
1902
1903 assert_eq!(diffs.len(), 1);
1906 assert_matches!(&diffs[0], VectorDiff::Append { values });
1907 assert_eq!(values.len(), 1);
1908 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1909
1910 assert_let_timeout!(
1912 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1913 );
1914 assert_eq!(expected_room_id, room_id);
1915
1916 assert_let_timeout!(
1918 Duration::from_secs(1),
1919 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1920 subscriber.recv()
1921 );
1922
1923 assert_eq!(diffs.len(), 1);
1925 assert_matches!(&diffs[0], VectorDiff::Set { index, value });
1926 assert_eq!(*index, 0);
1927 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1928
1929 assert_let_timeout!(
1931 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1932 );
1933 assert_eq!(expected_room_id, room_id);
1934 assert!(generic_stream.is_empty());
1935 }
1936}