Skip to content

Commit 0ca35d6

Browse files
committed
test: Test that room keys received by notification clients trigger redecryptions
1 parent daeffc0 commit 0ca35d6

File tree

1 file changed

+170
-4
lines changed
  • testing/matrix-sdk-integration-testing/src/tests

1 file changed

+170
-4
lines changed

testing/matrix-sdk-integration-testing/src/tests/timeline.rs

Lines changed: 170 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,20 @@ use matrix_sdk::{
2525
encryption::{backups::BackupState, EncryptionSettings},
2626
room::edit::EditedContent,
2727
ruma::{
28-
api::client::room::create_room::v3::Request as CreateRoomRequest,
28+
api::client::room::create_room::v3::{Request as CreateRoomRequest, RoomPreset},
2929
events::{
3030
room::{encryption::RoomEncryptionEventContent, message::RoomMessageEventContent},
3131
InitialStateEvent,
3232
},
3333
MilliSecondsSinceUnixEpoch,
3434
},
35+
RoomState,
3536
};
36-
use matrix_sdk_ui::timeline::{
37-
EventSendState, ReactionStatus, RoomExt, TimelineItem, TimelineItemContent,
37+
use matrix_sdk_ui::{
38+
notification_client::NotificationClient,
39+
room_list_service::RoomListLoadingState,
40+
sync_service::SyncService,
41+
timeline::{EventSendState, ReactionStatus, RoomExt, TimelineItem, TimelineItemContent},
3842
};
3943
use similar_asserts::assert_eq;
4044
use tokio::{
@@ -357,7 +361,7 @@ async fn test_enabling_backups_retries_decryption() {
357361
.create_room(assign!(CreateRoomRequest::new(), {
358362
is_direct: true,
359363
initial_state,
360-
preset: Some(matrix_sdk::ruma::api::client::room::create_room::v3::RoomPreset::PrivateChat)
364+
preset: Some(RoomPreset::PrivateChat)
361365
}))
362366
.await
363367
.unwrap();
@@ -462,3 +466,165 @@ async fn test_enabling_backups_retries_decryption() {
462466

463467
bob_sync.abort();
464468
}
469+
470+
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
471+
async fn test_room_keys_received_on_notification_client_trigger_redecryption() {
472+
let alice = TestClientBuilder::new("alice").use_sqlite().build().await.unwrap();
473+
alice.encryption().wait_for_e2ee_initialization_tasks().await;
474+
475+
// Set up sync for user Alice, and create a room.
476+
let alice_sync = spawn({
477+
let alice = alice.clone();
478+
async move {
479+
alice.sync(Default::default()).await.expect("sync failed!");
480+
}
481+
});
482+
483+
debug!("Creating the room…");
484+
485+
// The room needs to be encrypted.
486+
let initial_state =
487+
vec![InitialStateEvent::new(RoomEncryptionEventContent::with_recommended_defaults())
488+
.to_raw_any()];
489+
490+
let alice_room = alice
491+
.create_room(assign!(CreateRoomRequest::new(), {
492+
is_direct: true,
493+
initial_state,
494+
preset: Some(RoomPreset::PrivateChat)
495+
}))
496+
.await
497+
.unwrap();
498+
499+
assert!(alice_room
500+
.is_encrypted()
501+
.await
502+
.expect("We should be able to check that the room is encrypted"));
503+
504+
// Now here comes bob.
505+
let bob = TestClientBuilder::new("bob").use_sqlite().build().await.unwrap();
506+
bob.encryption().wait_for_e2ee_initialization_tasks().await;
507+
508+
debug!("Inviting Bob.");
509+
510+
alice_room
511+
.invite_user_by_id(bob.user_id().expect("We should have access to bob's user ID"))
512+
.await
513+
.expect("We should be able to invite Bob to the room");
514+
515+
// Sync once to get access to the room.
516+
let sync_service = SyncService::builder(bob.clone()).build().await.expect("Wat");
517+
sync_service.start().await;
518+
519+
let bob_rooms = sync_service
520+
.room_list_service()
521+
.all_rooms()
522+
.await
523+
.expect("We should be able to get the room");
524+
525+
debug!("Waiting for the room list to load");
526+
let wait_for_room_list_load = async {
527+
while let Some(state) = bob_rooms.loading_state().next().await {
528+
if let RoomListLoadingState::Loaded { .. } = state {
529+
break;
530+
}
531+
}
532+
};
533+
534+
timeout(Duration::from_secs(5), wait_for_room_list_load)
535+
.await
536+
.expect("We should be able to load the room list");
537+
538+
// Bob joins the room.
539+
let bob_room =
540+
bob.get_room(alice_room.room_id()).expect("We should have access to the room now");
541+
bob_room.join().await.expect("Bob should be able to join the room");
542+
543+
debug!("Bob joined the room");
544+
assert_eq!(bob_room.state(), RoomState::Joined);
545+
assert!(bob_room.is_encrypted().await.unwrap());
546+
547+
// Let's stop the sync so we don't receive the room key using the usual channel.
548+
sync_service.stop().await.expect("We should be able to stop the sync service");
549+
550+
debug!("Alice sends the message");
551+
let event_id = alice_room
552+
.send(RoomMessageEventContent::text_plain("It's a secret to everybody!"))
553+
.await
554+
.expect("We should be able to send a message to our new room")
555+
.event_id;
556+
557+
// We don't need Alice anymore.
558+
alice_sync.abort();
559+
560+
// Let's get the timeline and backpaginate to load the event.
561+
let mut timeline =
562+
bob_room.timeline().await.expect("We should be able to get a timeline for our room");
563+
564+
let mut item = None;
565+
566+
for _ in 0..10 {
567+
timeline
568+
.paginate_backwards(50)
569+
.await
570+
.expect("We should be able to paginate the timeline to fetch the history");
571+
572+
if let Some(timeline_item) = timeline.item_by_event_id(&event_id).await {
573+
item = Some(timeline_item);
574+
break;
575+
} else {
576+
timeline = bob_room.timeline().await.expect("We should be able to reset our timeline");
577+
sleep(Duration::from_millis(100)).await
578+
}
579+
}
580+
581+
let item = item.expect("The event should be in the timeline by now");
582+
583+
// The event is not decrypted yet.
584+
assert_matches!(item.content(), TimelineItemContent::UnableToDecrypt(_));
585+
586+
// Let's subscribe to our timeline so we don't miss the transition from UTD to
587+
// decrypted event.
588+
let (_, mut stream) = timeline
589+
.subscribe_filter_map(|item| {
590+
item.as_event().cloned().filter(|item| item.event_id() == Some(&event_id))
591+
})
592+
.await;
593+
594+
// Now we create a notification client.
595+
let notification_client = bob
596+
.notification_client("BOB_NOTIFICATION_CLIENT".to_owned())
597+
.await
598+
.expect("We should be able to build a notification client");
599+
600+
// This syncs and fetches the room key.
601+
debug!("The notification client syncs");
602+
let notification_client = NotificationClient::new(
603+
notification_client,
604+
matrix_sdk_ui::notification_client::NotificationProcessSetup::SingleProcess {
605+
sync_service: sync_service.into(),
606+
},
607+
)
608+
.await
609+
.expect("We should be able to build a notification client");
610+
611+
let _ = notification_client
612+
.get_notification(bob_room.room_id(), &event_id)
613+
.await
614+
.expect("We should be able toe get a notification item for the given event");
615+
616+
// Alright, we should now receive an update that the event had been decrypted.
617+
let _vector_diff = timeout(Duration::from_secs(5), stream.next()).await.unwrap().unwrap();
618+
619+
// Let's fetch the event again.
620+
let item =
621+
timeline.item_by_event_id(&event_id).await.expect("The event should be in the timeline");
622+
623+
// Yup it's decrypted great.
624+
assert_let!(
625+
TimelineItemContent::Message(message) = item.content(),
626+
"The event should have been decrypted now"
627+
);
628+
629+
assert_eq!(message.body(), "It's a secret to everybody!");
630+
}

0 commit comments

Comments
 (0)