diff --git a/Cargo.lock b/Cargo.lock index 48ff993ff5d..69d5aaaf929 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3066,6 +3066,7 @@ dependencies = [ name = "matrix-sdk-sled" version = "0.2.0" dependencies = [ + "assert_matches", "async-stream", "async-trait", "dashmap", @@ -3093,6 +3094,7 @@ dependencies = [ name = "matrix-sdk-sqlite" version = "0.1.0" dependencies = [ + "assert_matches", "async-stream", "async-trait", "ctor", diff --git a/Cargo.toml b/Cargo.toml index 0cc37470aef..aa8b66d32a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ rust-version = "1.65" [workspace.dependencies] anyhow = "1.0.68" +assert_matches = "1.5.0" async-stream = "0.3.3" async-trait = "0.1.60" base64 = "0.21.0" diff --git a/crates/matrix-sdk-base/Cargo.toml b/crates/matrix-sdk-base/Cargo.toml index ec210d3042d..7afafaffb00 100644 --- a/crates/matrix-sdk-base/Cargo.toml +++ b/crates/matrix-sdk-base/Cargo.toml @@ -27,7 +27,7 @@ experimental-sliding-sync = ["ruma/unstable-msc3575"] testing = ["dep:http", "dep:matrix-sdk-test", "dep:assert_matches"] [dependencies] -assert_matches = { version = "1.5.0", optional = true } +assert_matches = { workspace = true, optional = true } async-stream = { workspace = true } async-trait = { workspace = true } dashmap = { workspace = true } @@ -48,7 +48,7 @@ tracing = { workspace = true } zeroize = { workspace = true, features = ["zeroize_derive"] } [dev-dependencies] -assert_matches = "1.5.0" +assert_matches = { workspace = true } assign = "1.1.1" ctor = { workspace = true } futures = { version = "0.3.21", default-features = false, features = ["executor"] } diff --git a/crates/matrix-sdk-crypto/Cargo.toml b/crates/matrix-sdk-crypto/Cargo.toml index 4ac80533fb2..7b00312251d 100644 --- a/crates/matrix-sdk-crypto/Cargo.toml +++ b/crates/matrix-sdk-crypto/Cargo.toml @@ -63,7 +63,7 @@ tokio = { version = "1.24", default-features = false, features = ["time"] } [dev-dependencies] anyhow = { workspace = true } -assert_matches = "1.5.0" +assert_matches = { workspace = true } ctor.workspace = true futures = { version = "0.3.21", default-features = false, features = ["executor"] } http = { workspace = true } diff --git a/crates/matrix-sdk-crypto/src/machine.rs b/crates/matrix-sdk-crypto/src/machine.rs index 6946649f15d..bfb1d385a7a 100644 --- a/crates/matrix-sdk-crypto/src/machine.rs +++ b/crates/matrix-sdk-crypto/src/machine.rs @@ -69,8 +69,8 @@ use crate::{ requests::{IncomingResponse, OutgoingRequest, UploadSigningKeysRequest}, session_manager::{GroupSessionManager, SessionManager}, store::{ - withheld::DirectWithheldInfo, Changes, DeviceChanges, DynCryptoStore, IdentityChanges, - IntoCryptoStore, MemoryStore, Result as StoreResult, SecretImportError, Store, + Changes, DeviceChanges, DynCryptoStore, IdentityChanges, IntoCryptoStore, MemoryStore, + Result as StoreResult, SecretImportError, Store, }, types::{ events::{ @@ -80,7 +80,9 @@ use crate::{ RoomEventEncryptionScheme, SupportedEventEncryptionSchemes, }, room_key::{MegolmV1AesSha2Content, RoomKeyContent}, - room_key_withheld::RoomKeyWithheldEvent, + room_key_withheld::{ + MegolmV1AesSha2WithheldContent, RoomKeyWithheldContent, RoomKeyWithheldEvent, + }, ToDeviceEvents, }, Signatures, @@ -676,8 +678,19 @@ impl OlmMachine { changes: &mut Changes, event: &RoomKeyWithheldEvent, ) -> OlmResult<()> { - if let Some(info) = DirectWithheldInfo::from_event(event) { - changes.withheld_session_info.push(info) + match &event.content { + RoomKeyWithheldContent::MegolmV1AesSha2(c) => match c { + MegolmV1AesSha2WithheldContent::BlackListed(c) + | MegolmV1AesSha2WithheldContent::Unverified(c) => { + changes + .withheld_session_info + .entry(c.room_id.to_owned()) + .or_insert_with(BTreeMap::default) + .insert(c.session_id.to_owned(), event.to_owned()); + } + _ => (), + }, + _ => (), } Ok(()) @@ -1261,7 +1274,7 @@ impl OlmMachine { .store .get_withheld_info(room_id, content.session_id()) .await? - .map(|i| i.withheld_code()); + .map(|e| e.content.withheld_code()); if withheld_code.is_some() { // Partially withheld, report with a withheld code if we have one. @@ -1279,7 +1292,7 @@ impl OlmMachine { .store .get_withheld_info(room_id, content.session_id()) .await? - .map(|i| i.withheld_code()); + .map(|e| e.content.withheld_code()); Err(MegolmError::MissingRoomKey(withheld_code)) } 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 55e72659565..9700001dc14 100644 --- a/crates/matrix-sdk-crypto/src/session_manager/group_sessions.rs +++ b/crates/matrix-sdk-crypto/src/session_manager/group_sessions.rs @@ -34,10 +34,7 @@ use crate::{ identities::device::MaybeEncryptedRoomKey, olm::{Account, InboundGroupSession, OutboundGroupSession, Session, ShareInfo, ShareState}, store::{Changes, Result as StoreResult, Store}, - types::events::{ - room::encrypted::RoomEncryptedEventContent, - room_key_withheld::{RoomKeyWithheldContent, WithheldCode}, - }, + types::events::{room::encrypted::RoomEncryptedEventContent, room_key_withheld::WithheldCode}, Device, EncryptionSettings, OlmError, ToDeviceRequest, }; diff --git a/crates/matrix-sdk-crypto/src/store/integration_tests.rs b/crates/matrix-sdk-crypto/src/store/integration_tests.rs index aca45327c7c..ba39cfc3ada 100644 --- a/crates/matrix-sdk-crypto/src/store/integration_tests.rs +++ b/crates/matrix-sdk-crypto/src/store/integration_tests.rs @@ -5,6 +5,7 @@ macro_rules! cryptostore_integration_tests { mod cryptostore_integration_tests { use std::collections::{BTreeMap, HashMap}; + use assert_matches::assert_matches; use matrix_sdk_test::async_test; use ruma::{ device_id, encryption::SignedKey, room_id, serde::Base64, user_id, DeviceId, @@ -16,14 +17,18 @@ macro_rules! cryptostore_integration_tests { PrivateCrossSigningIdentity, ReadOnlyAccount, Session, }, store::{ - withheld::DirectWithheldInfo, Changes, CryptoStore, DeviceChanges, + Changes, CryptoStore, DeviceChanges, GossipRequest, IdentityChanges, RecoveryKey, RoomSettings, }, testing::{get_device, get_other_identity, get_own_identity}, types::{ events::{ room_key_request::MegolmV1AesSha2Content, - room_key_withheld::{CommonWithheldCodeContent, WithheldCode}, + room_key_withheld::{ + CommonWithheldCodeContent, MegolmV1AesSha2WithheldContent, + RoomKeyWithheldContent, WithheldCode, + }, + ToDeviceEvent, }, EventEncryptionAlgorithm, }, @@ -624,77 +629,80 @@ macro_rules! cryptostore_integration_tests { async fn withheld_info_storage() { let (account, store) = get_loaded_store("withheld_info_storage").await; - let mut info_list: Vec = Vec::new(); + let mut info_list: BTreeMap<_, BTreeMap<_, _>> = BTreeMap::new(); + let user_id = account.user_id().to_owned(); let room_id = room_id!("!DwLygpkclUAfQNnfva:example.com"); let session_id_1 = "GBnDxGP9i3IkPsz3/ihNr6P7qjIXxSRVWZ1MYmSn09w"; let session_id_2 = "IDLtnNCH2kIr3xIf1B7JFkGpQmTjyMca2jww+X6zeOE"; - let content = CommonWithheldCodeContent { - room_id: room_id.to_owned(), - session_id: session_id_1.into(), - from_device: JsOption::Undefined, - other: Default::default(), - sender_key: Curve25519PublicKey::from_base64( - "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA", - ) - .unwrap(), - }; - let info = DirectWithheldInfo::new( - EventEncryptionAlgorithm::MegolmV1AesSha2, - WithheldCode::Unverified, - content.to_owned(), + let content = RoomKeyWithheldContent::MegolmV1AesSha2( + MegolmV1AesSha2WithheldContent::Unverified( + CommonWithheldCodeContent { + room_id: room_id.to_owned(), + session_id: session_id_1.into(), + from_device: JsOption::Undefined, + other: Default::default(), + sender_key: Curve25519PublicKey::from_base64( + "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA", + ) + .unwrap(), + } + .into(), + ), ); - info_list.push(info); - - let content = CommonWithheldCodeContent { - room_id: room_id.to_owned(), - session_id: session_id_2.into(), - from_device: JsOption::Undefined, - other: Default::default(), - sender_key: Curve25519PublicKey::from_base64( - "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA", - ) - .unwrap(), - }; - - let info = DirectWithheldInfo::new( - EventEncryptionAlgorithm::MegolmV1AesSha2, - WithheldCode::Blacklisted, - content, + let event = ToDeviceEvent::new(user_id.to_owned(), content); + info_list + .entry(room_id.to_owned()) + .or_default() + .insert(session_id_1.to_owned(), event); + + let content = RoomKeyWithheldContent::MegolmV1AesSha2( + MegolmV1AesSha2WithheldContent::BlackListed( + CommonWithheldCodeContent { + room_id: room_id.to_owned(), + session_id: session_id_2.into(), + from_device: JsOption::Undefined, + other: Default::default(), + sender_key: Curve25519PublicKey::from_base64( + "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA", + ) + .unwrap(), + } + .into(), + ), ); - info_list.push(info); + let event = ToDeviceEvent::new(user_id.to_owned(), content); + info_list + .entry(room_id.to_owned()) + .or_default() + .insert(session_id_2.to_owned(), event); let changes = Changes { withheld_session_info: info_list, ..Default::default() }; - store.save_changes(changes).await.unwrap(); let is_withheld = store.get_withheld_info(room_id, session_id_1).await.unwrap(); - if let Some(info) = is_withheld { - let actual_code = info.withheld_code(); - assert_eq!(EventEncryptionAlgorithm::MegolmV1AesSha2, info.algorithm()); - assert_eq!(room_id, info.room_id()); - assert_eq!(WithheldCode::Unverified, actual_code); - } else { - panic!(); - } + assert_matches!( + is_withheld, Some(event) + if event.content.algorithm() == EventEncryptionAlgorithm::MegolmV1AesSha2 && + event.content.withheld_code() == WithheldCode::Unverified + ); let is_withheld = store.get_withheld_info(room_id, session_id_2).await.unwrap(); - if let Some(info) = is_withheld { - let actual_code = info.withheld_code(); - assert_eq!(WithheldCode::Blacklisted, actual_code); - } else { - panic!(); - } + assert_matches!( + is_withheld, Some(event) + if event.content.algorithm() == EventEncryptionAlgorithm::MegolmV1AesSha2 && + event.content.withheld_code() == WithheldCode::Blacklisted + ); let other_room_id = room_id!("!nQRyiRFuyUhXeaQfiR:example.com"); let is_withheld = store.get_withheld_info(other_room_id, session_id_2).await.unwrap(); - assert_eq!(is_withheld, None); + assert!(is_withheld.is_none()); } #[async_test] diff --git a/crates/matrix-sdk-crypto/src/store/memorystore.rs b/crates/matrix-sdk-crypto/src/store/memorystore.rs index b4b56dd3db5..a5ac003b7b6 100644 --- a/crates/matrix-sdk-crypto/src/store/memorystore.rs +++ b/crates/matrix-sdk-crypto/src/store/memorystore.rs @@ -15,10 +15,11 @@ use std::{collections::HashMap, convert::Infallible, sync::Arc}; use async_trait::async_trait; -use dashmap::{mapref::entry::Entry, DashMap, DashSet}; +use dashmap::{DashMap, DashSet}; use matrix_sdk_common::locks::Mutex; use ruma::{ - DeviceId, OwnedDeviceId, OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UserId, + DeviceId, OwnedDeviceId, OwnedRoomId, OwnedTransactionId, OwnedUserId, RoomId, TransactionId, + UserId, }; use tracing::warn; @@ -31,7 +32,7 @@ use crate::{ gossiping::{GossipRequest, SecretInfo}, identities::{ReadOnlyDevice, ReadOnlyUserIdentities}, olm::{OutboundGroupSession, PrivateCrossSigningIdentity}, - store::withheld::DirectWithheldInfo, + types::events::room_key_withheld::RoomKeyWithheldEvent, TrackedUser, }; @@ -54,7 +55,7 @@ pub struct MemoryStore { identities: Arc>, outgoing_key_requests: Arc>, key_requests_by_info: Arc>, - direct_withheld_info: Arc>, + direct_withheld_info: Arc>>, } impl Default for MemoryStore { @@ -149,8 +150,13 @@ impl CryptoStore for MemoryStore { self.key_requests_by_info.insert(info_string, id); } - for info in changes.withheld_session_info { - self.direct_withheld_info.insert(info.session_id().to_owned(), info); + for (room_id, data) in changes.withheld_session_info { + for (session_id, event) in data { + self.direct_withheld_info + .entry(room_id.to_owned()) + .or_insert_with(DashMap::new) + .insert(session_id, event); + } } Ok(()) @@ -284,12 +290,11 @@ impl CryptoStore for MemoryStore { &self, room_id: &RoomId, session_id: &str, - ) -> Result> { + ) -> Result> { Ok(self .direct_withheld_info - .get(session_id) - .filter(|e| e.value().room_id() == room_id) - .map(|e| e.value().to_owned())) + .get(room_id) + .and_then(|e| e.value().get(session_id).map(|v| v.value().to_owned()))) } async fn get_room_settings(&self, _room_id: &RoomId) -> Result> { diff --git a/crates/matrix-sdk-crypto/src/store/mod.rs b/crates/matrix-sdk-crypto/src/store/mod.rs index cfe86f42875..4e6b30c91a3 100644 --- a/crates/matrix-sdk-crypto/src/store/mod.rs +++ b/crates/matrix-sdk-crypto/src/store/mod.rs @@ -39,7 +39,7 @@ //! [`CryptoStore`]: trait.Cryptostore.html use std::{ - collections::{HashMap, HashSet}, + collections::{BTreeMap, HashMap, HashSet}, fmt::Debug, ops::Deref, sync::{atomic::AtomicBool, Arc}, @@ -68,7 +68,7 @@ use crate::{ InboundGroupSession, OlmMessageHash, OutboundGroupSession, PrivateCrossSigningIdentity, ReadOnlyAccount, Session, }, - types::EventEncryptionAlgorithm, + types::{events::room_key_withheld::RoomKeyWithheldEvent, EventEncryptionAlgorithm}, utilities::encode, verification::VerificationMachine, CrossSigningStatus, @@ -83,7 +83,6 @@ mod traits; #[macro_use] #[allow(missing_docs)] pub mod integration_tests; -pub mod withheld; use caches::{SequenceNumber, UsersForKeyQuery}; pub use error::{CryptoStoreError, Result}; @@ -92,7 +91,6 @@ pub use memorystore::MemoryStore; pub use traits::{CryptoStore, DynCryptoStore, IntoCryptoStore}; pub use crate::gossiping::{GossipRequest, SecretInfo}; -use crate::store::withheld::DirectWithheldInfo; /// A wrapper for our CryptoStore trait object. /// @@ -137,7 +135,7 @@ pub struct Changes { pub identities: IdentityChanges, pub devices: DeviceChanges, /// Stores when a `m.room_key.withheld` is received - pub withheld_session_info: Vec, + pub withheld_session_info: BTreeMap>, pub room_settings: HashMap, } diff --git a/crates/matrix-sdk-crypto/src/store/traits.rs b/crates/matrix-sdk-crypto/src/store/traits.rs index f2f8eb60853..b9ef2953c11 100644 --- a/crates/matrix-sdk-crypto/src/store/traits.rs +++ b/crates/matrix-sdk-crypto/src/store/traits.rs @@ -17,7 +17,6 @@ use std::{collections::HashMap, fmt, sync::Arc}; use async_trait::async_trait; use matrix_sdk_common::{locks::Mutex, AsyncTraitDeps}; use ruma::{DeviceId, OwnedDeviceId, RoomId, TransactionId, UserId}; -use vodozemac::Curve25519PublicKey; use super::{BackupKeys, Changes, CryptoStoreError, Result, RoomKeyCounts, RoomSettings}; use crate::{ @@ -25,7 +24,7 @@ use crate::{ InboundGroupSession, OlmMessageHash, OutboundGroupSession, PrivateCrossSigningIdentity, Session, }, - store::withheld::DirectWithheldInfo, + types::events::room_key_withheld::RoomKeyWithheldEvent, GossipRequest, ReadOnlyAccount, ReadOnlyDevice, ReadOnlyUserIdentities, SecretInfo, TrackedUser, }; @@ -91,7 +90,7 @@ pub trait CryptoStore: AsyncTraitDeps { &self, room_id: &RoomId, session_id: &str, - ) -> Result, Self::Error>; + ) -> Result, Self::Error>; /// Get all the inbound group sessions we have stored. async fn get_inbound_group_sessions(&self) -> Result, Self::Error>; @@ -357,7 +356,7 @@ impl CryptoStore for EraseCryptoStoreError { &self, room_id: &RoomId, session_id: &str, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { self.0.get_withheld_info(room_id, session_id).await.map_err(Into::into) } diff --git a/crates/matrix-sdk-crypto/src/store/withheld.rs b/crates/matrix-sdk-crypto/src/store/withheld.rs deleted file mode 100644 index 0f01654390f..00000000000 --- a/crates/matrix-sdk-crypto/src/store/withheld.rs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2023 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. - -//! When an encrypted message is sent in a room, the group key might not be sent -//! to all devices present in the room. Sometimes this may be inadvertent (for -//! example, if the sending device is not aware of some devices that have -//! joined), but some times, this may be purposeful. - -use ruma::RoomId; -use serde::{Deserialize, Serialize}; - -use crate::types::{ - events::room_key_withheld::{ - CommonWithheldCodeContent, MegolmV1AesSha2WithheldContent, RoomKeyWithheldContent, - RoomKeyWithheldEvent, WithheldCode, - }, - EventEncryptionAlgorithm, -}; - -/// We want to store when the owner of the group session sent us a withheld -/// code. It's not storing withheld code that can be sent in a -/// `m.forwarded_room_key`, it's another sort of relation as the same key can be -/// withheld for several reasons by different devices. -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -pub enum DirectWithheldInfo { - MegolmV1(MegolmV1WithheldInfo), - #[cfg(feature = "experimental-algorithms")] - MegolmV2(MegolmV2WithheldInfo), -} - -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -pub enum MegolmV1WithheldInfo { - BlackListed(Box), - Unverified(Box), -} - -#[cfg(feature = "experimental-algorithms")] -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -pub enum MegolmV2WithheldInfo { - BlackListed(Box), - Unverified(Box), -} - -impl DirectWithheldInfo { - pub fn new( - algorithm: EventEncryptionAlgorithm, - code: WithheldCode, - content: CommonWithheldCodeContent, - ) -> Self { - let content = content.into(); - - match algorithm { - EventEncryptionAlgorithm::MegolmV1AesSha2 => match code { - WithheldCode::Blacklisted => { - Self::MegolmV1(MegolmV1WithheldInfo::BlackListed(content)) - } - WithheldCode::Unverified => { - Self::MegolmV1(MegolmV1WithheldInfo::Unverified(content)) - } - _ => panic!("Unsupported direct withheld code"), - }, - #[cfg(feature = "experimental-algorithms")] - EventEncryptionAlgorithm::MegolmV1AesSha2 => match code { - WithheldCode::Blacklisted => { - Self::MegolmV2(MegolmV2WithheldInfo::BlackListed(content)) - } - WithheldCode::Unverified => { - Self::MegolmV2(MegolmV2WithheldInfo::Unverified(content)) - } - _ => panic!("Unsupported direct withheld code"), - }, - _ => todo!(), - } - } - - pub fn from_event(event: &RoomKeyWithheldEvent) -> Option { - match &event.content { - RoomKeyWithheldContent::MegolmV1AesSha2(c) => match c { - MegolmV1AesSha2WithheldContent::BlackListed(c) => { - Some(Self::MegolmV1(MegolmV1WithheldInfo::BlackListed(c.to_owned()))) - } - MegolmV1AesSha2WithheldContent::Unverified(c) => { - Some(Self::MegolmV1(MegolmV1WithheldInfo::Unverified(c.to_owned()))) - } - MegolmV1AesSha2WithheldContent::NoOlm(_) => todo!(), - _ => None, - }, - #[cfg(feature = "experimental-algorithms")] - RoomKeyWithheldContent::MegolmV2AesSha2(c) => match c { - MegolmV2AesSha2WithheldContent::BlackListed(_) => todo!(), - MegolmV2AesSha2WithheldContent::Unverified(_) => todo!(), - MegolmV2AesSha2WithheldContent::NoOlm(_) => todo!(), - }, - RoomKeyWithheldContent::Unknown(_) => None, - } - } - - pub fn algorithm(&self) -> EventEncryptionAlgorithm { - match self { - DirectWithheldInfo::MegolmV1(_) => EventEncryptionAlgorithm::MegolmV1AesSha2, - #[cfg(feature = "experimental-algorithms")] - DirectWithheldInfo::MegolmV2(_) => EventEncryptionAlgorithm::MegolmV2AesSha2, - } - } - - pub fn withheld_code(&self) -> WithheldCode { - match self { - DirectWithheldInfo::MegolmV1(c) => match c { - MegolmV1WithheldInfo::BlackListed(_) => WithheldCode::Blacklisted, - MegolmV1WithheldInfo::Unverified(_) => WithheldCode::Unverified, - }, - #[cfg(feature = "experimental-algorithms")] - DirectWithheldInfo::MegolmV2(c) => match c { - MegolmV2WithheldInfo::BlackListed(_) => WithheldCode::Blacklisted, - MegolmV2WithheldInfo::Unverified(_) => WithheldCode::Unverified, - }, - } - } - - pub fn room_id(&self) -> &RoomId { - match self { - DirectWithheldInfo::MegolmV1(c) => match c { - MegolmV1WithheldInfo::BlackListed(c) | MegolmV1WithheldInfo::Unverified(c) => { - &c.room_id - } - }, - #[cfg(feature = "experimental-algorithms")] - DirectWithheldInfo::MegolmV2(c) => match c { - MegolmV2WithheldInfo::BlackListed(c) | MegolmV2WithheldInfo::Unverified(c) => { - &c.room_id - } - }, - } - } - - pub fn session_id(&self) -> &str { - match self { - DirectWithheldInfo::MegolmV1(c) => match c { - MegolmV1WithheldInfo::BlackListed(c) | MegolmV1WithheldInfo::Unverified(c) => { - &c.session_id - } - }, - #[cfg(feature = "experimental-algorithms")] - DirectWithheldInfo::MegolmV2(c) => match c { - MegolmV2WithheldInfo::BlackListed(c) | MegolmV2WithheldInfo::Unverified(c) => { - &c.session_id - } - }, - } - } -} 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 20ed4bdd475..3f79dd1b48a 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 @@ -33,6 +33,16 @@ use crate::types::{ /// The `m.room_key_request` to-device event. pub type RoomKeyWithheldEvent = ToDeviceEvent; +impl Clone for RoomKeyWithheldEvent { + fn clone(&self) -> Self { + Self { + sender: self.sender.clone(), + content: self.content.clone(), + other: self.other.clone(), + } + } +} + /// The `m.room_key.withheld` event content. /// /// This is an enum over the different room key algorithms we support. @@ -120,6 +130,15 @@ impl RoomKeyWithheldContent { } } + pub fn withheld_code(&self) -> WithheldCode { + match self { + RoomKeyWithheldContent::MegolmV1AesSha2(c) => c.withheld_code(), + #[cfg(feature = "experimental-algorithms")] + RoomKeyWithheldContent::MegolmV2AesSha2(c) => c.withheld_code(), + RoomKeyWithheldContent::Unknown(c) => c.code.to_owned(), + } + } + /// Get the algorithm of the room key withheld. pub fn algorithm(&self) -> EventEncryptionAlgorithm { match &self { diff --git a/crates/matrix-sdk-indexeddb/Cargo.toml b/crates/matrix-sdk-indexeddb/Cargo.toml index 84247d624e6..a98ff6d0eb4 100644 --- a/crates/matrix-sdk-indexeddb/Cargo.toml +++ b/crates/matrix-sdk-indexeddb/Cargo.toml @@ -41,7 +41,7 @@ web-sys = { version = "0.3.57", features = ["IdbKeyRange"] } getrandom = { version = "0.2.6", features = ["js"] } [dev-dependencies] -assert_matches = "1.5.0" +assert_matches = { workspace = true } matrix-sdk-base = { path = "../matrix-sdk-base", features = ["testing"] } matrix-sdk-common = { path = "../matrix-sdk-common", features = ["js"] } matrix-sdk-crypto = { path = "../matrix-sdk-crypto", features = ["js", "testing"] } diff --git a/crates/matrix-sdk-indexeddb/src/crypto_store.rs b/crates/matrix-sdk-indexeddb/src/crypto_store.rs index e85fec54dc1..4fd888c2ab6 100644 --- a/crates/matrix-sdk-indexeddb/src/crypto_store.rs +++ b/crates/matrix-sdk-indexeddb/src/crypto_store.rs @@ -27,9 +27,10 @@ use matrix_sdk_crypto::{ PrivateCrossSigningIdentity, Session, }, store::{ - caches::SessionStore, withheld::DirectWithheldInfo, BackupKeys, Changes, CryptoStore, - CryptoStoreError, RoomKeyCounts, RoomSettings, + caches::SessionStore, BackupKeys, Changes, CryptoStore, CryptoStoreError, RoomKeyCounts, + RoomSettings, }, + types::events::room_key_withheld::RoomKeyWithheldEvent, GossipRequest, ReadOnlyAccount, ReadOnlyDevice, ReadOnlyUserIdentities, SecretInfo, TrackedUser, }; @@ -569,12 +570,12 @@ impl_crypto_store! { if !withheld_session_info.is_empty() { let withhelds = tx.object_store(keys::DIRECT_WITHHELD_INFO)?; - for info in withheld_session_info { - let room_id = info.room_id(); - let session_id = info.session_id(); + for (room_id, data) in withheld_session_info { + for (session_id, event) in data { - let key = self.encode_key(keys::DIRECT_WITHHELD_INFO, (session_id, room_id)); - withhelds.put_key_val(&key, &self.serialize_value(&info)?)?; + let key = self.encode_key(keys::DIRECT_WITHHELD_INFO, (session_id, &room_id)); + withhelds.put_key_val(&key, &self.serialize_value(&event)?)?; + } } } @@ -1005,7 +1006,7 @@ impl_crypto_store! { &self, room_id: &RoomId, session_id: &str, - ) -> Result> { + ) -> Result> { let key = self.encode_key(keys::DIRECT_WITHHELD_INFO, (session_id, room_id)); if let Some(pickle) = self .inner diff --git a/crates/matrix-sdk-sled/Cargo.toml b/crates/matrix-sdk-sled/Cargo.toml index 67f0d2b40e1..ae07c01b7cb 100644 --- a/crates/matrix-sdk-sled/Cargo.toml +++ b/crates/matrix-sdk-sled/Cargo.toml @@ -43,6 +43,7 @@ tokio = { version = "1.24.2", default-features = false, features = ["sync", "fs" tracing = { workspace = true } [dev-dependencies] +assert_matches = { workspace = true } glob = "0.3.0" matrix-sdk-base = { path = "../matrix-sdk-base", features = ["testing"] } matrix-sdk-crypto = { path = "../matrix-sdk-crypto", features = ["testing"] } diff --git a/crates/matrix-sdk-sled/src/crypto_store.rs b/crates/matrix-sdk-sled/src/crypto_store.rs index 6a1320e7094..5636dc97473 100644 --- a/crates/matrix-sdk-sled/src/crypto_store.rs +++ b/crates/matrix-sdk-sled/src/crypto_store.rs @@ -27,10 +27,13 @@ use matrix_sdk_crypto::{ PrivateCrossSigningIdentity, Session, }, store::{ - caches::SessionStore, withheld::DirectWithheldInfo, BackupKeys, Changes, CryptoStore, - CryptoStoreError, Result, RoomKeyCounts, RoomSettings, + caches::SessionStore, BackupKeys, Changes, CryptoStore, CryptoStoreError, Result, + RoomKeyCounts, RoomSettings, + }, + types::{ + events::{room_key_request::SupportedKeyInfo, room_key_withheld::RoomKeyWithheldEvent}, + EventEncryptionAlgorithm, }, - types::{events::room_key_request::SupportedKeyInfo, EventEncryptionAlgorithm}, GossipRequest, ReadOnlyAccount, ReadOnlyDevice, ReadOnlyUserIdentities, SecretInfo, TrackedUser, }; @@ -670,17 +673,16 @@ impl SledCryptoStore { } } - for info in &changes.withheld_session_info { - let session_id = info.session_id(); - let room_id = info.room_id(); - - let key = - self.encode_key(DIRECT_WITHHELD_INFO_TABLE, (session_id, room_id)); - direct_withheld_info.insert( - key, - self.serialize_value(info) - .map_err(ConflictableTransactionError::Abort)?, - )?; + for (room_id, data) in &changes.withheld_session_info { + for (session_id, event) in data { + let key = + self.encode_key(DIRECT_WITHHELD_INFO_TABLE, (session_id, room_id)); + direct_withheld_info.insert( + key, + self.serialize_value(&event) + .map_err(ConflictableTransactionError::Abort)?, + )?; + } } for (room_id, settings) in &room_settings_changes { @@ -1076,13 +1078,13 @@ impl CryptoStore for SledCryptoStore { &self, room_id: &RoomId, session_id: &str, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { let key = self.encode_key(DIRECT_WITHHELD_INFO_TABLE, (session_id, room_id.as_str())); Ok(self .direct_withheld_info .get(key) .map_err(CryptoStoreError::backend)? - .map(|d| self.deserialize_value::(&d)) + .map(|d| self.deserialize_value::(&d)) .transpose()?) } diff --git a/crates/matrix-sdk-sqlite/Cargo.toml b/crates/matrix-sdk-sqlite/Cargo.toml index 576f5a9e338..6e2c06d9c1f 100644 --- a/crates/matrix-sdk-sqlite/Cargo.toml +++ b/crates/matrix-sdk-sqlite/Cargo.toml @@ -38,6 +38,7 @@ tracing = { workspace = true } vodozemac = { workspace = true } [dev-dependencies] +assert_matches = { workspace = true } ctor = { workspace = true } glob = "0.3.0" matrix-sdk-base = { path = "../matrix-sdk-base", features = ["testing"] } diff --git a/crates/matrix-sdk-sqlite/src/crypto_store.rs b/crates/matrix-sdk-sqlite/src/crypto_store.rs index d293069ed9b..9a738f36bdc 100644 --- a/crates/matrix-sdk-sqlite/src/crypto_store.rs +++ b/crates/matrix-sdk-sqlite/src/crypto_store.rs @@ -27,10 +27,8 @@ use matrix_sdk_crypto::{ IdentityKeys, InboundGroupSession, OutboundGroupSession, PickledInboundGroupSession, PrivateCrossSigningIdentity, Session, }, - store::{ - caches::SessionStore, withheld::DirectWithheldInfo, BackupKeys, Changes, CryptoStore, - RoomKeyCounts, RoomSettings, - }, + store::{caches::SessionStore, BackupKeys, Changes, CryptoStore, RoomKeyCounts, RoomSettings}, + types::events::room_key_withheld::RoomKeyWithheldEvent, GossipRequest, ReadOnlyAccount, ReadOnlyDevice, ReadOnlyUserIdentities, SecretInfo, TrackedUser, }; @@ -770,12 +768,13 @@ impl CryptoStore for SqliteCryptoStore { txn.set_key_request(&request_id, request.sent_out, &serialized_request)?; } - for info in changes.withheld_session_info { - let session_id = - this.encode_key("direct_withheld_info", info.session_id.as_bytes()); - let room_id = this.encode_key("direct_withheld_info", info.room_id.as_bytes()); - let serialized_info = this.serialize_value(&info)?; - txn.set_direct_withheld(&session_id, &room_id, &serialized_info)?; + for (room_id, data) in changes.withheld_session_info { + for (session_id, event) in data { + let session_id = this.encode_key("direct_withheld_info", session_id); + let room_id = this.encode_key("direct_withheld_info", room_id.to_owned()); + let serialized_info = this.serialize_value(&event)?; + txn.set_direct_withheld(&session_id, &room_id, &serialized_info)?; + } } for (room_id, settings) in changes.room_settings { @@ -1045,15 +1044,16 @@ impl CryptoStore for SqliteCryptoStore { &self, room_id: &RoomId, session_id: &str, - ) -> Result> { - let session_id = self.encode_key("direct_withheld_info", session_id.as_bytes()); - let room_id = self.encode_key("direct_withheld_info", room_id.as_str().as_bytes()); + ) -> Result> { + let room_id = self.encode_key("direct_withheld_info", room_id); + let session_id = self.encode_key("direct_withheld_info", session_id); + self.acquire() .await? .get_direct_withheld_info(session_id, room_id) .await? .map(|value| { - let info = self.deserialize_value::(&value)?; + let info = self.deserialize_value::(&value)?; Ok(info) }) .transpose() diff --git a/crates/matrix-sdk/Cargo.toml b/crates/matrix-sdk/Cargo.toml index 3281f1a9e0a..62f43920230 100644 --- a/crates/matrix-sdk/Cargo.toml +++ b/crates/matrix-sdk/Cargo.toml @@ -134,7 +134,7 @@ tokio = { version = "1.24.2", default-features = false, features = ["fs", "rt"] [dev-dependencies] anyhow = { workspace = true } -assert_matches = "1.5.0" +assert_matches = { workspace = true } dirs = "4.0.0" futures = { version = "0.3.21", default-features = false, features = ["executor"] } matrix-sdk-test = { version = "0.6.0", path = "../../testing/matrix-sdk-test" } diff --git a/testing/sliding-sync-integration-test/Cargo.toml b/testing/sliding-sync-integration-test/Cargo.toml index cecf2993db5..d016366eb00 100644 --- a/testing/sliding-sync-integration-test/Cargo.toml +++ b/testing/sliding-sync-integration-test/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dev-dependencies] anyhow = { workspace = true } -assert_matches = "1.5.0" +assert_matches = { workspace = true } eyeball = { workspace = true } eyeball-im = { workspace = true } futures = { version = "0.3.25" }