diff --git a/bindings/matrix-sdk-crypto-ffi/src/machine.rs b/bindings/matrix-sdk-crypto-ffi/src/machine.rs index e4513042c..9e5803639 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/machine.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/machine.rs @@ -554,8 +554,10 @@ impl OlmMachine { }), )?; - let to_device_events = - to_device_events.into_iter().map(|event| event.json().get().to_owned()).collect(); + let to_device_events = to_device_events + .into_iter() + .map(|event| event.to_raw().json().get().to_owned()) + .collect(); let room_key_infos = room_key_infos.into_iter().map(|info| info.into()).collect(); Ok(SyncChangesResult { to_device_events, room_key_infos }) @@ -930,6 +932,8 @@ impl OlmMachine { }, } } + // Should not happen + _ => panic!("Unsupported algorithm in room"), }) } diff --git a/crates/matrix-sdk-base/src/response_processors/e2ee/to_device.rs b/crates/matrix-sdk-base/src/response_processors/e2ee/to_device.rs index 7da337a3a..f1f0b2ed0 100644 --- a/crates/matrix-sdk-base/src/response_processors/e2ee/to_device.rs +++ b/crates/matrix-sdk-base/src/response_processors/e2ee/to_device.rs @@ -99,6 +99,15 @@ async fn process( let (events, room_key_updates) = olm_machine.receive_sync_changes(encryption_sync_changes).await?; + let events = events + .iter() + // XXX There is loss of information here, after calling `to_raw` it is not + // possible to make the difference between a successfully decrypted event and a plain + // text event. This information needs to be propagated to top layer at some point if + // clients relies on custom encrypted to device events. + .map(|p| p.to_raw()) + .collect(); + Output { decrypted_to_device_events: events, room_key_updates: Some(room_key_updates) } } else { // If we have no `OlmMachine`, just return the events that were passed in. diff --git a/crates/matrix-sdk-common/src/deserialized_responses.rs b/crates/matrix-sdk-common/src/deserialized_responses.rs index e4a903ab4..930293e4c 100644 --- a/crates/matrix-sdk-common/src/deserialized_responses.rs +++ b/crates/matrix-sdk-common/src/deserialized_responses.rs @@ -17,7 +17,7 @@ use std::{collections::BTreeMap, fmt}; #[cfg(doc)] use ruma::events::AnyTimelineEvent; use ruma::{ - events::{AnyMessageLikeEvent, AnySyncTimelineEvent}, + events::{AnyMessageLikeEvent, AnySyncTimelineEvent, AnyToDeviceEvent}, push::Action, serde::{ AsRefStr, AsStrAsRefStr, DebugAsRefStr, DeserializeFromCowStr, FromString, JsonObject, Raw, @@ -282,6 +282,11 @@ pub enum AlgorithmInfo { /// key. sender_claimed_keys: BTreeMap, }, + + OlmV1Curve25519AesSha2 { + // The sender key of the device that encrypted the message + curve25519_key: String, + }, } /// Struct containing information on how an event was decrypted. @@ -615,6 +620,40 @@ impl fmt::Debug for DecryptedRoomEvent { } } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ProcessedToDeviceEvent { + /// A successfully-decrypted encrypted event. + Decrypted { + /// The decrypted to device event + decrypted_event: Raw, + /// Sender encryption information + encryption_info: EncryptionInfo, + }, + + /// An encrypted event which could not be decrypted. + UnableToDecrypt { + /// The `m.room.encrypted` to device event. + event: Raw, + }, + + /// An unencrypted event. + PlainText(Raw), + + /// An invalid to device event that was ignored + NotProcessed(Raw), +} + +impl ProcessedToDeviceEvent { + pub fn to_raw(&self) -> Raw { + match self { + ProcessedToDeviceEvent::Decrypted { decrypted_event, .. } => decrypted_event.clone(), + ProcessedToDeviceEvent::UnableToDecrypt { event } => event.clone(), + ProcessedToDeviceEvent::PlainText(event) => event.clone(), + ProcessedToDeviceEvent::NotProcessed(event) => event.clone(), + } + } +} + /// The location of an event bundled in an `unsigned` object. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub enum UnsignedEventLocation { diff --git a/crates/matrix-sdk-crypto/CHANGELOG.md b/crates/matrix-sdk-crypto/CHANGELOG.md index 40857f7f0..891228510 100644 --- a/crates/matrix-sdk-crypto/CHANGELOG.md +++ b/crates/matrix-sdk-crypto/CHANGELOG.md @@ -20,6 +20,12 @@ All notable changes to this project will be documented in this file. ### Features +- [**breaking**] `OlmMachine.receive_sync_changes` returns now a list of `ProcessedToDeviceEvent` + instead of a list of `Raw`. With variants like `Decrypted`|`UnableToDecrypt`|`PlainText`|`NotProcessed`. + This allows for example to make the difference between an event sent in clear and an event successfully decrypted. + A `ProcessedToDeviceEvent::Decrypted` now contains the `encryption_info` and `verification_state` of the event. + For quick compatibility a helper `ProcessedToDeviceEvent::to_raw` allows to map back to the previous behaviour. + - [**breaking**] Add support for the shared history flag defined in [MSC3061](https://github.com/matrix-org/matrix-spec-proposals/pull/3061). The shared history flag is now respected when room keys are received as an diff --git a/crates/matrix-sdk-crypto/src/machine/mod.rs b/crates/matrix-sdk-crypto/src/machine/mod.rs index 908e52492..48d3c2385 100644 --- a/crates/matrix-sdk-crypto/src/machine/mod.rs +++ b/crates/matrix-sdk-crypto/src/machine/mod.rs @@ -21,9 +21,9 @@ use std::{ use itertools::Itertools; use matrix_sdk_common::{ deserialized_responses::{ - AlgorithmInfo, DecryptedRoomEvent, DeviceLinkProblem, EncryptionInfo, UnableToDecryptInfo, - UnableToDecryptReason, UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel, - VerificationState, + AlgorithmInfo, DecryptedRoomEvent, DeviceLinkProblem, EncryptionInfo, + ProcessedToDeviceEvent, UnableToDecryptInfo, UnableToDecryptReason, + UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel, VerificationState, }, locks::RwLock as StdRwLock, BoxFuture, @@ -1286,7 +1286,7 @@ impl OlmMachine { transaction: &mut StoreTransaction, changes: &mut Changes, mut raw_event: Raw, - ) -> Option> { + ) -> Option { Self::record_message_id(&raw_event); let event: ToDeviceEvents = match raw_event.deserialize_as() { @@ -1294,8 +1294,7 @@ impl OlmMachine { Err(e) => { // Skip invalid events. warn!("Received an invalid to-device event: {e}"); - - return Some(raw_event); + return Some(ProcessedToDeviceEvent::NotProcessed(raw_event)); } }; @@ -1320,7 +1319,7 @@ impl OlmMachine { } } - return Some(raw_event); + return Some(ProcessedToDeviceEvent::UnableToDecrypt { event: raw_event }); } }; @@ -1372,12 +1371,75 @@ impl OlmMachine { raw_event = decrypted.result.raw_event; } } + + let encryption_info = + self.get_olm_encryption_info(&e.sender, decrypted.result.sender_key).await; + + Some(ProcessedToDeviceEvent::Decrypted { + decrypted_event: raw_event, + encryption_info, + }) } - e => self.handle_to_device_event(changes, &e).await, + e => { + self.handle_to_device_event(changes, &e).await; + Some(ProcessedToDeviceEvent::PlainText(raw_event)) + } } + } - Some(raw_event) + /// Get the sender information for a successfully decrypted olm message. + /// + /// # Arguments + /// + /// * `sender` - The claimed user_id retrieved from the event. + /// + /// * `sender_key` - The `Curve25519PublicKey` linked to the olm session + /// that decrypted the message. + /// + /// # Returns + /// + /// A [`EncryptionInfo`] struct. + async fn get_olm_encryption_info( + &self, + sender: &UserId, + sender_key: Curve25519PublicKey, + ) -> EncryptionInfo { + let device = + self.store().get_device_from_curve_key(sender, sender_key).await.unwrap_or(None); + + let state = if let Some(device) = &device { + if device.is_cross_signed_by_owner() { + if device.is_device_owner_verified() { + VerificationState::Verified + } else { + let identity = device + .device_owner_identity + .as_ref() + .expect("This device is cross-signed, so the identity exists"); + if identity.was_previously_verified() { + VerificationState::Unverified(VerificationLevel::VerificationViolation) + } else { + VerificationState::Unverified(VerificationLevel::UnverifiedIdentity) + } + } + } else { + VerificationState::Unverified(VerificationLevel::UnsignedDevice) + } + } else { + VerificationState::Unverified(VerificationLevel::None(DeviceLinkProblem::MissingDevice)) + }; + + EncryptionInfo { + sender: sender.to_owned(), + sender_device: device.map(|d| d.device_id().to_owned()), + algorithm_info: AlgorithmInfo::OlmV1Curve25519AesSha2 { + curve25519_key: sender_key.to_base64(), + }, + verification_state: state, + // Only relevant for megolm + session_id: None, + } } /// Decide whether a decrypted to-device event was sent from a dehydrated @@ -1435,7 +1497,7 @@ impl OlmMachine { pub async fn receive_sync_changes( &self, sync_changes: EncryptionSyncChanges<'_>, - ) -> OlmResult<(Vec>, Vec)> { + ) -> OlmResult<(Vec, Vec)> { let mut store_transaction = self.inner.store.transaction().await; let (events, changes) = @@ -1464,10 +1526,18 @@ impl OlmMachine { &self, transaction: &mut StoreTransaction, sync_changes: EncryptionSyncChanges<'_>, - ) -> OlmResult<(Vec>, Changes)> { + ) -> OlmResult<(Vec, Changes)> { // Remove verification objects that have expired or are done. - let mut events = self.inner.verification_machine.garbage_collect(); - + let mut events: Vec = self + .inner + .verification_machine + .garbage_collect() + .iter() + // These are `fake` to device events just serving as local echo + // in order for own client to react quickly to cancelled transaction. + // Just use PlainText for that. + .map(|e| ProcessedToDeviceEvent::PlainText(e.clone())) + .collect(); // The account is automatically saved by the store transaction created by the // caller. let mut changes = Default::default(); diff --git a/crates/matrix-sdk-crypto/src/machine/tests/megolm_sender_data.rs b/crates/matrix-sdk-crypto/src/machine/tests/megolm_sender_data.rs index 36477b241..1a6b9588f 100644 --- a/crates/matrix-sdk-crypto/src/machine/tests/megolm_sender_data.rs +++ b/crates/matrix-sdk-crypto/src/machine/tests/megolm_sender_data.rs @@ -17,8 +17,9 @@ use std::{fmt::Debug, iter, pin::Pin}; use assert_matches::assert_matches; use futures_core::Stream; use futures_util::{FutureExt, StreamExt}; +use matrix_sdk_common::deserialized_responses::ProcessedToDeviceEvent; use matrix_sdk_test::async_test; -use ruma::{events::AnyToDeviceEvent, room_id, serde::Raw, user_id, RoomId, TransactionId, UserId}; +use ruma::{room_id, user_id, RoomId, TransactionId, UserId}; use serde::Serialize; use serde_json::json; use tokio_stream::wrappers::errors::BroadcastStreamRecvError; @@ -286,7 +287,7 @@ async fn create_and_share_session_without_sender_data( pub async fn receive_to_device_event( machine: &OlmMachine, event: &ToDeviceEvent, -) -> (Vec>, Vec) +) -> (Vec, Vec) where C: EventType + Serialize + Debug, { diff --git a/crates/matrix-sdk-crypto/src/machine/tests/mod.rs b/crates/matrix-sdk-crypto/src/machine/tests/mod.rs index c464d1f05..e5d0dc54a 100644 --- a/crates/matrix-sdk-crypto/src/machine/tests/mod.rs +++ b/crates/matrix-sdk-crypto/src/machine/tests/mod.rs @@ -18,8 +18,9 @@ use assert_matches2::{assert_let, assert_matches}; use futures_util::{pin_mut, FutureExt, StreamExt}; use itertools::Itertools; use matrix_sdk_common::deserialized_responses::{ - AlgorithmInfo, UnableToDecryptInfo, UnableToDecryptReason, UnsignedDecryptionResult, - UnsignedEventLocation, VerificationLevel, VerificationState, WithheldCode, + AlgorithmInfo, ProcessedToDeviceEvent, UnableToDecryptInfo, UnableToDecryptReason, + UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel, VerificationState, + WithheldCode, }; use matrix_sdk_test::{async_test, message_like_event_content, ruma_response_from_json, test_json}; use ruma::{ @@ -397,7 +398,7 @@ async fn test_room_key_sharing() { let (decrypted, room_key_updates) = send_room_key_to_device(&alice, &bob, room_id).await.unwrap(); - let event = decrypted[0].deserialize().unwrap(); + let event = decrypted[0].to_raw().deserialize().unwrap(); if let AnyToDeviceEvent::RoomKey(event) = event { assert_eq!(&event.sender, alice.user_id()); @@ -489,7 +490,7 @@ async fn send_room_key_to_device( sender: &OlmMachine, receiver: &OlmMachine, room_id: &RoomId, -) -> OlmResult<(Vec>, Vec)> { +) -> OlmResult<(Vec, Vec)> { let to_device_requests = sender .share_room_key(room_id, iter::once(receiver.user_id()), EncryptionSettings::default()) .await diff --git a/crates/matrix-sdk-crypto/src/machine/tests/olm_encryption.rs b/crates/matrix-sdk-crypto/src/machine/tests/olm_encryption.rs index 478979a8c..efdeed6e4 100644 --- a/crates/matrix-sdk-crypto/src/machine/tests/olm_encryption.rs +++ b/crates/matrix-sdk-crypto/src/machine/tests/olm_encryption.rs @@ -18,6 +18,7 @@ use std::{ }; use assert_matches2::assert_let; +use matrix_sdk_common::deserialized_responses::ProcessedToDeviceEvent; use matrix_sdk_test::async_test; use ruma::{ device_id, @@ -292,7 +293,11 @@ async fn test_decrypt_to_device_message_with_unsigned_sender_keys() { // Bob receives the to-device message let (to_device_events, _) = receive_to_device_event(&bob, &event).await; + let event = to_device_events.first().expect("Bob did not get a to-device event").clone(); + // The to-device event should remain decrypted. - let event = to_device_events.first().expect("Bob did not get a to-device event"); + let ProcessedToDeviceEvent::UnableToDecrypt { event } = event else { + panic!("Should refuse to decrypt") + }; assert_eq!(event.get_field("type").unwrap(), Some("m.room.encrypted")); } diff --git a/crates/matrix-sdk-crypto/src/machine/tests/send_encrypted_to_device.rs b/crates/matrix-sdk-crypto/src/machine/tests/send_encrypted_to_device.rs index 41faf70c9..aa6234984 100644 --- a/crates/matrix-sdk-crypto/src/machine/tests/send_encrypted_to_device.rs +++ b/crates/matrix-sdk-crypto/src/machine/tests/send_encrypted_to_device.rs @@ -13,8 +13,11 @@ // limitations under the License. use assert_matches2::assert_matches; +use matrix_sdk_common::deserialized_responses::{ + AlgorithmInfo, ProcessedToDeviceEvent, VerificationLevel, VerificationState, +}; use matrix_sdk_test::async_test; -use ruma::to_device::DeviceIdOrAllDevices; +use ruma::{events::AnyToDeviceEvent, serde::Raw, to_device::DeviceIdOrAllDevices}; use serde_json::{json, value::to_raw_value}; use crate::{ @@ -22,7 +25,10 @@ use crate::{ test_helpers::{get_machine_pair, get_machine_pair_with_session}, tests, }, - types::{events::ToDeviceEvent, requests::ToDeviceRequest}, + types::{ + events::{ToDeviceCustomEvent, ToDeviceEvent}, + requests::ToDeviceRequest, + }, utilities::json_convert, EncryptionSyncChanges, OlmError, }; @@ -81,12 +87,15 @@ async fn test_send_encrypted_to_device() { let (decrypted, _) = bob.receive_sync_changes(sync_changes).await.unwrap(); assert_eq!(1, decrypted.len()); - - let decrypted_event = decrypted[0].deserialize().unwrap(); + let processed_event = &decrypted[0]; + let ProcessedToDeviceEvent::Decrypted { decrypted_event, .. } = processed_event else { + panic!("Unexpected variant"); + }; + let decrypted_event = decrypted_event.deserialize().unwrap(); assert_eq!(decrypted_event.event_type().to_string(), custom_event_type.to_owned()); - let decrypted_value = to_raw_value(&decrypted[0]).unwrap(); + let decrypted_value = to_raw_value(&decrypted[0].to_raw()).unwrap(); let decrypted_value = serde_json::to_value(decrypted_value).unwrap(); assert_eq!( @@ -100,6 +109,142 @@ async fn test_send_encrypted_to_device() { ); } +#[async_test] +async fn test_processed_to_device_variants() { + let (alice, bob) = + get_machine_pair_with_session(tests::alice_id(), tests::user_id(), false).await; + + let custom_event_type = "m.new_device"; + + let custom_content = json!({ + "device_id": "XYZABCDE", + "rooms": ["!726s6s6q:example.com"] + }); + + let device = alice.get_device(bob.user_id(), bob.device_id(), None).await.unwrap().unwrap(); + let raw_encrypted = device + .encrypt_event_raw(custom_event_type, &custom_content) + .await + .expect("Should have encryted the content"); + + let request = ToDeviceRequest::new( + bob.user_id(), + DeviceIdOrAllDevices::DeviceId(tests::bob_device_id().to_owned()), + "m.room.encrypted", + raw_encrypted.cast(), + ); + + let encrypted_event = ToDeviceEvent::new( + alice.user_id().to_owned(), + tests::to_device_requests_to_content(vec![request.clone().into()]), + ); + + let custom_event = json!({ + "sender": "@alice:example.com", + "type": "m.new_device", + "content": { + "device_id": "XYZABCDE", + "rooms": ["!726s6s6q:example.com"] + } + }); + let clear_event = serde_json::from_value::(custom_event.clone()).unwrap(); + + let encrypted_event = json_convert(&encrypted_event).unwrap(); + let clear_event = json_convert(&clear_event).unwrap(); + + let malformed_event_no_type = json!({ + "sender": "@alice:example.com", + "content": { + "device_id": "XYZABCDE", + "rooms": ["!726s6s6q:example.com"] + } + }); + let malformed_event: Raw = + serde_json::from_value(malformed_event_no_type).unwrap(); + + let alice_curve = alice + .get_device(alice.user_id(), alice.device_id(), None) + .await + .unwrap() + .unwrap() + .curve25519_key() + .unwrap(); + let bob_curve = bob + .get_device(bob.user_id(), bob.device_id(), None) + .await + .unwrap() + .unwrap() + .curve25519_key() + .unwrap(); + + // let's add a UTD event + let utd_event = json!({ + "content": { + "algorithm": "m.olm.v1.curve25519-aes-sha2", + "ciphertext": { + bob_curve.to_base64(): { + // this payload is just captured from a sync of some other element web with other users + "body": "Awogjvpx458CGhuo77HX/+tp1sxgRoCi7iAlzMvfrpbWoREQAiKACysX/p+ojr5QitCi9WRXNyamW2v2LTvoyWKtVaA2oHnYGR5s5RYhDfnIgh5MMSqqKlAbfqLvrbLovTYcKagCBbFnbA43f6zYM44buGgy8q70hMVH5WP6aK1E9Z3DVZ+8PnXQGpsrxvz2IsL6w0Nzl/qUyBEQFcgkjoDPawbsZRCllMgq2LQUyqlun6IgDTCozqsfxhDWpdfYGde4z16m34Ang7f5pH+BmPrFs6E1AO5+UbhhhS6NwWlfEtA6/9yfMxWLz1d2OrLh+QG7lYFAU9/CzIoPxaHKKr4JxgL9CjsmUPyDymWOWHP0jLi1NwpOv6hGpx0FgM7jJIMk6gWGgC5rEgEeTIwdrJh3F9OKTNSva5hvD9LomGk6tZgzQG6oap1e3wiOUyTt6S7BlyMppIu3RlIiNihZ9e17JEGiGDXOXzMJ6ISAgvGVgTP7+EvyEt2Wt4du7uBo/UvljRvVNu3I8tfItizPAOlvz460+aBDxk+sflJWt7OnhiyPnOCfopb+1RzqKVCnnPyVaP2f4BPf8qpn/f5YZk+5jJgBrGPiHzzmb3sQ5pC470s6+U3MpVFlFTG/xPBtMRMwPsbKoHfnRPqIqGu5dQ1Sw7T6taDXWjP450TvjxgHK5t2z1rLA2SXzAB1P8xbi6YXqQwxL6PvMNHn/TM0jiIQHYuqg5/RKLyhHybfP8JAjgNBw9z16wfKR/YoYFr7c+S4McQaMNa8v2SxGzhpCC3duAoK2qCWLEkYRO5cMCsGm/9bf8Q+//OykygBU/hdkT1eHUbexgALPLdfhzduutU7pbChg4T7SH7euh/3NLmS/SQvkmPfm3ckbh/Vlcj9CsXws/7MX/VJbhpbyzgBNtMnbG6tAeAofMa6Go/yMgiNBZIhLpAm31iUbUhaGm2IIlF/lsmSYEiBPoSVfFU44tetX2I/PBDGiBlzyU+yC2TOEBwMGxBE3WHbIe5/7sKW8xJF9t+HBfxIyW1QRtY3EKdEcuVOTyMxYzq3L5OKOOtPDHObYiiXg00mAgdQqgfkEAIfoRCOa2NYfTedwwo0S77eQ1sPvW5Hhf+Cm+bLibkWzaYHEZF+vyE9/Tn0tZGtH07RXfUyhp1vtTH49OBZHGkb/r+L8OjYJTST1dDCGqeGXO3uwYjoWHXtezLVHYgL+UOwcLJfMF5s9DQiqcfYXzp2kEWGsaetBFXcUWqq4RMHqlr6QfbxyuYLlQzc/AYA/MrT3J6nDpNLcvozH3RcIs8NcKcjdtjvgL0QGThy3RcecJQEDx3STrkkePL3dlyFCtVsmtQ0vjBBCxUgdySfxiobGGnpezZYi7q+Xz61GOZ9QqYmkcZOPzfNWeqtmzB7gqlH1gkFsK2yMAzKq2XCDFHvA7YAT3yMGiY06FcQ+2jyg7Bk2Q+AvjTG8hlPlmt6BZfW5cz1qx1apQn1qHXHrgfWcI52rApYQlNPOU1Uc8kZ8Ee6XUhhXBGY1rvZiKjKFG0PPuS8xo4/P7/u+gH5gItmEVDFL6giYPFsPpqAQkUN7hFoGiVZEjO4PwrLOmydsEcNOfACqrnUs08FQtvPg0sjHnxh6nh6FUQv93ukKl6+c9d+pCsN2xukrQ7Dog3nrjFZ6PrS5J0k9rDAOwTB55sfGXPZ2rATOK1WS4XcpsCtqwnYm4sGNc8ALMQkQ97zCnw8TcQwLvdUMlfbqQ5ykDQpQD68fITEDDHmBAeTCjpC713E6AhvOMwTJvjhd7hSkeOTRTmn9zXIVGNo1jSr8u0xO9uLGeWsV0+UlRLgp7/nsgfermjwNN8wj6MW3DHGS8UzzYfe9TGCeywqqIUTqgfXY48leGgB7twh4cl4jcOQniLATTvigIAQIvq/Uv8L45BGnkpKTdQ5F73gehXdVA", + "type": 1 + } + }, + "org.matrix.msgid": "93ee0170aa7740d0ac9ee137e820302d", + "sender_key": alice_curve.to_base64(), + }, + "type": "m.room.encrypted", + "sender": "@alice:example.org", + }); + + let utd_event: Raw = serde_json::from_value(utd_event).unwrap(); + + let sync_changes = EncryptionSyncChanges { + to_device_events: vec![encrypted_event, clear_event, malformed_event, utd_event], + changed_devices: &Default::default(), + one_time_keys_counts: &Default::default(), + unused_fallback_keys: None, + next_batch_token: None, + }; + + let (processed, _) = bob.receive_sync_changes(sync_changes).await.unwrap(); + + assert_eq!(4, processed.len()); + + let processed_event = &processed[0]; + let ProcessedToDeviceEvent::Decrypted { encryption_info, .. } = processed_event else { + panic!("Unexpected variant"); + }; + + 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_eq!(curve25519_key.to_owned(), alice_curve.to_base64()); + + assert_eq!(encryption_info.session_id, None); + assert_eq!( + encryption_info.verification_state, + VerificationState::Unverified(VerificationLevel::UnsignedDevice) + ); + + let processed_event = &processed[1]; + let ProcessedToDeviceEvent::PlainText(_) = processed_event else { + panic!("Unexpected variant"); + }; + + let processed_event = &processed[2]; + let ProcessedToDeviceEvent::NotProcessed(_) = processed_event else { + panic!("Unexpected variant"); + }; + + let processed_event = &processed[3]; + let ProcessedToDeviceEvent::UnableToDecrypt { .. } = processed_event else { + panic!("Unexpected variant"); + }; +} + #[async_test] async fn test_send_encrypted_to_device_no_session() { let (alice, bob, _) = get_machine_pair(tests::alice_id(), tests::user_id(), false).await; diff --git a/crates/matrix-sdk-crypto/src/session_manager/group_sessions/mod.rs b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/mod.rs index efda93c4f..4dca250eb 100644 --- a/crates/matrix-sdk-crypto/src/session_manager/group_sessions/mod.rs +++ b/crates/matrix-sdk-crypto/src/session_manager/group_sessions/mod.rs @@ -1031,7 +1031,7 @@ mod tests { }; use assert_matches2::assert_let; - use matrix_sdk_common::deserialized_responses::WithheldCode; + use matrix_sdk_common::deserialized_responses::{ProcessedToDeviceEvent, WithheldCode}; use matrix_sdk_test::{async_test, ruma_response_from_json}; use ruma::{ api::client::{ @@ -1822,8 +1822,12 @@ mod tests { let (decrypted, _) = bob.receive_sync_changes(sync_changes).await.unwrap(); assert_eq!(1, decrypted.len()); use crate::types::events::EventType; + assert_let!( + ProcessedToDeviceEvent::Decrypted { decrypted_event, .. } = + decrypted.first().unwrap().clone() + ); assert_eq!( - decrypted[0].get_field::("type").unwrap().unwrap(), + decrypted_event.get_field::("type").unwrap().unwrap(), RoomKeyBundleContent::EVENT_TYPE, ); }