Skip to content

Commit f14994b

Browse files
committed
test(sdk): Test if we accept historic room key bundles arriving out of order
1 parent d42d0f3 commit f14994b

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

crates/matrix-sdk/tests/integration/encryption.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod backups;
22
mod cross_signing;
33
mod recovery;
44
mod secret_storage;
5+
mod shared_history;
56
mod to_device;
67
mod verification;
78

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
use futures_util::{FutureExt, StreamExt};
2+
use matrix_sdk::{
3+
assert_decrypted_message_eq, assert_next_matches_with_timeout,
4+
deserialized_responses::{TimelineEvent, UnableToDecryptInfo, UnableToDecryptReason},
5+
encryption::EncryptionSettings,
6+
test_utils::mocks::MatrixMockServer,
7+
};
8+
use matrix_sdk_test::{
9+
async_test, event_factory::EventFactory, InvitedRoomBuilder, JoinedRoomBuilder, StateTestEvent,
10+
};
11+
use ruma::{
12+
device_id, event_id, events::room::message::RoomMessageEventContent, mxc_uri, room_id, user_id,
13+
};
14+
15+
#[async_test]
16+
async fn test_shared_history_out_of_order() {
17+
let room_id = room_id!("!test:localhost");
18+
let mxid = mxc_uri!("mxc://localhost/12345");
19+
20+
let alice_user_id = user_id!("@alice:localhost");
21+
let alice_device_id = device_id!("ALICEDEVICE");
22+
let bob_user_id = user_id!("@bob:localhost");
23+
let bob_device_id = device_id!("BOBDEVICE");
24+
25+
let matrix_mock_server = MatrixMockServer::new().await;
26+
matrix_mock_server.mock_crypto_endpoints_preset().await;
27+
matrix_mock_server.mock_invite_user_by_id().ok().mock_once().mount().await;
28+
29+
let encryption_settings =
30+
EncryptionSettings { auto_enable_cross_signing: true, ..Default::default() };
31+
32+
let alice = matrix_mock_server
33+
.client_builder_for_crypto_end_to_end(alice_user_id, alice_device_id)
34+
.enable_share_history_on_invite()
35+
.with_encryption_settings(encryption_settings)
36+
.build()
37+
.await;
38+
39+
let bob = matrix_mock_server
40+
.client_builder_for_crypto_end_to_end(bob_user_id, bob_device_id)
41+
.enable_share_history_on_invite()
42+
.with_encryption_settings(encryption_settings)
43+
.build()
44+
.await;
45+
46+
matrix_mock_server.exchange_e2ee_identities(&alice, &bob).await;
47+
48+
let event_factory = EventFactory::new().room(room_id);
49+
let alice_member_event = event_factory.member(alice_user_id).into_raw_timeline();
50+
51+
matrix_mock_server
52+
.mock_sync()
53+
.ok_and_run(&alice, |builder| {
54+
builder.add_joined_room(
55+
JoinedRoomBuilder::new(room_id)
56+
.add_state_event(StateTestEvent::Create)
57+
.add_state_event(StateTestEvent::Encryption),
58+
);
59+
})
60+
.await;
61+
62+
let room =
63+
alice.get_room(room_id).expect("Alice should have access to the room now that we synced");
64+
65+
let event_id = event_id!("$some_id");
66+
let (event_receiver, mock) =
67+
matrix_mock_server.mock_room_send().ok_with_capture(event_id, alice_user_id);
68+
69+
mock.mock_once().mount().await;
70+
71+
matrix_mock_server
72+
.mock_get_members()
73+
.ok(vec![alice_member_event.clone().cast()])
74+
.mock_once()
75+
.mount()
76+
.await;
77+
78+
let event_id = room
79+
.send(RoomMessageEventContent::text_plain("It's a secret to everybody"))
80+
.await
81+
.expect("We should be able to send an initial message")
82+
.event_id;
83+
84+
matrix_mock_server.mock_authenticated_media_config().ok_default().mock_once().mount().await;
85+
86+
let (receiver, upload_mock) = matrix_mock_server.mock_upload().ok_with_capture(mxid);
87+
upload_mock.mock_once().mount().await;
88+
89+
let (_guard, bundle_info) = matrix_mock_server.mock_capture_put_to_device(alice_user_id).await;
90+
91+
room.invite_user_by_id(bob_user_id).await.expect("We should be able to invite Bob");
92+
let bundle = receiver.await.expect("We should have received a bundle now.");
93+
94+
let mut bundle_stream = bob
95+
.encryption()
96+
.historic_room_key_stream()
97+
.await
98+
.expect("We should be able to get the bundle stream");
99+
100+
let bob_member_event = event_factory.member(alice_user_id).invited(bob_user_id);
101+
102+
matrix_mock_server
103+
.mock_sync()
104+
.ok_and_run(&bob, |builder| {
105+
builder.add_invited_room(
106+
InvitedRoomBuilder::new(room_id)
107+
.add_state_event(alice_member_event.cast())
108+
.add_state_event(bob_member_event.into_raw_timeline().cast()),
109+
);
110+
})
111+
.await;
112+
113+
let bob_room = bob.get_room(room_id).expect("Bob should have access to the invited room");
114+
115+
matrix_mock_server.mock_room_join(room_id).ok().mock_once().mount().await;
116+
bob_room.join().await.expect("Bob should be able to join the room");
117+
118+
let details = bob_room
119+
.invite_acceptance_details()
120+
.expect("We should have stored invite acceptance details");
121+
122+
assert_eq!(
123+
details.inviter,
124+
alice.user_id().unwrap(),
125+
"We should have recorded that Alice has invited us"
126+
);
127+
128+
let bundle_info = bundle_info.await;
129+
matrix_mock_server.mock_media_download().ok_bytes(bundle).mock_once().mount().await;
130+
131+
let mut room_key_stream = bob
132+
.encryption()
133+
.room_keys_received_stream()
134+
.await
135+
.expect("We should be able to listen to received room keys");
136+
137+
matrix_mock_server
138+
.mock_sync()
139+
.ok_and_run(&bob, |builder| {
140+
builder.add_to_device_event(
141+
bundle_info
142+
.deserialize_as()
143+
.expect("We should be able to deserialize the bundle info"),
144+
);
145+
})
146+
.await;
147+
148+
let bundle_notification = bundle_stream
149+
.next()
150+
.now_or_never()
151+
.flatten()
152+
.expect("We should have been notiifed about the received bundle");
153+
154+
assert_eq!(bundle_notification.sender, alice_user_id);
155+
assert_eq!(bundle_notification.room_id, room_id);
156+
157+
assert_next_matches_with_timeout!(room_key_stream, 1000, Ok(room_key_infos) => assert_eq!(room_key_infos.len(), 1));
158+
159+
let event = event_receiver.await.expect("We should have received Alice's event");
160+
161+
matrix_mock_server
162+
.mock_room_event()
163+
.room(room_id)
164+
.match_event_id()
165+
.ok(TimelineEvent::from_utd(
166+
event,
167+
UnableToDecryptInfo { session_id: None, reason: UnableToDecryptReason::Unknown },
168+
))
169+
.mock_once()
170+
.mount()
171+
.await;
172+
173+
let event = bob_room
174+
.event(&event_id, None)
175+
.await
176+
.expect("Bob should be able to fetch the event Alice has sent");
177+
178+
assert_decrypted_message_eq!(
179+
event,
180+
"It's a secret to everybody",
181+
"The decrypted event should match the message Alice has sent"
182+
);
183+
}

0 commit comments

Comments
 (0)