@@ -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,154 @@ 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_foobar ( ) {
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
+ match state {
529
+ RoomListLoadingState :: Loaded { .. } => break ,
530
+ _ => ( ) ,
531
+ }
532
+ }
533
+ } ;
534
+
535
+ timeout ( Duration :: from_secs ( 5 ) , wait_for_room_list_load)
536
+ . await
537
+ . expect ( "We should be able to load the room list" ) ;
538
+
539
+ // Bob joins the room.
540
+ let bob_room =
541
+ bob. get_room ( alice_room. room_id ( ) ) . expect ( "We should have access to the room now" ) ;
542
+ bob_room. join ( ) . await . expect ( "Bob should be able to join the room" ) ;
543
+
544
+ debug ! ( "Bob joined the room" ) ;
545
+ assert_eq ! ( bob_room. state( ) , RoomState :: Joined ) ;
546
+ assert ! ( bob_room. is_encrypted( ) . await . unwrap( ) ) ;
547
+
548
+ // Let's stop the sync so we don't receive the room key using the usual channel.
549
+ sync_service. stop ( ) . await . expect ( "We should be able to stop the sync service" ) ;
550
+
551
+ debug ! ( "Alice sends the message" ) ;
552
+ let event_id = alice_room
553
+ . send ( RoomMessageEventContent :: text_plain ( "It's a secret to everybody!" ) )
554
+ . await
555
+ . expect ( "We should be able to send a message to our new room" )
556
+ . event_id ;
557
+
558
+ // We don't need Alice anymore.
559
+ alice_sync. abort ( ) ;
560
+
561
+ // Let's get the timeline and backpaginate to load the event.
562
+ let timeline =
563
+ bob_room. timeline ( ) . await . expect ( "We should be able to get a timeline for our room" ) ;
564
+
565
+ timeline
566
+ . paginate_backwards ( 50 )
567
+ . await
568
+ . expect ( "We should be able to paginate the timeline to fetch the history" ) ;
569
+ let item =
570
+ timeline. item_by_event_id ( & event_id) . await . expect ( "The event should be in the timeline" ) ;
571
+
572
+ // The event is not decrypted yet.
573
+ assert_matches ! ( item. content( ) , TimelineItemContent :: UnableToDecrypt ( _) ) ;
574
+
575
+ // Let's subscribe to our timeline so we don't miss the transition from UTD to
576
+ // decrypted event.
577
+ let ( _, mut stream) = timeline
578
+ . subscribe_filter_map ( |item| {
579
+ item. as_event ( ) . cloned ( ) . filter ( |item| item. event_id ( ) == Some ( & event_id) )
580
+ } )
581
+ . await ;
582
+
583
+ // Now we create a notification client.
584
+ let notification_client = bob
585
+ . notification_client ( "BOB_NOTIFICATION_CLIENT" . to_owned ( ) )
586
+ . await
587
+ . expect ( "We should be able to build a notification client" ) ;
588
+
589
+ // This syncs and fetches the room key.
590
+ debug ! ( "The notification client syncs" ) ;
591
+ let notification_client = NotificationClient :: new (
592
+ notification_client,
593
+ matrix_sdk_ui:: notification_client:: NotificationProcessSetup :: SingleProcess {
594
+ sync_service : sync_service. into ( ) ,
595
+ } ,
596
+ )
597
+ . await
598
+ . expect ( "We should be able to build a notification client" ) ;
599
+
600
+ let _ = notification_client
601
+ . get_notification ( bob_room. room_id ( ) , & event_id)
602
+ . await
603
+ . expect ( "We should be able toe get a notification item for the given event" ) ;
604
+
605
+ // Alright, we should now receive an update that the event had been decrypted.
606
+ let _vector_diff = timeout ( Duration :: from_secs ( 5 ) , stream. next ( ) ) . await . unwrap ( ) . unwrap ( ) ;
607
+
608
+ // Let's fetch the event again.
609
+ let item =
610
+ timeline. item_by_event_id ( & event_id) . await . expect ( "The event should be in the timeline" ) ;
611
+
612
+ // Yup it's decrypted great.
613
+ assert_let ! (
614
+ TimelineItemContent :: Message ( message) = item. content( ) ,
615
+ "The event should have been decrypted now"
616
+ ) ;
617
+
618
+ assert_eq ! ( message. body( ) , "It's a secret to everybody!" ) ;
619
+ }
0 commit comments