@@ -649,25 +649,31 @@ impl Redecryptor {
649649
650650#[ cfg( test) ]
651651mod tests {
652- use std:: time:: Duration ;
652+ use std:: { collections :: BTreeSet , time:: Duration } ;
653653
654654 use assert_matches2:: assert_matches;
655655 use eyeball_im:: VectorDiff ;
656- use matrix_sdk_base:: deserialized_responses:: TimelineEventKind ;
656+ use matrix_sdk_base:: deserialized_responses:: { TimelineEventKind , VerificationState } ;
657657 use matrix_sdk_test:: {
658658 JoinedRoomBuilder , StateTestEvent , async_test, event_factory:: EventFactory ,
659659 } ;
660- use ruma:: { device_id, event_id, room_id, user_id} ;
660+ use ruma:: { RoomId , device_id, event_id, room_id, user_id} ;
661661 use serde_json:: json;
662+ use tracing:: Instrument ;
662663
663664 use crate :: {
664- assert_let_timeout, encryption:: EncryptionSettings , event_cache:: RoomEventCacheUpdate ,
665+ Client , assert_let_timeout,
666+ encryption:: EncryptionSettings ,
667+ event_cache:: { DecryptionRetryRequest , RoomEventCacheUpdate } ,
665668 test_utils:: mocks:: MatrixMockServer ,
666669 } ;
667670
668- #[ async_test]
669- async fn test_redecryptor ( ) {
670- let room_id = room_id ! ( "!test:localhost" ) ;
671+ async fn set_up_clients (
672+ room_id : & RoomId ,
673+ alice_enables_cross_signing : bool ,
674+ ) -> ( Client , Client , MatrixMockServer ) {
675+ let alice_span = tracing:: info_span!( "alice" ) ;
676+ let bob_span = tracing:: info_span!( "bob" ) ;
671677
672678 let alice_user_id = user_id ! ( "@alice:localhost" ) ;
673679 let alice_device_id = device_id ! ( "ALICEDEVICE" ) ;
@@ -677,8 +683,10 @@ mod tests {
677683 let matrix_mock_server = MatrixMockServer :: new ( ) . await ;
678684 matrix_mock_server. mock_crypto_endpoints_preset ( ) . await ;
679685
680- let encryption_settings =
681- EncryptionSettings { auto_enable_cross_signing : true , ..Default :: default ( ) } ;
686+ let encryption_settings = EncryptionSettings {
687+ auto_enable_cross_signing : alice_enables_cross_signing,
688+ ..Default :: default ( )
689+ } ;
682690
683691 // Create some clients for Alice and Bob.
684692
@@ -690,8 +698,12 @@ mod tests {
690698 . with_encryption_settings ( encryption_settings)
691699 } )
692700 . build ( )
701+ . instrument ( alice_span. clone ( ) )
693702 . await ;
694703
704+ let encryption_settings =
705+ EncryptionSettings { auto_enable_cross_signing : true , ..Default :: default ( ) } ;
706+
695707 let bob = matrix_mock_server
696708 . client_builder_for_crypto_end_to_end ( bob_user_id, bob_device_id)
697709 . on_builder ( |builder| {
@@ -700,17 +712,14 @@ mod tests {
700712 . with_encryption_settings ( encryption_settings)
701713 } )
702714 . build ( )
715+ . instrument ( bob_span. clone ( ) )
703716 . await ;
704717
705718 bob. event_cache ( ) . subscribe ( ) . expect ( "Bob should be able to enable the event cache" ) ;
706719
707720 // Ensure that Alice and Bob are aware of their devices and identities.
708721 matrix_mock_server. exchange_e2ee_identities ( & alice, & bob) . await ;
709722
710- let event_factory = EventFactory :: new ( ) . room ( room_id) ;
711- let alice_member_event = event_factory. member ( alice_user_id) . into_raw ( ) ;
712- let bob_member_event = event_factory. member ( bob_user_id) . into_raw ( ) ;
713-
714723 // Let us now create a room for them.
715724 let room_builder = JoinedRoomBuilder :: new ( room_id)
716725 . add_state_event ( StateTestEvent :: Create )
@@ -721,15 +730,33 @@ mod tests {
721730 . ok_and_run ( & alice, |builder| {
722731 builder. add_joined_room ( room_builder. clone ( ) ) ;
723732 } )
733+ . instrument ( alice_span)
724734 . await ;
725735
726736 matrix_mock_server
727737 . mock_sync ( )
728738 . ok_and_run ( & bob, |builder| {
729739 builder. add_joined_room ( room_builder) ;
730740 } )
741+ . instrument ( bob_span)
731742 . await ;
732743
744+ ( alice, bob, matrix_mock_server)
745+ }
746+
747+ #[ async_test]
748+ async fn test_redecryptor ( ) {
749+ let room_id = room_id ! ( "!test:localhost" ) ;
750+
751+ let event_factory = EventFactory :: new ( ) . room ( room_id) ;
752+ let ( alice, bob, matrix_mock_server) = set_up_clients ( room_id, true ) . await ;
753+
754+ let alice_user_id = alice. user_id ( ) . unwrap ( ) ;
755+ let bob_user_id = bob. user_id ( ) . unwrap ( ) ;
756+
757+ let alice_member_event = event_factory. member ( alice_user_id) . into_raw ( ) ;
758+ let bob_member_event = event_factory. member ( bob_user_id) . into_raw ( ) ;
759+
733760 let room = alice
734761 . get_room ( room_id)
735762 . expect ( "Alice should have access to the room now that we synced" ) ;
@@ -827,4 +854,158 @@ mod tests {
827854 assert_eq ! ( * index, 0 ) ;
828855 assert_matches ! ( & value. kind, TimelineEventKind :: Decrypted { .. } ) ;
829856 }
857+
858+ #[ async_test]
859+ async fn test_redecryptor_updating_encryption_info ( ) {
860+ let alice_span = tracing:: info_span!( "alice" ) ;
861+ let bob_span = tracing:: info_span!( "bob" ) ;
862+
863+ let room_id = room_id ! ( "!test:localhost" ) ;
864+
865+ let event_factory = EventFactory :: new ( ) . room ( room_id) ;
866+ let ( alice, bob, matrix_mock_server) = set_up_clients ( room_id, false ) . await ;
867+
868+ let alice_user_id = alice. user_id ( ) . unwrap ( ) ;
869+ let bob_user_id = bob. user_id ( ) . unwrap ( ) ;
870+
871+ let alice_member_event = event_factory. member ( alice_user_id) . into_raw ( ) ;
872+ let bob_member_event = event_factory. member ( bob_user_id) . into_raw ( ) ;
873+
874+ let room = alice
875+ . get_room ( room_id)
876+ . expect ( "Alice should have access to the room now that we synced" ) ;
877+
878+ // Alice will send a single event to the room, but this will trigger a to-device
879+ // message containing the room key to be sent as well. We capture both the event
880+ // and the to-device message.
881+
882+ let event_type = "m.room.message" ;
883+ let content = json ! ( { "body" : "It's a secret to everybody" , "msgtype" : "m.text" } ) ;
884+
885+ let event_id = event_id ! ( "$some_id" ) ;
886+ let ( event_receiver, mock) =
887+ matrix_mock_server. mock_room_send ( ) . ok_with_capture ( event_id, alice_user_id) ;
888+ let ( _guard, room_key) = matrix_mock_server. mock_capture_put_to_device ( alice_user_id) . await ;
889+
890+ {
891+ let _guard = mock. mock_once ( ) . mount_as_scoped ( ) . await ;
892+
893+ matrix_mock_server
894+ . mock_get_members ( )
895+ . ok ( vec ! [ alice_member_event. clone( ) , bob_member_event. clone( ) ] )
896+ . mock_once ( )
897+ . mount ( )
898+ . await ;
899+
900+ room. send_raw ( event_type, content)
901+ . into_future ( )
902+ . instrument ( alice_span. clone ( ) )
903+ . await
904+ . expect ( "We should be able to send an initial message" ) ;
905+ } ;
906+
907+ // Let's now see what Bob's event cache does.
908+
909+ let ( room_cache, _) = bob
910+ . event_cache ( )
911+ . for_room ( room_id)
912+ . instrument ( bob_span. clone ( ) )
913+ . await
914+ . expect ( "We should be able to get to the event cache for a specific room" ) ;
915+
916+ let ( _, mut subscriber) = room_cache. subscribe ( ) . await ;
917+
918+ // Let us retrieve the captured event and to-device message.
919+ let event = event_receiver. await . expect ( "Alice should have sent the event by now" ) ;
920+ let room_key = room_key. await ;
921+
922+ // Let us forward the event to Bob.
923+ matrix_mock_server
924+ . mock_sync ( )
925+ . ok_and_run ( & bob, |builder| {
926+ builder. add_joined_room ( JoinedRoomBuilder :: new ( room_id) . add_timeline_event ( event) ) ;
927+ } )
928+ . instrument ( bob_span. clone ( ) )
929+ . await ;
930+
931+ // Alright, Bob has received an update from the cache.
932+
933+ assert_let_timeout ! (
934+ Ok ( RoomEventCacheUpdate :: UpdateTimelineEvents { diffs, .. } ) = subscriber. recv( )
935+ ) ;
936+
937+ // There should be a single new event, and it should be a UTD as we did not
938+ // receive the room key yet.
939+ assert_eq ! ( diffs. len( ) , 1 ) ;
940+ assert_matches ! ( & diffs[ 0 ] , VectorDiff :: Append { values } ) ;
941+ assert_matches ! ( & values[ 0 ] . kind, TimelineEventKind :: UnableToDecrypt { .. } ) ;
942+
943+ // Now we send the room key to Bob.
944+ matrix_mock_server
945+ . mock_sync ( )
946+ . ok_and_run ( & bob, |builder| {
947+ builder. add_to_device_event (
948+ room_key
949+ . deserialize_as ( )
950+ . expect ( "We should be able to deserialize the room key" ) ,
951+ ) ;
952+ } )
953+ . instrument ( bob_span. clone ( ) )
954+ . await ;
955+
956+ // Bob should receive a new update from the cache.
957+ assert_let_timeout ! (
958+ Duration :: from_secs( 1 ) ,
959+ Ok ( RoomEventCacheUpdate :: UpdateTimelineEvents { diffs, .. } ) = subscriber. recv( )
960+ ) ;
961+
962+ // It should replace the UTD with a decrypted event.
963+ assert_eq ! ( diffs. len( ) , 1 ) ;
964+ assert_matches ! ( & diffs[ 0 ] , VectorDiff :: Set { index: 0 , value } ) ;
965+ assert_matches ! ( & value. kind, TimelineEventKind :: Decrypted { .. } ) ;
966+
967+ let encryption_info = value. encryption_info ( ) . unwrap ( ) ;
968+ assert_matches ! ( & encryption_info. verification_state, VerificationState :: Unverified ( _) ) ;
969+ let session_id = encryption_info. session_id ( ) . unwrap ( ) . to_owned ( ) ;
970+
971+ // Alice now creates the identity.
972+ alice
973+ . encryption ( )
974+ . bootstrap_cross_signing ( None )
975+ . await
976+ . expect ( "Alice should be able to create the cross-signing keys" ) ;
977+
978+ bob. update_tracked_users_for_testing ( [ alice_user_id] ) . instrument ( bob_span. clone ( ) ) . await ;
979+ matrix_mock_server
980+ . mock_sync ( )
981+ . ok_and_run ( & bob, |builder| {
982+ builder. add_change_device ( alice_user_id) ;
983+ } )
984+ . instrument ( bob_span. clone ( ) )
985+ . await ;
986+
987+ bob. event_cache ( ) . request_decryption ( DecryptionRetryRequest {
988+ room_id : room_id. into ( ) ,
989+ utd_session_ids : BTreeSet :: new ( ) ,
990+ refresh_info_session_ids : BTreeSet :: from ( [ session_id] ) ,
991+ } ) ;
992+
993+ // Bob should again receive a new update from the cache, this time updating the
994+ // encryption info.
995+ assert_let_timeout ! (
996+ Duration :: from_secs( 1 ) ,
997+ Ok ( RoomEventCacheUpdate :: UpdateTimelineEvents { diffs, .. } ) = subscriber. recv( )
998+ ) ;
999+
1000+ assert_eq ! ( diffs. len( ) , 1 ) ;
1001+ assert_matches ! ( & diffs[ 0 ] , VectorDiff :: Set { index: 0 , value } ) ;
1002+ assert_matches ! ( & value. kind, TimelineEventKind :: Decrypted { .. } ) ;
1003+ let encryption_info = value. encryption_info ( ) . unwrap ( ) ;
1004+
1005+ assert_matches ! (
1006+ & encryption_info. verification_state,
1007+ VerificationState :: Unverified ( _) ,
1008+ "The event should now know about the identity but still be unverified"
1009+ ) ;
1010+ }
8301011}
0 commit comments