@@ -652,25 +652,31 @@ impl Redecryptor {
652652
653653#[ cfg( test) ]
654654mod tests {
655- use std:: time:: Duration ;
655+ use std:: { collections :: BTreeSet , time:: Duration } ;
656656
657657 use assert_matches2:: assert_matches;
658658 use eyeball_im:: VectorDiff ;
659- use matrix_sdk_base:: deserialized_responses:: TimelineEventKind ;
659+ use matrix_sdk_base:: deserialized_responses:: { TimelineEventKind , VerificationState } ;
660660 use matrix_sdk_test:: {
661661 JoinedRoomBuilder , StateTestEvent , async_test, event_factory:: EventFactory ,
662662 } ;
663- use ruma:: { device_id, event_id, room_id, user_id} ;
663+ use ruma:: { RoomId , device_id, event_id, room_id, user_id} ;
664664 use serde_json:: json;
665+ use tracing:: Instrument ;
665666
666667 use crate :: {
667- assert_let_timeout, encryption:: EncryptionSettings , event_cache:: RoomEventCacheUpdate ,
668+ Client , assert_let_timeout,
669+ encryption:: EncryptionSettings ,
670+ event_cache:: { DecryptionRetryRequest , RoomEventCacheUpdate } ,
668671 test_utils:: mocks:: MatrixMockServer ,
669672 } ;
670673
671- #[ async_test]
672- async fn test_redecryptor ( ) {
673- let room_id = room_id ! ( "!test:localhost" ) ;
674+ async fn set_up_clients (
675+ room_id : & RoomId ,
676+ alice_enables_cross_signing : bool ,
677+ ) -> ( Client , Client , MatrixMockServer ) {
678+ let alice_span = tracing:: info_span!( "alice" ) ;
679+ let bob_span = tracing:: info_span!( "bob" ) ;
674680
675681 let alice_user_id = user_id ! ( "@alice:localhost" ) ;
676682 let alice_device_id = device_id ! ( "ALICEDEVICE" ) ;
@@ -680,8 +686,10 @@ mod tests {
680686 let matrix_mock_server = MatrixMockServer :: new ( ) . await ;
681687 matrix_mock_server. mock_crypto_endpoints_preset ( ) . await ;
682688
683- let encryption_settings =
684- EncryptionSettings { auto_enable_cross_signing : true , ..Default :: default ( ) } ;
689+ let encryption_settings = EncryptionSettings {
690+ auto_enable_cross_signing : alice_enables_cross_signing,
691+ ..Default :: default ( )
692+ } ;
685693
686694 // Create some clients for Alice and Bob.
687695
@@ -693,8 +701,12 @@ mod tests {
693701 . with_encryption_settings ( encryption_settings)
694702 } )
695703 . build ( )
704+ . instrument ( alice_span. clone ( ) )
696705 . await ;
697706
707+ let encryption_settings =
708+ EncryptionSettings { auto_enable_cross_signing : true , ..Default :: default ( ) } ;
709+
698710 let bob = matrix_mock_server
699711 . client_builder_for_crypto_end_to_end ( bob_user_id, bob_device_id)
700712 . on_builder ( |builder| {
@@ -703,17 +715,14 @@ mod tests {
703715 . with_encryption_settings ( encryption_settings)
704716 } )
705717 . build ( )
718+ . instrument ( bob_span. clone ( ) )
706719 . await ;
707720
708721 bob. event_cache ( ) . subscribe ( ) . expect ( "Bob should be able to enable the event cache" ) ;
709722
710723 // Ensure that Alice and Bob are aware of their devices and identities.
711724 matrix_mock_server. exchange_e2ee_identities ( & alice, & bob) . await ;
712725
713- let event_factory = EventFactory :: new ( ) . room ( room_id) ;
714- let alice_member_event = event_factory. member ( alice_user_id) . into_raw ( ) ;
715- let bob_member_event = event_factory. member ( bob_user_id) . into_raw ( ) ;
716-
717726 // Let us now create a room for them.
718727 let room_builder = JoinedRoomBuilder :: new ( room_id)
719728 . add_state_event ( StateTestEvent :: Create )
@@ -724,15 +733,33 @@ mod tests {
724733 . ok_and_run ( & alice, |builder| {
725734 builder. add_joined_room ( room_builder. clone ( ) ) ;
726735 } )
736+ . instrument ( alice_span)
727737 . await ;
728738
729739 matrix_mock_server
730740 . mock_sync ( )
731741 . ok_and_run ( & bob, |builder| {
732742 builder. add_joined_room ( room_builder) ;
733743 } )
744+ . instrument ( bob_span)
734745 . await ;
735746
747+ ( alice, bob, matrix_mock_server)
748+ }
749+
750+ #[ async_test]
751+ async fn test_redecryptor ( ) {
752+ let room_id = room_id ! ( "!test:localhost" ) ;
753+
754+ let event_factory = EventFactory :: new ( ) . room ( room_id) ;
755+ let ( alice, bob, matrix_mock_server) = set_up_clients ( room_id, true ) . await ;
756+
757+ let alice_user_id = alice. user_id ( ) . unwrap ( ) ;
758+ let bob_user_id = bob. user_id ( ) . unwrap ( ) ;
759+
760+ let alice_member_event = event_factory. member ( alice_user_id) . into_raw ( ) ;
761+ let bob_member_event = event_factory. member ( bob_user_id) . into_raw ( ) ;
762+
736763 let room = alice
737764 . get_room ( room_id)
738765 . expect ( "Alice should have access to the room now that we synced" ) ;
@@ -830,4 +857,158 @@ mod tests {
830857 assert_eq ! ( * index, 0 ) ;
831858 assert_matches ! ( & value. kind, TimelineEventKind :: Decrypted { .. } ) ;
832859 }
860+
861+ #[ async_test]
862+ async fn test_redecryptor_updating_encryption_info ( ) {
863+ let alice_span = tracing:: info_span!( "alice" ) ;
864+ let bob_span = tracing:: info_span!( "bob" ) ;
865+
866+ let room_id = room_id ! ( "!test:localhost" ) ;
867+
868+ let event_factory = EventFactory :: new ( ) . room ( room_id) ;
869+ let ( alice, bob, matrix_mock_server) = set_up_clients ( room_id, false ) . await ;
870+
871+ let alice_user_id = alice. user_id ( ) . unwrap ( ) ;
872+ let bob_user_id = bob. user_id ( ) . unwrap ( ) ;
873+
874+ let alice_member_event = event_factory. member ( alice_user_id) . into_raw ( ) ;
875+ let bob_member_event = event_factory. member ( bob_user_id) . into_raw ( ) ;
876+
877+ let room = alice
878+ . get_room ( room_id)
879+ . expect ( "Alice should have access to the room now that we synced" ) ;
880+
881+ // Alice will send a single event to the room, but this will trigger a to-device
882+ // message containing the room key to be sent as well. We capture both the event
883+ // and the to-device message.
884+
885+ let event_type = "m.room.message" ;
886+ let content = json ! ( { "body" : "It's a secret to everybody" , "msgtype" : "m.text" } ) ;
887+
888+ let event_id = event_id ! ( "$some_id" ) ;
889+ let ( event_receiver, mock) =
890+ matrix_mock_server. mock_room_send ( ) . ok_with_capture ( event_id, alice_user_id) ;
891+ let ( _guard, room_key) = matrix_mock_server. mock_capture_put_to_device ( alice_user_id) . await ;
892+
893+ {
894+ let _guard = mock. mock_once ( ) . mount_as_scoped ( ) . await ;
895+
896+ matrix_mock_server
897+ . mock_get_members ( )
898+ . ok ( vec ! [ alice_member_event. clone( ) , bob_member_event. clone( ) ] )
899+ . mock_once ( )
900+ . mount ( )
901+ . await ;
902+
903+ room. send_raw ( event_type, content)
904+ . into_future ( )
905+ . instrument ( alice_span. clone ( ) )
906+ . await
907+ . expect ( "We should be able to send an initial message" ) ;
908+ } ;
909+
910+ // Let's now see what Bob's event cache does.
911+
912+ let ( room_cache, _) = bob
913+ . event_cache ( )
914+ . for_room ( room_id)
915+ . instrument ( bob_span. clone ( ) )
916+ . await
917+ . expect ( "We should be able to get to the event cache for a specific room" ) ;
918+
919+ let ( _, mut subscriber) = room_cache. subscribe ( ) . await ;
920+
921+ // Let us retrieve the captured event and to-device message.
922+ let event = event_receiver. await . expect ( "Alice should have sent the event by now" ) ;
923+ let room_key = room_key. await ;
924+
925+ // Let us forward the event to Bob.
926+ matrix_mock_server
927+ . mock_sync ( )
928+ . ok_and_run ( & bob, |builder| {
929+ builder. add_joined_room ( JoinedRoomBuilder :: new ( room_id) . add_timeline_event ( event) ) ;
930+ } )
931+ . instrument ( bob_span. clone ( ) )
932+ . await ;
933+
934+ // Alright, Bob has received an update from the cache.
935+
936+ assert_let_timeout ! (
937+ Ok ( RoomEventCacheUpdate :: UpdateTimelineEvents { diffs, .. } ) = subscriber. recv( )
938+ ) ;
939+
940+ // There should be a single new event, and it should be a UTD as we did not
941+ // receive the room key yet.
942+ assert_eq ! ( diffs. len( ) , 1 ) ;
943+ assert_matches ! ( & diffs[ 0 ] , VectorDiff :: Append { values } ) ;
944+ assert_matches ! ( & values[ 0 ] . kind, TimelineEventKind :: UnableToDecrypt { .. } ) ;
945+
946+ // Now we send the room key to Bob.
947+ matrix_mock_server
948+ . mock_sync ( )
949+ . ok_and_run ( & bob, |builder| {
950+ builder. add_to_device_event (
951+ room_key
952+ . deserialize_as ( )
953+ . expect ( "We should be able to deserialize the room key" ) ,
954+ ) ;
955+ } )
956+ . instrument ( bob_span. clone ( ) )
957+ . await ;
958+
959+ // Bob should receive a new update from the cache.
960+ assert_let_timeout ! (
961+ Duration :: from_secs( 1 ) ,
962+ Ok ( RoomEventCacheUpdate :: UpdateTimelineEvents { diffs, .. } ) = subscriber. recv( )
963+ ) ;
964+
965+ // It should replace the UTD with a decrypted event.
966+ assert_eq ! ( diffs. len( ) , 1 ) ;
967+ assert_matches ! ( & diffs[ 0 ] , VectorDiff :: Set { index: 0 , value } ) ;
968+ assert_matches ! ( & value. kind, TimelineEventKind :: Decrypted { .. } ) ;
969+
970+ let encryption_info = value. encryption_info ( ) . unwrap ( ) ;
971+ assert_matches ! ( & encryption_info. verification_state, VerificationState :: Unverified ( _) ) ;
972+ let session_id = encryption_info. session_id ( ) . unwrap ( ) . to_owned ( ) ;
973+
974+ // Alice now creates the identity.
975+ alice
976+ . encryption ( )
977+ . bootstrap_cross_signing ( None )
978+ . await
979+ . expect ( "Alice should be able to create the cross-signing keys" ) ;
980+
981+ bob. update_tracked_users_for_testing ( [ alice_user_id] ) . instrument ( bob_span. clone ( ) ) . await ;
982+ matrix_mock_server
983+ . mock_sync ( )
984+ . ok_and_run ( & bob, |builder| {
985+ builder. add_change_device ( alice_user_id) ;
986+ } )
987+ . instrument ( bob_span. clone ( ) )
988+ . await ;
989+
990+ bob. event_cache ( ) . request_decryption ( DecryptionRetryRequest {
991+ room_id : room_id. into ( ) ,
992+ utd_session_ids : BTreeSet :: new ( ) ,
993+ refresh_info_session_ids : BTreeSet :: from ( [ session_id] ) ,
994+ } ) ;
995+
996+ // Bob should again receive a new update from the cache, this time updating the
997+ // encryption info.
998+ assert_let_timeout ! (
999+ Duration :: from_secs( 1 ) ,
1000+ Ok ( RoomEventCacheUpdate :: UpdateTimelineEvents { diffs, .. } ) = subscriber. recv( )
1001+ ) ;
1002+
1003+ assert_eq ! ( diffs. len( ) , 1 ) ;
1004+ assert_matches ! ( & diffs[ 0 ] , VectorDiff :: Set { index: 0 , value } ) ;
1005+ assert_matches ! ( & value. kind, TimelineEventKind :: Decrypted { .. } ) ;
1006+ let encryption_info = value. encryption_info ( ) . unwrap ( ) ;
1007+
1008+ assert_matches ! (
1009+ & encryption_info. verification_state,
1010+ VerificationState :: Unverified ( _) ,
1011+ "The event should now know about the identity but still be unverified"
1012+ ) ;
1013+ }
8331014}
0 commit comments