mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-24 00:25:34 -04:00
test: Add more olm decryption encryption_info tests
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use as_variant::as_variant;
|
||||
use matrix_sdk_common::deserialized_responses::ProcessedToDeviceEvent;
|
||||
use matrix_sdk_test::{ruma_response_from_json, test_json};
|
||||
use ruma::{
|
||||
api::client::keys::{
|
||||
@@ -29,14 +30,20 @@ use ruma::{
|
||||
encryption::OneTimeKey,
|
||||
events::dummy::ToDeviceDummyEventContent,
|
||||
serde::Raw,
|
||||
to_device::DeviceIdOrAllDevices,
|
||||
user_id, DeviceId, OwnedOneTimeKeyId, TransactionId, UserId,
|
||||
};
|
||||
use serde_json::json;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::{
|
||||
machine::tests,
|
||||
store::{Changes, MemoryStore},
|
||||
types::{events::ToDeviceEvent, requests::AnyOutgoingRequest},
|
||||
CrossSigningBootstrapRequests, DeviceData, OlmMachine,
|
||||
types::{
|
||||
events::ToDeviceEvent,
|
||||
requests::{AnyOutgoingRequest, ToDeviceRequest},
|
||||
},
|
||||
utilities::json_convert,
|
||||
CrossSigningBootstrapRequests, DeviceData, EncryptionSyncChanges, OlmMachine,
|
||||
};
|
||||
|
||||
/// These keys need to be periodically uploaded to the server.
|
||||
@@ -172,7 +179,7 @@ pub async fn get_machine_pair_with_session(
|
||||
}
|
||||
|
||||
/// Create a session for the two supplied Olm machines to communicate.
|
||||
async fn build_session_for_pair(
|
||||
pub async fn build_session_for_pair(
|
||||
alice: OlmMachine,
|
||||
bob: OlmMachine,
|
||||
mut one_time_keys: BTreeMap<
|
||||
@@ -276,3 +283,51 @@ pub fn bootstrap_requests_to_keys_query_response(
|
||||
|
||||
ruma_response_from_json(&kq_response)
|
||||
}
|
||||
|
||||
/// Encrypt and send a given to device event from the sender to the recipient.
|
||||
///
|
||||
/// Simulates the reception by having the recipient machine receiving a sync
|
||||
/// with the encrypted message.
|
||||
/// Returns the event as received by the recipient.
|
||||
pub async fn encrypt_to_device_helper(
|
||||
sender: &OlmMachine,
|
||||
recipient: &OlmMachine,
|
||||
event_type: &str,
|
||||
event_content: Value,
|
||||
) -> ProcessedToDeviceEvent {
|
||||
let device =
|
||||
sender.get_device(recipient.user_id(), recipient.device_id(), None).await.unwrap().unwrap();
|
||||
let raw_encrypted = device
|
||||
.encrypt_event_raw(event_type, &event_content)
|
||||
.await
|
||||
.expect("Should have encrypted the content");
|
||||
|
||||
let request = ToDeviceRequest::new(
|
||||
recipient.user_id(),
|
||||
DeviceIdOrAllDevices::DeviceId(recipient.device_id().to_owned()),
|
||||
"m.room.encrypted",
|
||||
raw_encrypted.cast(),
|
||||
);
|
||||
|
||||
let encrypted_event = ToDeviceEvent::new(
|
||||
sender.user_id().to_owned(),
|
||||
tests::to_device_requests_to_content(vec![request.clone().into()]),
|
||||
);
|
||||
|
||||
let encrypted_event = json_convert(&encrypted_event).unwrap();
|
||||
|
||||
let sync_changes = EncryptionSyncChanges {
|
||||
to_device_events: vec![encrypted_event],
|
||||
changed_devices: &Default::default(),
|
||||
one_time_keys_counts: &Default::default(),
|
||||
unused_fallback_keys: None,
|
||||
next_batch_token: None,
|
||||
};
|
||||
|
||||
let (to_devices, _) = recipient
|
||||
.receive_sync_changes(sync_changes)
|
||||
.await
|
||||
.expect("Receive Sync changes should not fail");
|
||||
|
||||
to_devices.first().unwrap().clone()
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ use crate::{
|
||||
mod decryption_verification_state;
|
||||
mod interactive_verification;
|
||||
mod megolm_sender_data;
|
||||
mod olm_decryption_encryption_info;
|
||||
mod olm_encryption;
|
||||
mod room_settings;
|
||||
mod send_encrypted_to_device;
|
||||
@@ -837,6 +838,7 @@ async fn test_decrypt_unencrypted_event() {
|
||||
);
|
||||
}
|
||||
|
||||
/// This only bootstrap cross-signing but it will not sign the current device !!
|
||||
pub async fn setup_cross_signing_for_machine_test_helper(alice: &OlmMachine, bob: &OlmMachine) {
|
||||
let CrossSigningBootstrapRequests { upload_signing_keys_req: alice_upload_signing, .. } =
|
||||
alice.bootstrap_cross_signing(false).await.expect("Expect Alice x-signing key request");
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use assert_matches2::{assert_let, assert_matches};
|
||||
use matrix_sdk_common::deserialized_responses::{
|
||||
ProcessedToDeviceEvent, VerificationLevel, VerificationState,
|
||||
};
|
||||
use matrix_sdk_test::async_test;
|
||||
use ruma::TransactionId;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
machine::{
|
||||
test_helpers::{
|
||||
bootstrap_requests_to_keys_query_response, build_session_for_pair,
|
||||
encrypt_to_device_helper, get_machine_pair_with_session,
|
||||
get_prepared_machine_test_helper,
|
||||
},
|
||||
tests,
|
||||
tests::{
|
||||
alice_device_id, alice_id,
|
||||
decryption_verification_state::mark_alice_identity_as_verified_test_helper,
|
||||
},
|
||||
},
|
||||
verification::tests::bob_id,
|
||||
DeviceData, OlmMachine,
|
||||
};
|
||||
|
||||
#[async_test]
|
||||
async fn test_to_device_verification_state_signed_device() {
|
||||
let (alice, bob) = get_machine_pair_with_session(alice_id(), tests::user_id(), false).await;
|
||||
|
||||
let bootstrap_requests = alice.bootstrap_cross_signing(false).await.unwrap();
|
||||
let kq_response = bootstrap_requests_to_keys_query_response(bootstrap_requests);
|
||||
bob.receive_keys_query_response(&TransactionId::new(), &kq_response).await.unwrap();
|
||||
|
||||
let custom_event_type = "m.hello";
|
||||
|
||||
let custom_content = json!({
|
||||
"what": "foo",
|
||||
});
|
||||
|
||||
let received = encrypt_to_device_helper(&alice, &bob, custom_event_type, custom_content).await;
|
||||
|
||||
assert_let!(ProcessedToDeviceEvent::Decrypted { encryption_info, .. } = received);
|
||||
|
||||
assert_matches!(
|
||||
encryption_info.verification_state,
|
||||
VerificationState::Unverified(VerificationLevel::UnverifiedIdentity)
|
||||
);
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn test_to_device_verification_state_verified() {
|
||||
let (alice, bob) = get_machine_pair_with_session(alice_id(), tests::user_id(), false).await;
|
||||
|
||||
let bootstrap_requests = alice.bootstrap_cross_signing(false).await.unwrap();
|
||||
let kq_response = bootstrap_requests_to_keys_query_response(bootstrap_requests);
|
||||
bob.receive_keys_query_response(&TransactionId::new(), &kq_response).await.unwrap();
|
||||
|
||||
let bootstrap_requests = bob.bootstrap_cross_signing(false).await.unwrap();
|
||||
let kq_response = bootstrap_requests_to_keys_query_response(bootstrap_requests);
|
||||
alice.receive_keys_query_response(&TransactionId::new(), &kq_response).await.unwrap();
|
||||
|
||||
mark_alice_identity_as_verified_test_helper(&alice, &bob).await;
|
||||
|
||||
let custom_event_type = "m.hello";
|
||||
|
||||
let custom_content = json!({
|
||||
"what": "foo",
|
||||
});
|
||||
|
||||
let received = encrypt_to_device_helper(&alice, &bob, custom_event_type, custom_content).await;
|
||||
|
||||
assert_let!(ProcessedToDeviceEvent::Decrypted { encryption_info, .. } = received);
|
||||
|
||||
assert_matches!(encryption_info.verification_state, VerificationState::Verified);
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn test_to_device_verification_state_verification_violation() {
|
||||
let (alice, bob) = get_machine_pair_with_session(alice_id(), tests::user_id(), false).await;
|
||||
|
||||
let bootstrap_requests = alice.bootstrap_cross_signing(false).await.unwrap();
|
||||
let kq_response = bootstrap_requests_to_keys_query_response(bootstrap_requests);
|
||||
bob.receive_keys_query_response(&TransactionId::new(), &kq_response).await.unwrap();
|
||||
|
||||
// Simulate Alice's cross-signing key changing after having been verified by
|
||||
// setting the `previously_verified` flag
|
||||
let alice_identity =
|
||||
bob.store().get_identity(alice.user_id()).await.unwrap().unwrap().other().unwrap();
|
||||
alice_identity.mark_as_previously_verified().await.unwrap();
|
||||
|
||||
let custom_event_type = "m.hello";
|
||||
|
||||
let custom_content = json!({
|
||||
"what": "foo",
|
||||
});
|
||||
|
||||
let received = encrypt_to_device_helper(&alice, &bob, custom_event_type, custom_content).await;
|
||||
|
||||
assert_let!(ProcessedToDeviceEvent::Decrypted { encryption_info, .. } = received);
|
||||
|
||||
assert_matches!(
|
||||
encryption_info.verification_state,
|
||||
VerificationState::Unverified(VerificationLevel::VerificationViolation)
|
||||
);
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn test_to_device_verification_level_none() {
|
||||
// Arrange
|
||||
// Set up prepared machine where it is the first time ever bob will receive a
|
||||
// message from this alice device. So bob is not yet aware of alice device.
|
||||
let (bob, otk) = get_prepared_machine_test_helper(bob_id(), false).await;
|
||||
let alice_device = alice_device_id();
|
||||
let alice = OlmMachine::new(alice_id(), alice_device).await;
|
||||
// Bob doesn't know yet alice keys. Alice contact in an async way
|
||||
let bob_device = DeviceData::from_machine_test_helper(&bob).await.unwrap();
|
||||
alice.store().save_device_data(&[bob_device]).await.unwrap();
|
||||
// Let alice claim one otk and create the outbound session
|
||||
let (alice, bob) = build_session_for_pair(alice, bob, otk).await;
|
||||
|
||||
// Act
|
||||
|
||||
let custom_event_type = "m.hello";
|
||||
|
||||
let custom_content = json!({
|
||||
"what": "foo",
|
||||
});
|
||||
|
||||
let received = encrypt_to_device_helper(&alice, &bob, custom_event_type, custom_content).await;
|
||||
|
||||
// The decryption will fail (MissingSigningKey) for custom to-device events if
|
||||
// the recipient does not know the sender.
|
||||
// The VerificationLevel::None can only happen for room_key not custom events.
|
||||
assert_matches!(received, ProcessedToDeviceEvent::UnableToDecrypt { .. });
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use assert_matches2::assert_matches;
|
||||
use assert_matches2::{assert_let, assert_matches};
|
||||
use matrix_sdk_common::deserialized_responses::{
|
||||
AlgorithmInfo, ProcessedToDeviceEvent, VerificationLevel, VerificationState,
|
||||
};
|
||||
@@ -88,9 +88,9 @@ async fn test_send_encrypted_to_device() {
|
||||
|
||||
assert_eq!(1, decrypted.len());
|
||||
let processed_event = &decrypted[0];
|
||||
let ProcessedToDeviceEvent::Decrypted { decrypted_event, .. } = processed_event else {
|
||||
panic!("Unexpected variant");
|
||||
};
|
||||
|
||||
assert_let!(ProcessedToDeviceEvent::Decrypted { decrypted_event, .. } = processed_event);
|
||||
|
||||
let decrypted_event = decrypted_event.deserialize().unwrap();
|
||||
|
||||
assert_eq!(decrypted_event.event_type().to_string(), custom_event_type.to_owned());
|
||||
@@ -210,17 +210,16 @@ async fn test_processed_to_device_variants() {
|
||||
assert_eq!(4, processed.len());
|
||||
|
||||
let processed_event = &processed[0];
|
||||
let ProcessedToDeviceEvent::Decrypted { encryption_info, .. } = processed_event else {
|
||||
panic!("Unexpected variant");
|
||||
};
|
||||
|
||||
assert_let!(ProcessedToDeviceEvent::Decrypted { encryption_info, .. } = processed_event);
|
||||
|
||||
assert_eq!(alice.user_id().to_owned(), encryption_info.sender);
|
||||
assert_eq!(Some(alice.device_id().to_owned()), encryption_info.sender_device);
|
||||
|
||||
let AlgorithmInfo::OlmV1Curve25519AesSha2 { curve25519_key } = &encryption_info.algorithm_info
|
||||
else {
|
||||
panic!("Unexpected algorithm info");
|
||||
};
|
||||
assert_let!(
|
||||
AlgorithmInfo::OlmV1Curve25519AesSha2 { curve25519_key } = &encryption_info.algorithm_info
|
||||
);
|
||||
|
||||
assert_eq!(curve25519_key.to_owned(), alice_curve.to_base64());
|
||||
|
||||
assert_eq!(encryption_info.session_id, None);
|
||||
@@ -230,19 +229,13 @@ async fn test_processed_to_device_variants() {
|
||||
);
|
||||
|
||||
let processed_event = &processed[1];
|
||||
let ProcessedToDeviceEvent::PlainText(_) = processed_event else {
|
||||
panic!("Unexpected variant");
|
||||
};
|
||||
assert_matches!(processed_event, ProcessedToDeviceEvent::PlainText(_));
|
||||
|
||||
let processed_event = &processed[2];
|
||||
let ProcessedToDeviceEvent::NotProcessed(_) = processed_event else {
|
||||
panic!("Unexpected variant");
|
||||
};
|
||||
assert_matches!(processed_event, ProcessedToDeviceEvent::NotProcessed(_));
|
||||
|
||||
let processed_event = &processed[3];
|
||||
let ProcessedToDeviceEvent::UnableToDecrypt { .. } = processed_event else {
|
||||
panic!("Unexpected variant");
|
||||
};
|
||||
assert_matches!(processed_event, ProcessedToDeviceEvent::UnableToDecrypt { .. });
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
|
||||
Reference in New Issue
Block a user