Skip to content

Commit d9249da

Browse files
committed
test(redecryptor): More tests for the redecryptor
1 parent 8f9d700 commit d9249da

File tree

1 file changed

+194
-13
lines changed

1 file changed

+194
-13
lines changed

crates/matrix-sdk/src/event_cache/redecryptor.rs

Lines changed: 194 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -652,25 +652,31 @@ impl Redecryptor {
652652

653653
#[cfg(test)]
654654
mod 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

Comments
 (0)