diff --git a/crates/matrix-sdk-crypto/src/session_manager/group_sessions.rs b/crates/matrix-sdk-crypto/src/session_manager/group_sessions.rs index 8cdb2f502..80ab0063d 100644 --- a/crates/matrix-sdk-crypto/src/session_manager/group_sessions.rs +++ b/crates/matrix-sdk-crypto/src/session_manager/group_sessions.rs @@ -505,7 +505,6 @@ impl GroupSessionManager { let encryption_settings = encryption_settings.into(); let algorithm = encryption_settings.algorithm.to_owned(); let mut changes = Changes::default(); - // let mut no_olm: BTreeMap> = BTreeMap::new(); // Try to get an existing session or create a new one. let (outbound, inbound) = @@ -722,7 +721,7 @@ impl GroupSessionManager { #[cfg(test)] mod tests { - use std::{collections::HashSet, ops::Deref}; + use std::{collections::HashSet, ops::Deref, sync::Arc}; use matrix_sdk_test::{async_test, response_from_file}; use ruma::{ @@ -749,7 +748,7 @@ mod tests { }, EventEncryptionAlgorithm, }, - Device, EncryptionSettings, LocalTrust, OlmMachine, + Device, EncryptionSettings, LocalTrust, OlmMachine, ToDeviceRequest, }; fn alice_id() -> &'static UserId { @@ -905,6 +904,30 @@ mod tests { assert_eq!(withheld_count, 2); } + fn count_withheld_from(requests: &[Arc], code: WithheldCode) -> usize { + requests + .iter() + .filter(|r| r.event_type == "m.room_key.withheld".into()) + .map(|r| { + let mut count = 0; + // count targets + for message in r.messages.values() { + message.iter().for_each(|(_, content)| { + let withheld: RoomKeyWithheldContent = + content.deserialize_as::().unwrap(); + + if let MegolmV1AesSha2(content) = withheld { + if content.withheld_code() == code { + count += 1; + } + } + }) + } + count + }) + .sum() + } + #[async_test] async fn test_no_olm_sent_once() { let machine = machine().await; @@ -913,33 +936,24 @@ mod tests { let users = keys_claim.one_time_keys.keys().map(Deref::deref); let first_room_id = room_id!("!test:localhost"); + let requests = machine - .share_room_key(first_room_id, users, EncryptionSettings::default()) + .share_room_key(first_room_id, users.to_owned(), EncryptionSettings::default()) .await .unwrap(); // there will be two no_olm - let withheld_count: usize = requests - .iter() - .filter(|r| r.event_type == "m.room_key.withheld".into()) - .map(|r| { - let mut count = 0; - // count targets - for message in r.messages.values() { - message.iter().for_each(|(_, content)| { - let withheld: RoomKeyWithheldContent = - content.deserialize_as::().unwrap(); + let withheld_count: usize = count_withheld_from(&requests, WithheldCode::NoOlm); + assert_eq!(withheld_count, 2); - if let MegolmV1AesSha2(content) = withheld { - if content.withheld_code() == WithheldCode::NoOlm { - count += 1; - } - } - }) - } - count - }) - .sum(); + // Re-sharing same session while request has not been sent should not produces + // withheld + let new_requests = machine + .share_room_key(first_room_id, users, EncryptionSettings::default()) + .await + .unwrap(); + let withheld_count: usize = count_withheld_from(&new_requests, WithheldCode::NoOlm); + // No additional request was added, still the 2 already pending assert_eq!(withheld_count, 2); let response = ToDeviceResponse::new(); @@ -947,6 +961,8 @@ mod tests { machine.mark_request_as_sent(&request.txn_id, &response).await.unwrap(); } + // The fact that an olm was sent should be remembered even if sharing another + // session in an other room. let second_room_id = room_id!("!other:localhost"); let users = keys_claim.one_time_keys.keys().map(Deref::deref); let requests = machine @@ -954,28 +970,7 @@ mod tests { .await .unwrap(); - // there will be two no_olm - let withheld_count: usize = requests - .iter() - .filter(|r| r.event_type == "m.room_key.withheld".into()) - .map(|r| { - let mut count = 0; - // count targets - for message in r.messages.values() { - message.iter().for_each(|(_, content)| { - let withheld: RoomKeyWithheldContent = - content.deserialize_as::().unwrap(); - - if let MegolmV1AesSha2(content) = withheld { - if content.withheld_code() == WithheldCode::NoOlm { - count += 1; - } - } - }) - } - count - }) - .sum(); + let withheld_count: usize = count_withheld_from(&requests, WithheldCode::NoOlm); assert_eq!(withheld_count, 0); // Help how do I simulate the creation of a new session for the device diff --git a/crates/matrix-sdk-crypto/src/types/events/room_key_withheld.rs b/crates/matrix-sdk-crypto/src/types/events/room_key_withheld.rs index 7c6af93c4..28ddbabdf 100644 --- a/crates/matrix-sdk-crypto/src/types/events/room_key_withheld.rs +++ b/crates/matrix-sdk-crypto/src/types/events/room_key_withheld.rs @@ -411,7 +411,7 @@ pub(super) mod test { EventEncryptionAlgorithm, }; - pub fn json() -> Value { + pub fn json(code: &WithheldCode) -> Value { json!({ "sender": "@alice:example.org", "content": { @@ -419,8 +419,8 @@ pub(super) mod test { "session_id": "0ZcULv8j1nqVWx6orFjD6OW9JQHydDPXfaanA+uRyfs", "algorithm": "m.megolm.v1.aes-sha2", "sender_key": "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA", - "code": "m.unverified", - "reason": "The sender has disabled encrypting to unverified devices.", + "code": code.to_owned(), + "reason": code.to_human_readable(), "org.matrix.msgid": "8836f2f0-635d-4f0e-9228-446c63ba3ea3" }, "type": "m.room_key.withheld", @@ -443,6 +443,21 @@ pub(super) mod test { }) } + pub fn unknown_alg_json() -> Value { + json!({ + "sender": "@alice:example.org", + "content": { + "algorithm": "caesar.cipher", + "sender_key": "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA", + "code": "m.brutus", + "reason": "Tu quoque fili", + "org.matrix.msgid": "8836f2f0-635d-4f0e-9228-446c63ba3ea3" + }, + "type": "m.room_key.withheld", + "m.custom.top": "something custom in the top", + }) + } + pub fn unknown_code_json() -> Value { json!({ "sender": "@alice:example.org", @@ -462,15 +477,44 @@ pub(super) mod test { #[test] fn deserialization() -> Result<(), serde_json::Error> { - let json = json(); - let event: RoomKeyWithheldEvent = serde_json::from_value(json.clone())?; - assert_matches!( - event.content, - RoomKeyWithheldContent::MegolmV1AesSha2(MegolmV1AesSha2WithheldContent::AnyContent(_)) - ); - let serialized = serde_json::to_value(event)?; - assert_eq!(json, serialized); + let codes = [ + WithheldCode::Unverified, + WithheldCode::Blacklisted, + WithheldCode::Unauthorised, + WithheldCode::Unavailable, + ]; + for code in codes { + let json = json(&code); + let event: RoomKeyWithheldEvent = serde_json::from_value(json.clone())?; + assert_matches!( + event.content, + RoomKeyWithheldContent::MegolmV1AesSha2( + MegolmV1AesSha2WithheldContent::AnyContent(_) + ) + ); + if let RoomKeyWithheldContent::MegolmV1AesSha2(content) = &event.content { + assert_eq!(content.withheld_code().to_owned(), code) + } else { + panic!() + } + + if let RoomKeyWithheldContent::MegolmV1AesSha2( + MegolmV1AesSha2WithheldContent::AnyContent((_, content)), + ) = &event.content + { + assert_eq!(content.reason, ruma::JsOption::Some(code.to_human_readable())) + } else { + panic!() + } + + assert_eq!( + event.content.algorithm().to_owned(), + EventEncryptionAlgorithm::MegolmV1AesSha2 + ); + let serialized = serde_json::to_value(event)?; + assert_eq!(json, serialized); + } Ok(()) } @@ -513,6 +557,23 @@ pub(super) mod test { Ok(()) } + #[test] + fn deserialization_unknown_alg() -> Result<(), serde_json::Error> { + let json = unknown_alg_json(); + let event: RoomKeyWithheldEvent = serde_json::from_value(json.clone())?; + assert_matches!(event.content, RoomKeyWithheldContent::Unknown(_)); + + if let RoomKeyWithheldContent::Unknown(content) = &event.content { + assert_matches!(content.code, WithheldCode::_Custom(_)); + } else { + panic!() + } + let serialized = serde_json::to_value(event)?; + assert_eq!(json, serialized); + + Ok(()) + } + #[test] fn serialization_to_device() { let mut messages = BTreeMap::new();