@@ -25,16 +25,20 @@ use matrix_sdk::{
25
25
encryption:: { backups:: BackupState , EncryptionSettings } ,
26
26
room:: edit:: EditedContent ,
27
27
ruma:: {
28
- api:: client:: room:: create_room:: v3:: Request as CreateRoomRequest ,
28
+ api:: client:: room:: create_room:: v3:: { Request as CreateRoomRequest , RoomPreset } ,
29
29
events:: {
30
30
room:: { encryption:: RoomEncryptionEventContent , message:: RoomMessageEventContent } ,
31
31
InitialStateEvent ,
32
32
} ,
33
33
MilliSecondsSinceUnixEpoch ,
34
34
} ,
35
+ RoomState ,
35
36
} ;
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 } ,
38
42
} ;
39
43
use similar_asserts:: assert_eq;
40
44
use tokio:: {
@@ -357,7 +361,7 @@ async fn test_enabling_backups_retries_decryption() {
357
361
. create_room ( assign ! ( CreateRoomRequest :: new( ) , {
358
362
is_direct: true ,
359
363
initial_state,
360
- preset: Some ( matrix_sdk :: ruma :: api :: client :: room :: create_room :: v3 :: RoomPreset :: PrivateChat )
364
+ preset: Some ( RoomPreset :: PrivateChat )
361
365
} ) )
362
366
. await
363
367
. unwrap ( ) ;
@@ -462,3 +466,165 @@ async fn test_enabling_backups_retries_decryption() {
462
466
463
467
bob_sync. abort ( ) ;
464
468
}
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