test(crypto): Factor out test helper for encrypting to-device content

I'm going to need to suppress `sender_device_keys` for more tests, so pull out
a test helper to help with this.
This commit is contained in:
Richard van der Hoff
2025-10-08 22:40:38 +01:00
parent 43e94bcfb4
commit 8b6572bb23
2 changed files with 71 additions and 29 deletions
@@ -33,23 +33,23 @@ use ruma::{
to_device::DeviceIdOrAllDevices,
user_id, DeviceId, OwnedOneTimeKeyId, TransactionId, UserId,
};
use serde::Serialize;
use serde_json::{json, Value};
use tokio::sync::Mutex;
use crate::{
machine::tests,
olm::PrivateCrossSigningIdentity,
session_manager::CollectStrategy,
store::{types::Changes, CryptoStoreWrapper, MemoryStore},
types::{
events::ToDeviceEvent,
events::{room::encrypted::ToDeviceEncryptedEventContent, ToDeviceEvent},
requests::{AnyOutgoingRequest, ToDeviceRequest},
DeviceKeys,
},
utilities::json_convert,
verification::VerificationMachine,
Account, CrossSigningBootstrapRequests, DecryptionSettings, Device, DeviceData,
EncryptionSyncChanges, OlmMachine, OtherUserIdentityData, TrustRequirement,
Account, CollectStrategy, CrossSigningBootstrapRequests, DecryptionSettings, Device,
DeviceData, EncryptionSyncChanges, OlmMachine, OtherUserIdentityData, TrustRequirement,
};
/// These keys need to be periodically uploaded to the server.
@@ -227,6 +227,58 @@ pub async fn send_and_receive_encrypted_to_device_test_helper(
decrypted[0].clone()
}
/// Encrypt the given event content into the content of an
/// olm-encrypted to-device event, suppressing the `sender_device_keys` field in
/// the encrypted content.
///
/// This is much the same as calling [`Device::encrypt`] on the recipient
/// device, other than the suppression of `sender_device_keys`.
///
/// # Arguments
///
/// * `sender` - The OlmMachine to use to encrypt the event.
/// * `recipient` - The recipient of the encrypted event.
/// * `event_type` - The type of the event to encrypt.
/// * `content` - The content of the event to encrypt.
pub async fn build_encrypted_to_device_content_without_sender_data(
sender: &OlmMachine,
recipient_device: &DeviceKeys,
event_type: &str,
content: &impl Serialize,
) -> ToDeviceEncryptedEventContent {
let sender_store = &sender.inner.store;
let sender_key = recipient_device.curve25519_key().unwrap();
let sessions = sender_store
.get_sessions(&sender_key.to_base64())
.await
.expect("Could not get most recent session")
.expect("No olm session found");
let mut olm_session = sessions.lock().await.first().unwrap().clone();
let plaintext = serde_json::to_string(&json!({
"sender": sender.user_id(),
"sender_device": sender.device_id(),
"keys": { "ed25519": sender.identity_keys().ed25519.to_base64() },
"recipient": recipient_device.user_id,
"recipient_keys": { "ed25519": recipient_device.ed25519_key().unwrap().to_base64() },
"type": event_type,
"content": content,
}))
.unwrap();
let ciphertext = olm_session.encrypt_helper(&plaintext).await;
let content =
olm_session.build_encrypted_event(ciphertext, None).await.expect("could not encrypt");
sender_store
.save_changes(Changes { sessions: vec![olm_session], ..Default::default() })
.await
.expect("Could not save session");
content
}
/// Create a session for the two supplied Olm machines to communicate.
pub async fn build_session_for_pair(
alice: OlmMachine,
@@ -28,8 +28,9 @@ use serde_json::{json, value::to_raw_value, Value};
use crate::{
machine::{
test_helpers::{
build_session_for_pair, get_machine_pair, get_machine_pair_with_session,
get_prepared_machine_test_helper, send_and_receive_encrypted_to_device_test_helper,
build_encrypted_to_device_content_without_sender_data, build_session_for_pair,
get_machine_pair, get_machine_pair_with_session, get_prepared_machine_test_helper,
send_and_receive_encrypted_to_device_test_helper,
},
tests::{self, decryption_verification_state::mark_alice_identity_as_verified_test_helper},
},
@@ -45,7 +46,7 @@ use crate::{
utilities::json_convert,
verification::tests::bob_id,
CrossSigningBootstrapRequests, DecryptionSettings, DeviceData, EncryptionSettings,
EncryptionSyncChanges, LocalTrust, OlmError, OlmMachine, Session, TrustRequirement,
EncryptionSyncChanges, LocalTrust, OlmError, OlmMachine, TrustRequirement,
};
#[async_test]
@@ -635,33 +636,22 @@ async fn create_and_share_session_without_sender_data(
// the behaviour of the real implementation. See
// `GroupSessionManager::share_room_key` for inspiration on how to do that.
let olm_sessions = alice
.store()
.get_sessions(&bob.identity_keys().curve25519.to_base64())
let bob_device = alice
.get_device(bob.user_id(), bob.device_id(), None)
.await
.unwrap()
.unwrap();
let mut olm_session: Session = olm_sessions.lock().await[0].clone();
.expect("Attempt to send message to unknown device");
let room_key_content = outbound_session.as_content().await;
let plaintext = serde_json::to_string(&json!({
"sender": alice.user_id(),
"sender_device": alice.device_id(),
"keys": { "ed25519": alice.identity_keys().ed25519.to_base64() },
// We deliberately do *not* include:
// "org.matrix.msc4147.device_keys": alice_device_keys,
"recipient": bob.user_id(),
"recipient_keys": { "ed25519": bob.identity_keys().ed25519.to_base64() },
"type": room_key_content.event_type(),
"content": room_key_content,
}))
.unwrap();
let ciphertext = olm_session.encrypt_helper(&plaintext).await;
ToDeviceEvent::new(
alice.user_id().to_owned(),
olm_session.build_encrypted_event(ciphertext, None).await.unwrap(),
let content = build_encrypted_to_device_content_without_sender_data(
alice,
&bob_device.device_keys,
room_key_content.event_type(),
&room_key_content,
)
.await;
ToDeviceEvent::new(alice.user_id().to_owned(), content)
}
/// Simulate uploading keys for alice that mean bob thinks alice's device