Skip to content

Commit a5e6728

Browse files
committed
test(redecryptor): More tests for the redecryptor
1 parent c4c9cea commit a5e6728

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
@@ -649,25 +649,31 @@ impl Redecryptor {
649649

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

Comments
 (0)