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 { .. })
202 || unresolved_event.encryption_info()
203 != Some(&resolved_utd.decrypted_event.encryption_info)
204 {
205 unresolved_event.kind =
206 TimelineEventKind::Decrypted(resolved_utd.decrypted_event);
207
208 if let Some(actions) = resolved_utd.actions {
209 unresolved_event.set_push_actions(actions);
210 }
211
212 Self::Resolved(unresolved_event)
214 } else {
215 Self::NotYet(resolved_utd)
216 }
217 }
218
219 Self::Resolved(event) => Self::Resolved(event),
220 }
221 }
222
223 pub fn as_resolved(&self) -> Option<&TimelineEvent> {
224 if let Self::Resolved(event) = self { Some(event) } else { None }
225 }
226}
227
228pub(super) trait TryResolveEvents {
231 fn try_resolve_events(
232 &self,
233 event_linked_chunk: &EventLinkedChunk,
234 ) -> Cow<'_, [MaybeResolvedEvent]>;
235}
236
237impl TryResolveEvents for [MaybeResolvedEvent] {
238 fn try_resolve_events(
239 &self,
240 event_linked_chunk: &EventLinkedChunk,
241 ) -> Cow<'_, [MaybeResolvedEvent]> {
242 let mut new_resolved_events = Cow::Borrowed(self);
243
244 for (nth, resolved_event) in self.iter().enumerate() {
245 match resolved_event {
246 MaybeResolvedEvent::NotYet(resolved_utd) => {
247 if let Some((_location, event)) =
252 event_linked_chunk.find_event(&resolved_utd.event_id)
253 {
254 let new_resolved_event = MaybeResolvedEvent::NotYet(resolved_utd.clone())
255 .try_resolve_event(event);
256
257 if matches!(new_resolved_event, MaybeResolvedEvent::Resolved(_)) {
258 unsafe {
265 *new_resolved_events.to_mut().get_unchecked_mut(nth) =
266 new_resolved_event;
267 }
268 }
269 }
270 }
271
272 MaybeResolvedEvent::Resolved(_event) => {
273 }
275 }
276 }
277
278 new_resolved_events
279 }
280}
281
282#[derive(Debug, Clone)]
285pub struct DecryptionRetryRequest {
286 pub room_id: OwnedRoomId,
288 pub utd_session_ids: BTreeSet<OwnedSessionId>,
290 pub refresh_info_session_ids: BTreeSet<OwnedSessionId>,
293}
294
295#[derive(Debug, Clone)]
297pub enum RedecryptorReport {
298 ResolvedUtds {
300 room_id: OwnedRoomId,
302 events: BTreeSet<OwnedEventId>,
304 },
305 Lagging,
308 BackupAvailable,
313}
314
315pub(super) struct RedecryptorChannels {
316 utd_reporter: Sender<RedecryptorReport>,
317 pub(super) decryption_request_sender: UnboundedSender<DecryptionRetryRequest>,
318 pub(super) decryption_request_receiver:
319 Mutex<Option<UnboundedReceiver<DecryptionRetryRequest>>>,
320}
321
322impl RedecryptorChannels {
323 pub(super) fn new() -> Self {
324 let (utd_reporter, _) = broadcast::channel(100);
325 let (decryption_request_sender, decryption_request_receiver) = unbounded_channel();
326
327 Self {
328 utd_reporter,
329 decryption_request_sender,
330 decryption_request_receiver: Mutex::new(Some(decryption_request_receiver)),
331 }
332 }
333}
334
335fn filter_timeline_event_to_utd(
340 event: TimelineEvent,
341) -> Option<(OwnedEventId, Raw<AnySyncTimelineEvent>)> {
342 let event_id = event.event_id().map(ToOwned::to_owned);
343
344 let event = as_variant!(event.kind, TimelineEventKind::UnableToDecrypt { event, .. } => event);
347 event_id.zip(event)
350}
351
352fn filter_timeline_event_to_decrypted(
358 event: TimelineEvent,
359) -> Option<(OwnedEventId, DecryptedRoomEvent)> {
360 let event_id = event.event_id().map(ToOwned::to_owned);
361
362 let event = as_variant!(event.kind, TimelineEventKind::Decrypted(event) => event);
363 event_id.zip(event)
366}
367
368impl EventCache {
369 async fn all_encrypted_events(
377 &self,
378 room_id: &RoomId,
379 session_id: SessionId<'_>,
380 ) -> Result<Vec<EventIdAndUtd>, EventCacheError> {
381 let caches = self.inner.all_caches_for_room(room_id).await?;
382
383 Ok(caches
384 .all_events_of_type(Some("m.room.encrypted"), Some(session_id))
385 .await?
386 .filter_map(filter_timeline_event_to_utd)
387 .collect())
388 }
389
390 async fn all_in_memory_encrypted_events(&self) -> BTreeMap<OwnedRoomId, Vec<EventIdAndUtd>> {
393 let mut utds = BTreeMap::new();
394
395 for (room_id, caches) in self.inner.by_room.read().await.iter() {
396 let room_utds: Vec<_> = caches
397 .all_in_memory_events()
398 .await
399 .into_iter()
400 .flatten()
401 .filter_map(filter_timeline_event_to_utd)
402 .collect();
403
404 utds.insert(room_id.to_owned(), room_utds);
405 }
406
407 utds
408 }
409
410 async fn all_decrypted_events(
411 &self,
412 room_id: &RoomId,
413 session_id: SessionId<'_>,
414 ) -> Result<Vec<EventIdAndEvent>, EventCacheError> {
415 let caches = self.inner.all_caches_for_room(room_id).await?;
416
417 Ok(caches
418 .all_events_of_type(None, Some(session_id))
419 .await?
420 .filter_map(filter_timeline_event_to_decrypted)
421 .collect())
422 }
423
424 async fn all_in_memory_decrypted_events(&self) -> BTreeMap<OwnedRoomId, Vec<EventIdAndEvent>> {
425 let mut decrypted_events = BTreeMap::new();
426
427 for (room_id, caches) in self.inner.by_room.read().await.iter() {
428 let room_utds: Vec<_> = caches
429 .all_in_memory_events()
430 .await
431 .into_iter()
432 .flatten()
433 .filter_map(filter_timeline_event_to_decrypted)
434 .collect();
435
436 decrypted_events.insert(room_id.to_owned(), room_utds);
437 }
438
439 decrypted_events
440 }
441
442 #[instrument(skip_all, fields(room_id))]
454 async fn on_resolved_utds(
455 &self,
456 room_id: &RoomId,
457 resolved_utds: Vec<ResolvedUtd>,
458 ) -> Result<(), EventCacheError> {
459 if resolved_utds.is_empty() {
460 trace!("No events were redecrypted or updated, nothing to replace");
461 return Ok(());
462 }
463
464 timer!("Resolving UTDs");
465
466 let event_ids: BTreeSet<_> =
467 resolved_utds.iter().map(|resolved_utd| resolved_utd.event_id.clone()).collect();
468
469 let all_caches = self.inner.all_caches_for_room(room_id).await?;
470 let mut maybe_resolved_events = Vec::with_capacity(resolved_utds.len());
471
472 {
489 let room_cache = &all_caches.room;
490 let mut state = room_cache.state().write().await?;
491
492 let mut maybe_resolved_in_memory_events = Vec::new();
493
494 for resolved_utd in resolved_utds {
495 if let Some((location, event)) = state.find_event(&resolved_utd.event_id).await? {
497 let maybe_resolved_event =
498 MaybeResolvedEvent::NotYet(resolved_utd).try_resolve_event(event);
499
500 if matches!(location, EventLocation::Memory(_)) {
503 maybe_resolved_in_memory_events.push(maybe_resolved_event.clone());
504 }
505
506 maybe_resolved_events.push(maybe_resolved_event);
509 } else {
510 maybe_resolved_events.push(MaybeResolvedEvent::NotYet(resolved_utd));
514 }
515 }
516
517 state
519 .save_events(
520 maybe_resolved_events
521 .iter()
522 .filter_map(|resolved_event| resolved_event.as_resolved())
523 .cloned(),
524 )
525 .await?;
526
527 let timeline_event_diffs = state
529 .replace_in_memory_utds(&maybe_resolved_in_memory_events)
530 .await?
531 .unwrap_or_default();
532
533 if !timeline_event_diffs.is_empty() {
534 state.update_sender.send(
535 RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs {
536 diffs: timeline_event_diffs,
537 origin: EventsOrigin::Cache,
538 }),
539 Some(RoomEventCacheGenericUpdate { room_id: room_id.to_owned() }),
540 );
541 }
542 }
543
544 {
546 for (thread_id, thread_cache) in try_join_all(
555 all_caches.threads.read().await.iter().map(|(thread_id, thread_cache)| async {
556 Result::<_, EventCacheError>::Ok(
557 thread_cache
561 .replace_in_memory_utds(&maybe_resolved_events)
562 .await?
563 .then(|| (thread_id.clone(), thread_cache.clone())),
564 )
565 }),
566 )
567 .await?
568 .into_iter()
569 .flatten()
571 {
572 let new_thread_summary = thread_cache.update_thread_summary().await?;
573
574 all_caches.room.update_thread_summary(&thread_id, new_thread_summary)?;
575 }
576 }
577
578 if let Some(pinned_events_cache) = all_caches.pinned_events.get() {
580 pinned_events_cache.replace_in_memory_utds(&maybe_resolved_events).await?;
581 }
582
583 {
585 try_join_all(all_caches.event_focused.read().await.values().map(
591 |event_focused_cache| {
592 event_focused_cache.replace_in_memory_utds(&maybe_resolved_events)
593 },
594 ))
595 .await?;
596 }
597
598 let report =
599 RedecryptorReport::ResolvedUtds { room_id: room_id.to_owned(), events: event_ids };
600 let _ = self.inner.redecryption_channels.utd_reporter.send(report);
601
602 Ok(())
603 }
604
605 async fn decrypt_event(
607 &self,
608 room_id: &RoomId,
609 room: Option<&Room>,
610 push_context: Option<&PushContext>,
611 event: &Raw<EncryptedEvent>,
612 ) -> Option<(DecryptedRoomEvent, Option<Vec<Action>>)> {
613 if let Some(room) = room {
614 match room
615 .decrypt_event(
616 event.cast_ref_unchecked::<OriginalSyncRoomEncryptedEvent>(),
617 push_context,
618 )
619 .await
620 {
621 Ok(maybe_decrypted) => {
622 let actions = maybe_decrypted.push_actions().map(|a| a.to_vec());
623
624 if let TimelineEventKind::Decrypted(decrypted) = maybe_decrypted.kind {
625 Some((decrypted, actions))
626 } else {
627 warn!(
628 "Failed to redecrypt an event despite receiving a room key or request to redecrypt"
629 );
630 None
631 }
632 }
633 Err(e) => {
634 warn!(
635 "Failed to redecrypt an event despite receiving a room key or request to redecrypt {e:?}"
636 );
637 None
638 }
639 }
640 } else {
641 let client = self.inner.client().ok()?;
642 let machine = client.olm_machine().await;
643 let machine = machine.as_ref()?;
644
645 match machine.decrypt_room_event(event, room_id, client.decryption_settings()).await {
646 Ok(decrypted) => Some((decrypted, None)),
647 Err(e) => {
648 warn!(
649 "Failed to redecrypt an event despite receiving a room key or a request to redecrypt {e:?}"
650 );
651 None
652 }
653 }
654 }
655 }
656
657 #[instrument(skip_all, fields(room_id, session_id))]
660 async fn retry_decryption(
661 &self,
662 room_id: &RoomId,
663 session_id: SessionId<'_>,
664 ) -> Result<(), EventCacheError> {
665 let events = self.all_encrypted_events(room_id, session_id).await?;
667 self.retry_decryption_for_events(room_id, events).await
668 }
669
670 #[instrument(skip_all, fields(updates.linked_chunk_id))]
672 async fn retry_decryption_for_event_cache_updates(
673 &self,
674 updates: RoomEventCacheLinkedChunkUpdate,
675 ) -> Result<(), EventCacheError> {
676 let room_id = updates.linked_chunk_id.room_id();
677 let events: Vec<_> = updates
678 .updates
679 .into_iter()
680 .flat_map(|updates| updates.into_items())
681 .filter_map(filter_timeline_event_to_utd)
682 .collect();
683
684 self.retry_decryption_for_events(room_id, events).await
685 }
686
687 async fn retry_decryption_for_in_memory_events(&self) {
688 let utds = self.all_in_memory_encrypted_events().await;
689
690 for (room_id, utds) in utds.into_iter() {
691 if let Err(e) = self.retry_decryption_for_events(&room_id, utds).await {
692 warn!(%room_id, "Failed to redecrypt in-memory events {e:?}");
693 }
694 }
695 }
696
697 #[instrument(skip_all, fields(room_id, session_id))]
699 async fn retry_decryption_for_events(
700 &self,
701 room_id: &RoomId,
702 events: Vec<EventIdAndUtd>,
703 ) -> Result<(), EventCacheError> {
704 trace!("Retrying to decrypt");
705
706 if events.is_empty() {
707 trace!("No relevant events found.");
708 return Ok(());
709 }
710
711 let room = self.inner.client().ok().and_then(|client| client.get_room(room_id));
712 let push_context =
713 if let Some(room) = &room { room.push_context().await.ok().flatten() } else { None };
714
715 let mut decrypted_events = Vec::with_capacity(events.len());
717
718 for (event_id, event) in events {
719 if let Some((decrypted_event, actions)) = self
723 .decrypt_event(
724 room_id,
725 room.as_ref(),
726 push_context.as_ref(),
727 event.cast_ref_unchecked(),
728 )
729 .await
730 {
731 decrypted_events.push(ResolvedUtd { event_id, decrypted_event, actions });
732 }
733 }
734
735 if !decrypted_events.is_empty() && tracing::level_enabled!(tracing::Level::TRACE) {
736 let event_ids: BTreeSet<_> =
737 decrypted_events.iter().map(|resolved_utd| &resolved_utd.event_id).collect();
738
739 trace!(?event_ids, "Successfully redecrypted events");
740 }
741
742 self.on_resolved_utds(room_id, decrypted_events).await?;
745
746 Ok(())
747 }
748
749 async fn update_encryption_info_for_events(
751 &self,
752 room: &Room,
753 events: Vec<EventIdAndEvent>,
754 ) -> Result<(), EventCacheError> {
755 let mut updated_events = Vec::with_capacity(events.len());
757
758 for (event_id, mut event) in events {
759 if let Some(session_id) = event.encryption_info.session_id() {
760 let new_encryption_info =
761 room.get_encryption_info(session_id, &event.encryption_info.sender).await;
762
763 if let Some(new_encryption_info) = new_encryption_info
766 && event.encryption_info != new_encryption_info
767 {
768 event.encryption_info = new_encryption_info;
769 updated_events.push(ResolvedUtd {
770 event_id,
771 decrypted_event: event,
772 actions: None,
773 });
774 }
775 }
776 }
777
778 if !updated_events.is_empty() && tracing::level_enabled!(tracing::Level::TRACE) {
779 let event_ids: BTreeSet<_> =
780 updated_events.iter().map(|resolved_utd| &resolved_utd.event_id).collect();
781
782 trace!(?event_ids, "Replacing the encryption info of some events");
783 }
784
785 self.on_resolved_utds(room.room_id(), updated_events).await
786 }
787
788 #[instrument(skip_all, fields(room_id, session_id))]
789 async fn update_encryption_info(
790 &self,
791 room_id: &RoomId,
792 session_id: SessionId<'_>,
793 ) -> Result<(), EventCacheError> {
794 trace!("Updating encryption info");
795
796 let Ok(client) = self.inner.client() else {
797 return Ok(());
798 };
799
800 let Some(room) = client.get_room(room_id) else {
801 return Ok(());
802 };
803
804 let events = self.all_decrypted_events(room_id, session_id).await?;
806
807 if events.is_empty() {
808 trace!("No relevant events found.");
809 return Ok(());
810 }
811
812 self.update_encryption_info_for_events(&room, events).await
814 }
815
816 async fn retry_update_encryption_info_for_in_memory_events(&self) {
817 let decrypted_events = self.all_in_memory_decrypted_events().await;
818
819 for (room_id, events) in decrypted_events.into_iter() {
820 let Some(room) = self.inner.client().ok().and_then(|c| c.get_room(&room_id)) else {
821 continue;
822 };
823
824 if let Err(e) = self.update_encryption_info_for_events(&room, events).await {
825 warn!(
826 %room_id,
827 "Failed to replace the encryption info for in-memory events {e:?}"
828 );
829 }
830 }
831 }
832
833 async fn retry_in_memory_events(&self) {
843 self.retry_decryption_for_in_memory_events().await;
844 self.retry_update_encryption_info_for_in_memory_events().await;
845 }
846
847 pub fn request_decryption(&self, request: DecryptionRetryRequest) {
887 let _ =
888 self.inner.redecryption_channels.decryption_request_sender.send(request).inspect_err(
889 |_| warn!("Requesting a decryption while the redecryption task has been shut down"),
890 );
891 }
892
893 pub fn subscribe_to_decryption_reports(
944 &self,
945 ) -> impl Stream<Item = Result<RedecryptorReport, BroadcastStreamRecvError>> {
946 BroadcastStream::new(self.inner.redecryption_channels.utd_reporter.subscribe())
947 }
948}
949
950#[inline(always)]
951fn upgrade_event_cache(cache: &Weak<EventCacheInner>) -> Option<EventCache> {
952 cache.upgrade().map(|inner| EventCache { inner })
953}
954
955async fn send_report_and_retry_memory_events(
956 cache: &Weak<EventCacheInner>,
957 report: RedecryptorReport,
958) -> Result<(), ()> {
959 let Some(cache) = upgrade_event_cache(cache) else {
960 return Err(());
961 };
962
963 cache.retry_in_memory_events().await;
964 let _ = cache.inner.redecryption_channels.utd_reporter.send(report);
965
966 Ok(())
967}
968
969pub(crate) struct Redecryptor {
976 _task: BackgroundTaskHandle,
977}
978
979impl Redecryptor {
980 pub(super) fn new(
985 client: &Client,
986 cache: Weak<EventCacheInner>,
987 receiver: UnboundedReceiver<DecryptionRetryRequest>,
988 linked_chunk_update_sender: &Sender<RoomEventCacheLinkedChunkUpdate>,
989 ) -> Self {
990 let linked_chunk_stream = BroadcastStream::new(linked_chunk_update_sender.subscribe());
991 let backup_state_stream = client.encryption().backups().state_stream();
992
993 let task = client
994 .task_monitor()
995 .spawn_infinite_task("event_cache::redecryptor", async {
996 let request_redecryption_stream = UnboundedReceiverStream::new(receiver);
997
998 Self::listen_for_room_keys_task(
999 cache,
1000 request_redecryption_stream,
1001 linked_chunk_stream,
1002 backup_state_stream,
1003 )
1004 .await;
1005 })
1006 .abort_on_drop();
1007
1008 Self { _task: task }
1009 }
1010
1011 async fn subscribe_to_room_key_stream(
1016 cache: &Weak<EventCacheInner>,
1017 ) -> Option<(
1018 impl Stream<Item = Result<Vec<RoomKeyInfo>, BroadcastStreamRecvError>>,
1019 impl Stream<Item = Vec<RoomKeyWithheldInfo>>,
1020 )> {
1021 let event_cache = cache.upgrade()?;
1022 let client = event_cache.client().ok()?;
1023 let machine = client.olm_machine().await;
1024
1025 machine.as_ref().map(|m| {
1026 (m.store().room_keys_received_stream(), m.store().room_keys_withheld_received_stream())
1027 })
1028 }
1029
1030 async fn redecryption_loop(
1031 cache: &Weak<EventCacheInner>,
1032 decryption_request_stream: &mut Pin<&mut impl Stream<Item = DecryptionRetryRequest>>,
1033 events_stream: &mut Pin<
1034 &mut impl Stream<Item = Result<RoomEventCacheLinkedChunkUpdate, BroadcastStreamRecvError>>,
1035 >,
1036 backup_state_stream: &mut Pin<
1037 &mut impl Stream<Item = Result<BackupState, BroadcastStreamRecvError>>,
1038 >,
1039 ) -> bool {
1040 let Some((room_key_stream, withheld_stream)) =
1041 Self::subscribe_to_room_key_stream(cache).await
1042 else {
1043 return false;
1044 };
1045
1046 pin_mut!(room_key_stream);
1047 pin_mut!(withheld_stream);
1048
1049 loop {
1050 tokio::select! {
1051 Some(request) = decryption_request_stream.next() => {
1055 let Some(cache) = upgrade_event_cache(cache) else {
1056 break false;
1057 };
1058
1059 trace!(?request, "Received a redecryption request");
1060
1061 for session_id in request.utd_session_ids {
1062 let _ = cache
1063 .retry_decryption(&request.room_id, &session_id)
1064 .await
1065 .inspect_err(|e| warn!("Error redecrypting after an explicit request was received {e:?}"));
1066 }
1067
1068 for session_id in request.refresh_info_session_ids {
1069 let _ = cache.update_encryption_info(&request.room_id, &session_id).await.inspect_err(|e|
1070 warn!(
1071 room_id = %request.room_id,
1072 session_id = session_id,
1073 "Unable to update the encryption info {e:?}",
1074 ));
1075 }
1076 }
1077 room_keys = room_key_stream.next() => {
1080 match room_keys {
1081 Some(Ok(room_keys)) => {
1082 let Some(cache) = upgrade_event_cache(cache) else {
1087 break false;
1088 };
1089
1090 trace!(?room_keys, "Received new room keys");
1091
1092 for key in &room_keys {
1093 let _ = cache
1094 .retry_decryption(&key.room_id, &key.session_id)
1095 .await
1096 .inspect_err(|e| warn!("Error redecrypting {e:?}"));
1097 }
1098
1099 for key in room_keys {
1100 let _ = cache.update_encryption_info(&key.room_id, &key.session_id).await.inspect_err(|e|
1101 warn!(
1102 room_id = %key.room_id,
1103 session_id = key.session_id,
1104 "Unable to update the encryption info {e:?}",
1105 ));
1106 }
1107 },
1108 Some(Err(_)) => {
1109 warn!("The room key stream lagged, reporting the lag to our listeners");
1117
1118 if send_report_and_retry_memory_events(cache, RedecryptorReport::Lagging).await.is_err() {
1119 break false;
1120 }
1121 },
1122 None => {
1126 break true;
1127 }
1128 }
1129 }
1130 withheld_info = withheld_stream.next() => {
1131 match withheld_info {
1132 Some(infos) => {
1133 let Some(cache) = upgrade_event_cache(cache) else {
1134 break false;
1135 };
1136
1137 trace!(?infos, "Received new withheld infos");
1138
1139 for RoomKeyWithheldInfo { room_id, session_id, .. } in &infos {
1140 let _ = cache.update_encryption_info(room_id, session_id).await.inspect_err(|e|
1141 warn!(
1142 room_id = %room_id,
1143 session_id = session_id,
1144 "Unable to update the encryption info {e:?}",
1145 ));
1146 }
1147 }
1148 None => break true,
1151 }
1152 }
1153 Some(event_updates) = events_stream.next() => {
1158 match event_updates {
1159 Ok(updates) => {
1160 let Some(cache) = upgrade_event_cache(cache) else {
1161 break false;
1162 };
1163
1164 let linked_chunk_id = updates.linked_chunk_id.to_owned();
1165
1166 let _ = cache.retry_decryption_for_event_cache_updates(updates).await.inspect_err(|e|
1167 warn!(
1168 %linked_chunk_id,
1169 "Unable to handle UTDs from event cache updates {e:?}",
1170 )
1171 );
1172 }
1173 Err(_) => {
1174 if send_report_and_retry_memory_events(cache, RedecryptorReport::Lagging).await.is_err() {
1175 break false;
1176 }
1177 }
1178 }
1179 }
1180 Some(backup_state_update) = backup_state_stream.next() => {
1181 match backup_state_update {
1182 Ok(state) => {
1183 match state {
1184 BackupState::Unknown |
1185 BackupState::Creating |
1186 BackupState::Enabling |
1187 BackupState::Resuming |
1188 BackupState::Downloading |
1189 BackupState::Disabling =>{
1190 }
1194 BackupState::Enabled => {
1195 if send_report_and_retry_memory_events(cache, RedecryptorReport::BackupAvailable).await.is_err() {
1202 break false;
1203 }
1204 }
1205 }
1206 }
1207 Err(_) => {
1208 if send_report_and_retry_memory_events(cache, RedecryptorReport::Lagging).await.is_err() {
1209 break false;
1210 }
1211 }
1212 }
1213 }
1214 else => break false,
1215 }
1216 }
1217 }
1218
1219 async fn listen_for_room_keys_task(
1220 cache: Weak<EventCacheInner>,
1221 decryption_request_stream: UnboundedReceiverStream<DecryptionRetryRequest>,
1222 events_stream: BroadcastStream<RoomEventCacheLinkedChunkUpdate>,
1223 backup_state_stream: impl Stream<Item = Result<BackupState, BroadcastStreamRecvError>>,
1224 ) {
1225 pin_mut!(decryption_request_stream);
1229 pin_mut!(events_stream);
1230 pin_mut!(backup_state_stream);
1231
1232 while Self::redecryption_loop(
1233 &cache,
1234 &mut decryption_request_stream,
1235 &mut events_stream,
1236 &mut backup_state_stream,
1237 )
1238 .await
1239 {
1240 info!("Regenerating the re-decryption streams");
1241
1242 if send_report_and_retry_memory_events(&cache, RedecryptorReport::Lagging)
1246 .await
1247 .is_err()
1248 {
1249 break;
1250 }
1251 }
1252
1253 info!("Shutting down the event cache redecryptor");
1254 }
1255}
1256
1257#[cfg(not(target_family = "wasm"))]
1258#[cfg(test)]
1259mod tests {
1260 use std::{
1261 assert_matches,
1262 collections::BTreeSet,
1263 sync::{
1264 Arc,
1265 atomic::{AtomicBool, Ordering},
1266 },
1267 time::Duration,
1268 };
1269
1270 use async_trait::async_trait;
1271 use eyeball_im::VectorDiff;
1272 use matrix_sdk_base::{
1273 cross_process_lock::CrossProcessLockGeneration,
1274 crypto::types::events::{ToDeviceEvent, room::encrypted::ToDeviceEncryptedEventContent},
1275 deserialized_responses::{TimelineEventKind, VerificationState},
1276 event_cache::{
1277 Event, Gap,
1278 store::{EventCacheStore, EventCacheStoreError, MemoryStore},
1279 thread::ThreadInfo,
1280 },
1281 linked_chunk::{
1282 ChunkIdentifier, ChunkIdentifierGenerator, ChunkMetadata, LinkedChunkId, Position,
1283 RawChunk, Update,
1284 },
1285 locks::Mutex,
1286 sleep::sleep,
1287 store::StoreConfig,
1288 };
1289 use matrix_sdk_common::cross_process_lock::CrossProcessLockConfig;
1290 use matrix_sdk_test::{JoinedRoomBuilder, async_test, event_factory::EventFactory};
1291 use ruma::{
1292 EventId, OwnedEventId, RoomId, RoomVersionId, device_id, event_id,
1293 events::{AnySyncTimelineEvent, relation::RelationType},
1294 room_id,
1295 serde::Raw,
1296 user_id,
1297 };
1298 use serde_json::json;
1299 use strass::assert_let;
1300 use tokio::sync::oneshot::{self, Sender};
1301 use tracing::{Instrument, info};
1302
1303 use crate::{
1304 Client, assert_let_timeout,
1305 encryption::EncryptionSettings,
1306 event_cache::{
1307 DecryptionRetryRequest, RoomEventCacheGenericUpdate, RoomEventCacheUpdate,
1308 TimelineVectorDiffs,
1309 },
1310 test_utils::mocks::MatrixMockServer,
1311 };
1312
1313 #[derive(Debug, Clone)]
1318 struct DelayingStore {
1319 memory_store: MemoryStore,
1320 delaying: Arc<AtomicBool>,
1321 foo: Arc<Mutex<Option<Sender<()>>>>,
1322 }
1323
1324 impl DelayingStore {
1325 fn new() -> Self {
1326 Self {
1327 memory_store: MemoryStore::new(),
1328 delaying: AtomicBool::new(true).into(),
1329 foo: Arc::new(Mutex::new(None)),
1330 }
1331 }
1332
1333 async fn stop_delaying(&self) {
1334 let (sender, receiver) = oneshot::channel();
1335
1336 {
1337 *self.foo.lock() = Some(sender);
1338 }
1339
1340 self.delaying.store(false, Ordering::SeqCst);
1341
1342 receiver.await.expect("We should be able to receive a response")
1343 }
1344 }
1345
1346 #[cfg_attr(target_family = "wasm", async_trait(?Send))]
1347 #[cfg_attr(not(target_family = "wasm"), async_trait)]
1348 impl EventCacheStore for DelayingStore {
1349 type Error = EventCacheStoreError;
1350
1351 async fn close(&self) -> Result<(), EventCacheStoreError> {
1352 self.memory_store.close().await
1353 }
1354
1355 async fn reopen(&self) -> Result<(), EventCacheStoreError> {
1356 self.memory_store.reopen().await
1357 }
1358
1359 async fn try_take_leased_lock(
1360 &self,
1361 lease_duration_ms: u32,
1362 key: &str,
1363 holder: &str,
1364 ) -> Result<Option<CrossProcessLockGeneration>, Self::Error> {
1365 self.memory_store.try_take_leased_lock(lease_duration_ms, key, holder).await
1366 }
1367
1368 async fn handle_linked_chunk_updates(
1369 &self,
1370 linked_chunk_id: LinkedChunkId<'_>,
1371 updates: Vec<Update<Event, Gap>>,
1372 ) -> Result<(), Self::Error> {
1373 while self.delaying.load(Ordering::SeqCst) {
1379 sleep(Duration::from_millis(10)).await;
1380 }
1381
1382 let sender = self.foo.lock().take();
1383 let ret = self.memory_store.handle_linked_chunk_updates(linked_chunk_id, updates).await;
1384
1385 if let Some(sender) = sender {
1386 sender.send(()).expect("We should be able to notify the other side that we're done with the storage operation");
1387 }
1388
1389 ret
1390 }
1391
1392 async fn load_all_chunks(
1393 &self,
1394 linked_chunk_id: LinkedChunkId<'_>,
1395 ) -> Result<Vec<RawChunk<Event, Gap>>, Self::Error> {
1396 self.memory_store.load_all_chunks(linked_chunk_id).await
1397 }
1398
1399 async fn load_all_chunks_metadata(
1400 &self,
1401 linked_chunk_id: LinkedChunkId<'_>,
1402 ) -> Result<Vec<ChunkMetadata>, Self::Error> {
1403 self.memory_store.load_all_chunks_metadata(linked_chunk_id).await
1404 }
1405
1406 async fn load_last_chunk(
1407 &self,
1408 linked_chunk_id: LinkedChunkId<'_>,
1409 ) -> Result<(Option<RawChunk<Event, Gap>>, ChunkIdentifierGenerator), Self::Error> {
1410 self.memory_store.load_last_chunk(linked_chunk_id).await
1411 }
1412
1413 async fn load_previous_chunk(
1414 &self,
1415 linked_chunk_id: LinkedChunkId<'_>,
1416 before_chunk_identifier: ChunkIdentifier,
1417 ) -> Result<Option<RawChunk<Event, Gap>>, Self::Error> {
1418 self.memory_store.load_previous_chunk(linked_chunk_id, before_chunk_identifier).await
1419 }
1420
1421 async fn load_thread_info(
1422 &self,
1423 room_id: &RoomId,
1424 thread_id: &EventId,
1425 insert_default_if_missing: bool,
1426 ) -> Result<Option<ThreadInfo>, Self::Error> {
1427 self.memory_store.load_thread_info(room_id, thread_id, insert_default_if_missing).await
1428 }
1429
1430 async fn update_thread_info(
1431 &self,
1432 room_id: &RoomId,
1433 thread_id: &EventId,
1434 thread_info: &ThreadInfo,
1435 ) -> Result<(), Self::Error> {
1436 self.memory_store.update_thread_info(room_id, thread_id, thread_info).await
1437 }
1438
1439 async fn clear_all_events(&self, room_id: Option<&RoomId>) -> Result<(), Self::Error> {
1440 self.memory_store.clear_all_events(room_id).await
1441 }
1442
1443 async fn filter_duplicated_events(
1444 &self,
1445 linked_chunk_id: LinkedChunkId<'_>,
1446 events: Vec<OwnedEventId>,
1447 ) -> Result<Vec<(OwnedEventId, Position)>, Self::Error> {
1448 self.memory_store.filter_duplicated_events(linked_chunk_id, events).await
1449 }
1450
1451 async fn find_event(
1452 &self,
1453 room_id: &RoomId,
1454 event_id: &EventId,
1455 ) -> Result<Option<Event>, Self::Error> {
1456 self.memory_store.find_event(room_id, event_id).await
1457 }
1458
1459 async fn find_event_relations(
1460 &self,
1461 room_id: &RoomId,
1462 event_id: &EventId,
1463 filters: Option<&[RelationType]>,
1464 ) -> Result<Vec<(Event, Option<Position>)>, Self::Error> {
1465 self.memory_store.find_event_relations(room_id, event_id, filters).await
1466 }
1467
1468 async fn get_room_events(
1469 &self,
1470 room_id: &RoomId,
1471 event_type: Option<&str>,
1472 session_id: Option<&str>,
1473 ) -> Result<Vec<Event>, Self::Error> {
1474 self.memory_store.get_room_events(room_id, event_type, session_id).await
1475 }
1476
1477 async fn save_event(&self, room_id: &RoomId, event: Event) -> Result<(), Self::Error> {
1478 self.memory_store.save_event(room_id, event).await
1479 }
1480
1481 async fn optimize(&self) -> Result<(), Self::Error> {
1482 self.memory_store.optimize().await
1483 }
1484
1485 async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1486 self.memory_store.get_size().await
1487 }
1488 }
1489
1490 async fn set_up_clients(
1491 room_id: &RoomId,
1492 alice_enables_cross_signing: bool,
1493 use_delayed_store: bool,
1494 ) -> (Client, Client, MatrixMockServer, Option<DelayingStore>) {
1495 let alice_span = tracing::info_span!("alice");
1496 let bob_span = tracing::info_span!("bob");
1497
1498 let alice_user_id = user_id!("@alice:localhost");
1499 let alice_device_id = device_id!("ALICEDEVICE");
1500 let bob_user_id = user_id!("@bob:localhost");
1501 let bob_device_id = device_id!("BOBDEVICE");
1502
1503 let matrix_mock_server = MatrixMockServer::new().await;
1504 matrix_mock_server.mock_crypto_endpoints_preset().await;
1505
1506 let encryption_settings = EncryptionSettings {
1507 auto_enable_cross_signing: alice_enables_cross_signing,
1508 ..Default::default()
1509 };
1510
1511 let alice = matrix_mock_server
1514 .client_builder_for_crypto_end_to_end(alice_user_id, alice_device_id)
1515 .on_builder(|builder| {
1516 builder
1517 .with_enable_share_history_on_invite(true)
1518 .with_encryption_settings(encryption_settings)
1519 })
1520 .build()
1521 .instrument(alice_span.clone())
1522 .await;
1523
1524 let encryption_settings =
1525 EncryptionSettings { auto_enable_cross_signing: true, ..Default::default() };
1526
1527 let (store_config, store) = if use_delayed_store {
1528 let store = DelayingStore::new();
1529
1530 (
1531 StoreConfig::new(CrossProcessLockConfig::multi_process(
1532 "delayed_store_event_cache_test",
1533 ))
1534 .event_cache_store(store.clone()),
1535 Some(store),
1536 )
1537 } else {
1538 (
1539 StoreConfig::new(CrossProcessLockConfig::multi_process(
1540 "normal_store_event_cache_test",
1541 )),
1542 None,
1543 )
1544 };
1545
1546 let bob = matrix_mock_server
1547 .client_builder_for_crypto_end_to_end(bob_user_id, bob_device_id)
1548 .on_builder(|builder| {
1549 builder
1550 .with_enable_share_history_on_invite(true)
1551 .with_encryption_settings(encryption_settings)
1552 .store_config(store_config)
1553 })
1554 .build()
1555 .instrument(bob_span.clone())
1556 .await;
1557
1558 bob.event_cache().subscribe().expect("Bob should be able to enable the event cache");
1559
1560 matrix_mock_server.exchange_e2ee_identities(&alice, &bob).await;
1562
1563 let event_factory = EventFactory::new().room(room_id).sender(alice_user_id);
1564
1565 let room_builder = JoinedRoomBuilder::new(room_id)
1567 .add_state_event(event_factory.create(alice_user_id, RoomVersionId::V1))
1568 .add_state_event(event_factory.room_encryption());
1569
1570 matrix_mock_server
1571 .mock_sync()
1572 .ok_and_run(&alice, |builder| {
1573 builder.add_joined_room(room_builder.clone());
1574 })
1575 .instrument(alice_span)
1576 .await;
1577
1578 matrix_mock_server
1579 .mock_sync()
1580 .ok_and_run(&bob, |builder| {
1581 builder.add_joined_room(room_builder);
1582 })
1583 .instrument(bob_span)
1584 .await;
1585
1586 (alice, bob, matrix_mock_server, store)
1587 }
1588
1589 async fn prepare_room(
1590 matrix_mock_server: &MatrixMockServer,
1591 event_factory: &EventFactory,
1592 alice: &Client,
1593 bob: &Client,
1594 room_id: &RoomId,
1595 ) -> (Raw<AnySyncTimelineEvent>, Raw<ToDeviceEvent<ToDeviceEncryptedEventContent>>) {
1596 let alice_user_id = alice.user_id().unwrap();
1597 let bob_user_id = bob.user_id().unwrap();
1598
1599 let alice_member_event = event_factory.member(alice_user_id).into_raw();
1600 let bob_member_event = event_factory.member(bob_user_id).into_raw();
1601
1602 let room = alice
1603 .get_room(room_id)
1604 .expect("Alice should have access to the room now that we synced");
1605
1606 let event_type = "m.room.message";
1611 let content = json!({"body": "It's a secret to everybody", "msgtype": "m.text"});
1612
1613 let event_id = event_id!("$some_id");
1614 let (event_receiver, mock) =
1615 matrix_mock_server.mock_room_send().ok_with_capture(event_id, alice_user_id);
1616 let (_guard, room_key) = matrix_mock_server.mock_capture_put_to_device(alice_user_id).await;
1617
1618 {
1619 let _guard = mock.mock_once().mount_as_scoped().await;
1620
1621 matrix_mock_server
1622 .mock_get_members()
1623 .ok(vec![alice_member_event.clone(), bob_member_event.clone()])
1624 .mock_once()
1625 .mount()
1626 .await;
1627
1628 room.send_raw(event_type, content)
1629 .await
1630 .expect("We should be able to send an initial message");
1631 };
1632
1633 let event = event_receiver.await.expect("Alice should have sent the event by now");
1635 let room_key = room_key.await;
1636
1637 (event, room_key)
1638 }
1639
1640 #[async_test]
1641 async fn test_redecryptor() {
1642 let room_id = room_id!("!test:localhost");
1643
1644 let event_factory = EventFactory::new().room(room_id);
1645 let (alice, bob, matrix_mock_server, _) = set_up_clients(room_id, true, false).await;
1646
1647 let (event, room_key) =
1648 prepare_room(&matrix_mock_server, &event_factory, &alice, &bob, room_id).await;
1649
1650 let event_cache = bob.event_cache();
1653 let (room_cache, _) = event_cache
1654 .room(room_id)
1655 .await
1656 .expect("We should be able to get to the event cache for a specific room");
1657
1658 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1659 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1660
1661 bob.inner
1664 .base_client
1665 .regenerate_olm(None)
1666 .await
1667 .expect("We should be able to regenerate the Olm machine");
1668
1669 matrix_mock_server
1671 .mock_sync()
1672 .ok_and_run(&bob, |builder| {
1673 builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(event));
1674 })
1675 .await;
1676
1677 assert_let_timeout!(
1680 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1681 subscriber.recv()
1682 );
1683
1684 assert_eq!(diffs.len(), 1);
1687 assert_let!(VectorDiff::Append { values } = &diffs[0]);
1688 assert_eq!(values.len(), 1);
1689 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
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 matrix_mock_server
1699 .mock_sync()
1700 .ok_and_run(&bob, |builder| {
1701 builder.add_to_device_event(
1702 room_key
1703 .deserialize_as()
1704 .expect("We should be able to deserialize the room key"),
1705 );
1706 })
1707 .await;
1708
1709 assert_let_timeout!(
1711 Duration::from_secs(1),
1712 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1713 subscriber.recv()
1714 );
1715
1716 assert_eq!(diffs.len(), 1);
1718 assert_let!(VectorDiff::Set { index, value } = &diffs[0]);
1719 assert_eq!(*index, 0);
1720 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1721
1722 assert_let_timeout!(
1723 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1724 );
1725 assert_eq!(expected_room_id, room_id);
1726 assert!(generic_stream.is_empty());
1727 }
1728
1729 #[async_test]
1730 async fn test_redecryptor_updating_encryption_info() {
1731 let bob_span = tracing::info_span!("bob");
1732
1733 let room_id = room_id!("!test:localhost");
1734
1735 let event_factory = EventFactory::new().room(room_id);
1736 let (alice, bob, matrix_mock_server, _) = set_up_clients(room_id, false, false).await;
1737
1738 let (event, room_key) =
1739 prepare_room(&matrix_mock_server, &event_factory, &alice, &bob, room_id).await;
1740
1741 let event_cache = bob.event_cache();
1744 let (room_cache, _) = event_cache
1745 .room(room_id)
1746 .instrument(bob_span.clone())
1747 .await
1748 .expect("We should be able to get to the event cache for a specific room");
1749
1750 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1751 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1752
1753 matrix_mock_server
1755 .mock_sync()
1756 .ok_and_run(&bob, |builder| {
1757 builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(event));
1758 })
1759 .instrument(bob_span.clone())
1760 .await;
1761
1762 assert_let_timeout!(
1765 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1766 subscriber.recv()
1767 );
1768
1769 assert_eq!(diffs.len(), 1);
1772 assert_let!(VectorDiff::Append { values } = &diffs[0]);
1773 assert_eq!(values.len(), 1);
1774 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1775
1776 assert_let_timeout!(
1777 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1778 );
1779 assert_eq!(expected_room_id, room_id);
1780 assert!(generic_stream.is_empty());
1781
1782 matrix_mock_server
1784 .mock_sync()
1785 .ok_and_run(&bob, |builder| {
1786 builder.add_to_device_event(
1787 room_key
1788 .deserialize_as()
1789 .expect("We should be able to deserialize the room key"),
1790 );
1791 })
1792 .instrument(bob_span.clone())
1793 .await;
1794
1795 assert_let_timeout!(
1797 Duration::from_secs(1),
1798 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1799 subscriber.recv()
1800 );
1801
1802 assert_eq!(diffs.len(), 1);
1804 assert_let!(VectorDiff::Set { index: 0, value } = &diffs[0]);
1805 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1806
1807 let encryption_info = value.encryption_info().unwrap();
1808 assert_matches!(&encryption_info.verification_state, VerificationState::Unverified(_));
1809
1810 assert_let_timeout!(
1811 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1812 );
1813 assert_eq!(expected_room_id, room_id);
1814 assert!(generic_stream.is_empty());
1815
1816 let session_id = encryption_info.session_id().unwrap().to_owned();
1817 let alice_user_id = alice.user_id().unwrap();
1818
1819 alice
1821 .encryption()
1822 .bootstrap_cross_signing(None)
1823 .await
1824 .expect("Alice should be able to create the cross-signing keys");
1825
1826 bob.update_tracked_users_for_testing([alice_user_id]).instrument(bob_span.clone()).await;
1827 matrix_mock_server
1828 .mock_sync()
1829 .ok_and_run(&bob, |builder| {
1830 builder.add_change_device(alice_user_id);
1831 })
1832 .instrument(bob_span.clone())
1833 .await;
1834
1835 bob.event_cache().request_decryption(DecryptionRetryRequest {
1836 room_id: room_id.into(),
1837 utd_session_ids: BTreeSet::new(),
1838 refresh_info_session_ids: BTreeSet::from([session_id]),
1839 });
1840
1841 assert_let_timeout!(
1844 Duration::from_secs(1),
1845 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1846 subscriber.recv()
1847 );
1848
1849 assert_eq!(diffs.len(), 1);
1850 assert_let!(VectorDiff::Set { index: 0, value } = &diffs[0]);
1851 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1852 let encryption_info = value.encryption_info().unwrap();
1853
1854 assert_matches!(
1855 &encryption_info.verification_state,
1856 VerificationState::Unverified(_),
1857 "The event should now know about the identity but still be unverified"
1858 );
1859
1860 assert_let_timeout!(
1861 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1862 );
1863 assert_eq!(expected_room_id, room_id);
1864 assert!(generic_stream.is_empty());
1865 }
1866
1867 #[async_test]
1868 async fn test_event_is_redecrypted_even_if_key_arrives_while_event_processing() {
1869 let room_id = room_id!("!test:localhost");
1870
1871 let event_factory = EventFactory::new().room(room_id);
1872 let (alice, bob, matrix_mock_server, delayed_store) =
1873 set_up_clients(room_id, true, true).await;
1874
1875 let delayed_store = delayed_store.unwrap();
1876
1877 let (event, room_key) =
1878 prepare_room(&matrix_mock_server, &event_factory, &alice, &bob, room_id).await;
1879
1880 let event_cache = bob.event_cache();
1881
1882 let (room_cache, _) = event_cache
1884 .room(room_id)
1885 .await
1886 .expect("We should be able to get to the event cache for a specific room");
1887
1888 let (_, mut subscriber) = room_cache.subscribe().await.unwrap();
1889 let mut generic_stream = event_cache.subscribe_to_room_generic_updates();
1890
1891 matrix_mock_server
1893 .mock_sync()
1894 .ok_and_run(&bob, |builder| {
1895 builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(event));
1896 })
1897 .await;
1898
1899 matrix_mock_server
1901 .mock_sync()
1902 .ok_and_run(&bob, |builder| {
1903 builder.add_to_device_event(
1904 room_key
1905 .deserialize_as()
1906 .expect("We should be able to deserialize the room key"),
1907 );
1908 })
1909 .await;
1910
1911 info!("Stopping the delay");
1912 delayed_store.stop_delaying().await;
1913
1914 assert_let_timeout!(
1920 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1921 subscriber.recv()
1922 );
1923
1924 assert_eq!(diffs.len(), 1);
1927 assert_let!(VectorDiff::Append { values } = &diffs[0]);
1928 assert_eq!(values.len(), 1);
1929 assert_matches!(&values[0].kind, TimelineEventKind::UnableToDecrypt { .. });
1930
1931 assert_let_timeout!(
1933 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1934 );
1935 assert_eq!(expected_room_id, room_id);
1936
1937 assert_let_timeout!(
1939 Duration::from_secs(1),
1940 Ok(RoomEventCacheUpdate::UpdateTimelineEvents(TimelineVectorDiffs { diffs, .. })) =
1941 subscriber.recv()
1942 );
1943
1944 assert_eq!(diffs.len(), 1);
1946 assert_let!(VectorDiff::Set { index, value } = &diffs[0]);
1947 assert_eq!(*index, 0);
1948 assert_matches!(&value.kind, TimelineEventKind::Decrypted { .. });
1949
1950 assert_let_timeout!(
1952 Ok(RoomEventCacheGenericUpdate { room_id: expected_room_id }) = generic_stream.recv()
1953 );
1954 assert_eq!(expected_room_id, room_id);
1955 assert!(generic_stream.is_empty());
1956 }
1957}