From 009ead2eeaf365e1fb0f790557f20d4eaf6874ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 8 Dec 2021 13:03:11 +0100 Subject: [PATCH] chore: Bump Ruma. --- crates/matrix-qrcode/Cargo.toml | 5 +- crates/matrix-sdk-appservice/Cargo.toml | 4 +- crates/matrix-sdk-base/Cargo.toml | 20 +- crates/matrix-sdk-base/src/client.rs | 11 +- crates/matrix-sdk-common/Cargo.toml | 17 +- crates/matrix-sdk-crypto/Cargo.toml | 9 +- crates/matrix-sdk-crypto/README.md | 4 +- crates/matrix-sdk-crypto/src/backups/mod.rs | 8 +- crates/matrix-sdk-crypto/src/error.rs | 2 + .../src/identities/manager.rs | 208 +++++++++++------- .../matrix-sdk-crypto/src/identities/user.rs | 22 +- crates/matrix-sdk-crypto/src/machine.rs | 36 ++- crates/matrix-sdk-crypto/src/olm/account.rs | 57 +++-- .../src/olm/group_sessions/inbound.rs | 2 +- crates/matrix-sdk-crypto/src/olm/session.rs | 6 + .../src/session_manager/group_sessions.rs | 3 +- .../src/session_manager/sessions.rs | 8 +- crates/matrix-sdk-crypto/src/store/mod.rs | 6 +- crates/matrix-sdk-test/Cargo.toml | 6 +- crates/matrix-sdk/Cargo.toml | 4 +- crates/matrix-sdk/src/encryption/mod.rs | 18 +- 21 files changed, 297 insertions(+), 159 deletions(-) diff --git a/crates/matrix-qrcode/Cargo.toml b/crates/matrix-qrcode/Cargo.toml index 8747634f4..4d7096ec7 100644 --- a/crates/matrix-qrcode/Cargo.toml +++ b/crates/matrix-qrcode/Cargo.toml @@ -27,5 +27,8 @@ byteorder = "1.4.3" image = { version = "0.23.14", optional = true } qrcode = { version = "0.12.0", default-features = false } rqrr = { version = "0.4.0", optional = true } -ruma-identifiers = { git = "https://github.com/ruma/ruma", rev = "6c4892664" } thiserror = "1.0.25" + +[dependencies.ruma-identifiers] +git = "https://github.com/ruma/ruma/" +rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d" diff --git a/crates/matrix-sdk-appservice/Cargo.toml b/crates/matrix-sdk-appservice/Cargo.toml index 4b0f5e461..0d6d0395e 100644 --- a/crates/matrix-sdk-appservice/Cargo.toml +++ b/crates/matrix-sdk-appservice/Cargo.toml @@ -37,8 +37,8 @@ url = "2" warp = { version = "0.3.1", optional = true, default-features = false } [dependencies.ruma] -git = "https://github.com/ruma/ruma" -rev = "6c4892664" +git = "https://github.com/ruma/ruma/" +rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d" features = ["client-api-c", "appservice-api-s", "unstable-pre-spec"] [dev-dependencies] diff --git a/crates/matrix-sdk-base/Cargo.toml b/crates/matrix-sdk-base/Cargo.toml index 31b1c049d..5890dfbf6 100644 --- a/crates/matrix-sdk-base/Cargo.toml +++ b/crates/matrix-sdk-base/Cargo.toml @@ -19,7 +19,14 @@ rustdoc-args = ["--cfg", "feature=\"docs\""] default = [] encryption = ["matrix-sdk-crypto"] qrcode = ["matrix-sdk-crypto/qrcode"] -sled_state_store = ["sled", "pbkdf2", "hmac", "sha2", "rand", "chacha20poly1305"] +sled_state_store = [ + "sled", + "pbkdf2", + "hmac", + "sha2", + "rand", + "chacha20poly1305", +] sled_cryptostore = ["matrix-sdk-crypto/sled_cryptostore"] docs = ["encryption", "sled_cryptostore"] @@ -35,7 +42,6 @@ matrix-sdk-common = { version = "0.4.0", path = "../matrix-sdk-common" } matrix-sdk-crypto = { version = "0.4.0", path = "../matrix-sdk-crypto", optional = true } pbkdf2 = { version = "0.9.0", default-features = false, optional = true } rand = { version = "0.8.4", optional = true } -ruma = { git = "https://github.com/ruma/ruma", rev = "6c4892664", features = ["client-api-c", "unstable-pre-spec"] } serde = { version = "1.0.126", features = ["rc"] } serde_json = "1.0.64" sha2 = { version = "0.9.5", optional = true } @@ -44,6 +50,11 @@ thiserror = "1.0.25" tracing = "0.1.26" zeroize = { version = "1.3.0", features = ["zeroize_derive"] } +[dependencies.ruma] +git = "https://github.com/ruma/ruma/" +rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d" +features = ["client-api-c", "unstable-pre-spec"] + [target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio] version = "1.7.1" default-features = false @@ -60,7 +71,10 @@ clap = "2.33.3" rustyline = "9.0.0" rustyline-derive = "0.5.0" syntect = "4.5.0" -tokio = { version = "1.7.1", default-features = false, features = ["rt-multi-thread", "macros"] } +tokio = { version = "1.7.1", default-features = false, features = [ + "rt-multi-thread", + "macros", +] } tempfile = "3.2.0" [target.'cfg(target_arch = "wasm32")'.dev-dependencies] diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index b05647a9c..f0998ebd8 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -650,6 +650,7 @@ impl BaseClient { &self, response: api::sync::sync_events::Response, ) -> Result { + #[allow(unused_variables)] let api::sync::sync_events::Response { next_batch, rooms, @@ -658,6 +659,7 @@ impl BaseClient { to_device, device_lists, device_one_time_keys_count, + device_unused_fallback_key_types, .. } = response; @@ -679,8 +681,13 @@ impl BaseClient { // decrypts to-device events, but leaves room events alone. // This makes sure that we have the decryption keys for the room // events at hand. - o.receive_sync_changes(to_device, &device_lists, &device_one_time_keys_count) - .await? + o.receive_sync_changes( + to_device, + &device_lists, + &device_one_time_keys_count, + device_unused_fallback_key_types.as_deref(), + ) + .await? } else { to_device } diff --git a/crates/matrix-sdk-common/Cargo.toml b/crates/matrix-sdk-common/Cargo.toml index 1dc72d607..7c4f857d4 100644 --- a/crates/matrix-sdk-common/Cargo.toml +++ b/crates/matrix-sdk-common/Cargo.toml @@ -13,11 +13,18 @@ version = "0.4.1" [dependencies] async-trait = "0.1.50" -ruma = { git = "https://github.com/ruma/ruma", rev = "6c4892664", features = ["client-api-c"] } serde = "1.0.126" +[dependencies.ruma] +git = "https://github.com/ruma/ruma/" +rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d" +features = ["client-api-c"] + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -uuid = { version = "0.8.2", default-features = false, features = ["v4", "serde"] } +uuid = { version = "0.8.2", default-features = false, features = [ + "v4", + "serde", +] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio] version = "1.7.1" @@ -36,4 +43,8 @@ features = ["now"] async-lock = "2.4.0" futures-util = { version = "0.3.15", default-features = false, features = ["channel"] } wasm-bindgen-futures = "0.4.24" -uuid = { version = "0.8.2", default-features = false, features = ["v4", "wasm-bindgen", "serde"] } +uuid = { version = "0.8.2", default-features = false, features = [ + "v4", + "wasm-bindgen", + "serde", +] } diff --git a/crates/matrix-sdk-crypto/Cargo.toml b/crates/matrix-sdk-crypto/Cargo.toml index dbb7c9923..1f1997f81 100644 --- a/crates/matrix-sdk-crypto/Cargo.toml +++ b/crates/matrix-sdk-crypto/Cargo.toml @@ -38,10 +38,6 @@ matrix-sdk-common = { version = "0.4.0", path = "../matrix-sdk-common" } olm-rs = { version = "2.1", features = ["serde"] } pbkdf2 = { version = "0.9.0", default-features = false } rand = "0.8.4" -ruma = { git = "https://github.com/ruma/ruma", rev = "6c4892664", features = [ - "client-api-c", - "unstable-pre-spec", -] } serde = { version = "1.0.126", features = ["derive", "rc"] } serde_json = "1.0.64" sha2 = "0.9.5" @@ -50,6 +46,11 @@ thiserror = "1.0.25" tracing = "0.1.26" zeroize = { version = "1.3.0", features = ["zeroize_derive"] } +[dependencies.ruma] +git = "https://github.com/ruma/ruma/" +rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d" +features = ["client-api-c", "unstable-pre-spec"] + [dev-dependencies] criterion = { version = "0.3.4", features = [ "async", diff --git a/crates/matrix-sdk-crypto/README.md b/crates/matrix-sdk-crypto/README.md index f48d9b8bf..d157d588b 100644 --- a/crates/matrix-sdk-crypto/README.md +++ b/crates/matrix-sdk-crypto/README.md @@ -33,12 +33,14 @@ async fn main() -> Result<(), OlmError> { let to_device_events = ToDevice::default(); let changed_devices = DeviceLists::default(); let one_time_key_counts = BTreeMap::default(); + let unused_fallback_keys = Some(Vec::new()); // Push changes that the server sent to us in a sync response. let decrypted_to_device = machine.receive_sync_changes( to_device_events, &changed_devices, - &one_time_key_counts + &one_time_key_counts, + unused_fallback_keys.as_deref(), ).await?; // Pull requests that we need to send out. diff --git a/crates/matrix-sdk-crypto/src/backups/mod.rs b/crates/matrix-sdk-crypto/src/backups/mod.rs index aa94bad28..1d32a3268 100644 --- a/crates/matrix-sdk-crypto/src/backups/mod.rs +++ b/crates/matrix-sdk-crypto/src/backups/mod.rs @@ -30,7 +30,8 @@ use std::{ use matrix_sdk_common::{locks::RwLock, uuid::Uuid}; use ruma::{ - api::client::r0::backup::RoomKeyBackup, DeviceKeyAlgorithm, DeviceKeyId, RoomId, UserId, + api::client::r0::backup::RoomKeyBackup, serde::Raw, DeviceKeyAlgorithm, DeviceKeyId, RoomId, + UserId, }; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -369,6 +370,11 @@ impl BackupMachine { .or_default() .insert(session_id.clone()); + let session = Raw::from_json( + serde_json::value::to_raw_value(&session) + .expect("Can't serialize a backed up room key"), + ); + backup .entry(room_id) .or_insert_with(|| RoomKeyBackup::new(BTreeMap::new())) diff --git a/crates/matrix-sdk-crypto/src/error.rs b/crates/matrix-sdk-crypto/src/error.rs index 3dba23a60..5b7029427 100644 --- a/crates/matrix-sdk-crypto/src/error.rs +++ b/crates/matrix-sdk-crypto/src/error.rs @@ -213,4 +213,6 @@ pub(crate) enum SessionCreationError { DeviceMissingCurveKey(Box, Box), #[error("Error creating new Olm session for {0} {1}: {2:?}")] OlmError(Box, Box, OlmSessionError), + #[error("Error deserializing the one-time key: {0}")] + InvalidJson(#[from] serde_json::Error), } diff --git a/crates/matrix-sdk-crypto/src/identities/manager.rs b/crates/matrix-sdk-crypto/src/identities/manager.rs index cb4336ae3..07886cbdc 100644 --- a/crates/matrix-sdk-crypto/src/identities/manager.rs +++ b/crates/matrix-sdk-crypto/src/identities/manager.rs @@ -23,7 +23,7 @@ use futures_util::future::join_all; use matrix_sdk_common::executor::spawn; use ruma::{ api::client::r0::keys::get_keys::Response as KeysQueryResponse, encryption::DeviceKeys, - DeviceId, UserId, + serde::Raw, DeviceId, UserId, }; use tracing::{debug, info, trace, warn}; @@ -205,7 +205,7 @@ impl IdentityManager { own_user_id: Arc, own_device_id: Arc, user_id: Box, - device_map: BTreeMap, DeviceKeys>, + device_map: BTreeMap, Raw>, ) -> StoreResult { let own_device_id = (&*own_device_id).to_owned(); @@ -213,18 +213,31 @@ impl IdentityManager { let current_devices: HashSet> = device_map.keys().cloned().collect(); - let tasks = device_map.into_iter().filter_map(|(device_id, device_keys)| { - if user_id != device_keys.user_id || device_id != device_keys.device_id { + let tasks = device_map.into_iter().filter_map(|(device_id, device_keys)| match device_keys + .deserialize() + { + Ok(device_keys) => { + if user_id != device_keys.user_id || device_id != device_keys.device_id { + warn!( + user_id = user_id.as_str(), + device_id = device_id.as_str(), + device_key_user = device_keys.user_id.as_str(), + device_key_device_id = device_keys.device_id.as_str(), + "Mismatch in the device keys payload", + ); + None + } else { + Some(spawn(Self::update_or_create_device(store.clone(), device_keys))) + } + } + Err(e) => { warn!( user_id = user_id.as_str(), device_id = device_id.as_str(), - device_key_user = device_keys.user_id.as_str(), - device_key_device_id = device_keys.device_id.as_str(), - "Mismatch in the device keys payload", + error =? e, + "Device keys failed to deserialize", ); None - } else { - Some(spawn(Self::update_or_create_device(store.clone(), device_keys))) } }); @@ -272,7 +285,7 @@ impl IdentityManager { /// they are new, one of their properties has changed or they got deleted. async fn handle_devices_from_key_query( &self, - device_keys_map: BTreeMap, BTreeMap, DeviceKeys>>, + device_keys_map: BTreeMap, BTreeMap, Raw>>, ) -> StoreResult { let mut changes = DeviceChanges::default(); @@ -312,93 +325,122 @@ impl IdentityManager { let mut changes = IdentityChanges::default(); let mut changed_identity = None; + // TODO this is a bit chunky, refactor this into smaller methods. + for (user_id, master_key) in &response.master_keys { - let master_key = MasterPubkey::from(master_key); + match master_key.deserialize() { + Ok(master_key) => { + let master_key = MasterPubkey::from(master_key); - let self_signing = if let Some(s) = response.self_signing_keys.get(user_id) { - SelfSigningPubkey::from(s) - } else { - warn!( - user_id = user_id.as_str(), - "A user identity didn't contain a self signing pubkey" - ); - continue; - }; + let self_signing = if let Some(s) = + response.self_signing_keys.get(user_id).and_then(|k| k.deserialize().ok()) + { + SelfSigningPubkey::from(s) + } else { + warn!( + user_id = user_id.as_str(), + "A user identity didn't contain a self signing pubkey \ + or the key was invalid" + ); + continue; + }; - let result = if let Some(mut i) = self.store.get_user_identity(user_id).await? { - match &mut i { - ReadOnlyUserIdentities::Own(ref mut identity) => { - let user_signing = if let Some(s) = response.user_signing_keys.get(user_id) + let result = if let Some(mut i) = self.store.get_user_identity(user_id).await? { + match &mut i { + ReadOnlyUserIdentities::Own(ref mut identity) => { + let user_signing = if let Some(s) = response + .user_signing_keys + .get(user_id) + .and_then(|k| k.deserialize().ok()) + { + UserSigningPubkey::from(s) + } else { + warn!( + user_id = user_id.as_str(), + "User identity for our own user didn't \ + contain a user signing pubkey", + ); + continue; + }; + + identity + .update(master_key, self_signing, user_signing) + .map(|_| (i, false)) + } + ReadOnlyUserIdentities::Other(ref mut identity) => { + identity.update(master_key, self_signing).map(|_| (i, false)) + } + } + } else if user_id == self.user_id() { + if let Some(s) = response + .user_signing_keys + .get(user_id) + .and_then(|k| k.deserialize().ok()) { - UserSigningPubkey::from(s) + let user_signing = UserSigningPubkey::from(s); + + if master_key.user_id() != user_id + || self_signing.user_id() != user_id + || user_signing.user_id() != user_id + { + warn!( + user_id = user_id.as_str(), + "User ID mismatch in one of the cross signing keys", + ); + continue; + } + + ReadOnlyOwnUserIdentity::new(master_key, self_signing, user_signing) + .map(|i| (ReadOnlyUserIdentities::Own(i), true)) } else { warn!( user_id = user_id.as_str(), - "User identity for our own user didn't \ - contain a user signing pubkey", + "User identity for our own user didn't contain a \ + user signing pubkey or the key isn't valid", ); continue; - }; - - identity.update(master_key, self_signing, user_signing).map(|_| (i, false)) - } - ReadOnlyUserIdentities::Other(ref mut identity) => { - identity.update(master_key, self_signing).map(|_| (i, false)) - } - } - } else if user_id == self.user_id() { - if let Some(s) = response.user_signing_keys.get(user_id) { - let user_signing = UserSigningPubkey::from(s); - - if master_key.user_id() != user_id - || self_signing.user_id() != user_id - || user_signing.user_id() != user_id - { + } + } else if master_key.user_id() != user_id || self_signing.user_id() != user_id { warn!( - user_id = user_id.as_str(), + user = user_id.as_str(), "User ID mismatch in one of the cross signing keys", ); continue; - } - - ReadOnlyOwnUserIdentity::new(master_key, self_signing, user_signing) - .map(|i| (ReadOnlyUserIdentities::Own(i), true)) - } else { - warn!( - user_id = user_id.as_str(), - "User identity for our own user didn't contain a \ - user signing pubkey", - ); - continue; - } - } else if master_key.user_id() != user_id || self_signing.user_id() != user_id { - warn!(user = user_id.as_str(), "User ID mismatch in one of the cross signing keys",); - continue; - } else { - ReadOnlyUserIdentity::new(master_key, self_signing) - .map(|i| (ReadOnlyUserIdentities::Other(i), true)) - }; - - match result { - Ok((i, new)) => { - if let Some(identity) = i.own() { - let private_identity = self.store.private_identity(); - let private_identity = private_identity.lock().await; - - let result = private_identity.clear_if_differs(identity).await; - - if result.any_cleared() { - changed_identity = Some((&*private_identity).clone()); - info!(cleared =? result, "Removed some or all of our private cross signing keys"); - } - } - - if new { - trace!(user_id = user_id.as_str(), identity =? i, "Created new user identity"); - changes.new.push(i); } else { - trace!(user_id = user_id.as_str(), identity =? i, "Updated a user identity"); - changes.changed.push(i); + ReadOnlyUserIdentity::new(master_key, self_signing) + .map(|i| (ReadOnlyUserIdentities::Other(i), true)) + }; + + match result { + Ok((i, new)) => { + if let Some(identity) = i.own() { + let private_identity = self.store.private_identity(); + let private_identity = private_identity.lock().await; + + let result = private_identity.clear_if_differs(identity).await; + + if result.any_cleared() { + changed_identity = Some((&*private_identity).clone()); + info!(cleared =? result, "Removed some or all of our private cross signing keys"); + } + } + + if new { + trace!(user_id = user_id.as_str(), identity =? i, "Created new user identity"); + changes.new.push(i); + } else { + trace!(user_id = user_id.as_str(), identity =? i, "Updated a user identity"); + changes.changed.push(i); + } + } + Err(e) => { + warn!( + user_id = user_id.as_str(), + error =? e, + "Couldn't update or create new user identity" + ); + continue; + } } } Err(e) => { diff --git a/crates/matrix-sdk-crypto/src/identities/user.rs b/crates/matrix-sdk-crypto/src/identities/user.rs index bc8fcce6a..cb7a10117 100644 --- a/crates/matrix-sdk-crypto/src/identities/user.rs +++ b/crates/matrix-sdk-crypto/src/identities/user.rs @@ -956,17 +956,19 @@ pub(crate) mod test { fn device(response: &KeyQueryResponse) -> (ReadOnlyDevice, ReadOnlyDevice) { let mut devices = response.device_keys.values().next().unwrap().values(); - let first = ReadOnlyDevice::try_from(devices.next().unwrap()).unwrap(); - let second = ReadOnlyDevice::try_from(devices.next().unwrap()).unwrap(); + let first = + ReadOnlyDevice::try_from(&devices.next().unwrap().deserialize().unwrap()).unwrap(); + let second = + ReadOnlyDevice::try_from(&devices.next().unwrap().deserialize().unwrap()).unwrap(); (first, second) } fn own_identity(response: &KeyQueryResponse) -> ReadOnlyOwnUserIdentity { let user_id = user_id!("@example:localhost"); - let master_key = response.master_keys.get(user_id).unwrap(); - let user_signing = response.user_signing_keys.get(user_id).unwrap(); - let self_signing = response.self_signing_keys.get(user_id).unwrap(); + let master_key = response.master_keys.get(user_id).unwrap().deserialize().unwrap(); + let user_signing = response.user_signing_keys.get(user_id).unwrap().deserialize().unwrap(); + let self_signing = response.self_signing_keys.get(user_id).unwrap().deserialize().unwrap(); ReadOnlyOwnUserIdentity::new(master_key.into(), self_signing.into(), user_signing.into()) .unwrap() @@ -980,8 +982,8 @@ pub(crate) mod test { let user_id = user_id!("@example2:localhost"); let response = other_key_query(); - let master_key = response.master_keys.get(user_id).unwrap(); - let self_signing = response.self_signing_keys.get(user_id).unwrap(); + let master_key = response.master_keys.get(user_id).unwrap().deserialize().unwrap(); + let self_signing = response.self_signing_keys.get(user_id).unwrap().deserialize().unwrap(); ReadOnlyUserIdentity::new(master_key.into(), self_signing.into()).unwrap() } @@ -991,9 +993,9 @@ pub(crate) mod test { let user_id = user_id!("@example:localhost"); let response = own_key_query(); - let master_key = response.master_keys.get(user_id).unwrap(); - let user_signing = response.user_signing_keys.get(user_id).unwrap(); - let self_signing = response.self_signing_keys.get(user_id).unwrap(); + let master_key = response.master_keys.get(user_id).unwrap().deserialize().unwrap(); + let user_signing = response.user_signing_keys.get(user_id).unwrap().deserialize().unwrap(); + let self_signing = response.self_signing_keys.get(user_id).unwrap().deserialize().unwrap(); ReadOnlyOwnUserIdentity::new(master_key.into(), self_signing.into(), user_signing.into()) .unwrap(); diff --git a/crates/matrix-sdk-crypto/src/machine.rs b/crates/matrix-sdk-crypto/src/machine.rs index f51ff4429..65054dd7c 100644 --- a/crates/matrix-sdk-crypto/src/machine.rs +++ b/crates/matrix-sdk-crypto/src/machine.rs @@ -46,9 +46,10 @@ use ruma::{ secret::request::SecretName, AnyMessageEventContent, AnyRoomEvent, AnyToDeviceEvent, EventContent, }, + serde::Raw, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId, UInt, UserId, }; -use serde_json::Value; +use serde_json::{value::to_raw_value, Value}; use tracing::{debug, error, info, trace, warn}; #[cfg(feature = "backups_v1")] @@ -562,7 +563,13 @@ impl OlmMachine { /// [`OlmMachine`]: struct.OlmMachine.html async fn keys_for_upload(&self) -> Option { let (device_keys, one_time_keys) = self.account.keys_for_upload().await?; - Some(assign!(upload_keys::Request::new(), { device_keys, one_time_keys })) + + let device_keys = device_keys + .map(|d| Raw::from_json(to_raw_value(&d).expect("Coulnd't serialize device keys"))); + + Some( + assign!(upload_keys::Request::new(), { device_keys, one_time_keys, fallback_keys: BTreeMap::new(), }), + ) } /// Decrypt a to-device event. @@ -859,8 +866,12 @@ impl OlmMachine { self.verification_machine.get_requests(user_id) } - fn update_one_time_key_count(&self, key_count: &BTreeMap) { - self.account.update_uploaded_key_count(key_count); + async fn update_key_counts( + &self, + one_time_key_count: &BTreeMap, + #[allow(unused_variables)] unused_fallback_keys: Option<&[DeviceKeyAlgorithm]>, + ) { + self.account.update_uploaded_key_count(one_time_key_count); } async fn handle_to_device_event(&self, event: &AnyToDeviceEvent) { @@ -913,6 +924,7 @@ impl OlmMachine { to_device_events: ToDevice, changed_devices: &DeviceLists, one_time_keys_counts: &BTreeMap, + unused_fallback_keys: Option<&[DeviceKeyAlgorithm]>, ) -> OlmResult { // Remove verification objects that have expired or are done. let mut events = self.verification_machine.garbage_collect(); @@ -922,7 +934,7 @@ impl OlmMachine { let mut changes = Changes { account: Some(self.account.inner.clone()), ..Default::default() }; - self.update_one_time_key_count(one_time_keys_counts); + self.update_key_counts(one_time_keys_counts, unused_fallback_keys).await; for user_id in &changed_devices.changed { if let Err(e) = self.identity_manager.mark_user_as_changed(user_id).await { @@ -1568,8 +1580,10 @@ pub(crate) mod test { AnyMessageEventContent, AnySyncMessageEvent, AnySyncRoomEvent, AnyToDeviceEvent, AnyToDeviceEventContent, SyncMessageEvent, ToDeviceEvent, Unsigned, }, - room_id, uint, user_id, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, - MilliSecondsSinceUnixEpoch, UserId, + room_id, + serde::Raw, + uint, user_id, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch, + UserId, }; use serde_json::json; @@ -1581,7 +1595,7 @@ pub(crate) mod test { }; /// These keys need to be periodically uploaded to the server. - type OneTimeKeys = BTreeMap, OneTimeKey>; + type OneTimeKeys = BTreeMap, Raw>; fn alice_id() -> &'static UserId { user_id!("@alice:example.org") @@ -1635,7 +1649,7 @@ pub(crate) mod test { let response = keys_upload_response(); machine.receive_keys_upload_response(&response).await.unwrap(); - (machine, request.one_time_keys.unwrap()) + (machine, request.one_time_keys) } async fn get_machine_after_query() -> (OlmMachine, OneTimeKeys) { @@ -1836,7 +1850,7 @@ pub(crate) mod test { &machine.user_id, &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()), ed25519_key, - &mut json!(&mut request.one_time_keys.as_mut().unwrap().values_mut().next()), + &mut json!(&mut request.one_time_keys.values_mut().next()), ); assert!(ret.is_ok()); @@ -1852,7 +1866,7 @@ pub(crate) mod test { let mut response = keys_upload_response(); response.one_time_key_counts.insert( DeviceKeyAlgorithm::SignedCurve25519, - (request.one_time_keys.unwrap().len() as u64).try_into().unwrap(), + (request.one_time_keys.len() as u64).try_into().unwrap(), ); machine.receive_keys_upload_response(&response).await.unwrap(); diff --git a/crates/matrix-sdk-crypto/src/olm/account.rs b/crates/matrix-sdk-crypto/src/olm/account.rs index 7949b8226..67af1d7f4 100644 --- a/crates/matrix-sdk-crypto/src/olm/account.rs +++ b/crates/matrix-sdk-crypto/src/olm/account.rs @@ -43,7 +43,11 @@ use ruma::{ DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId, UInt, UserId, }; use serde::{Deserialize, Serialize}; -use serde_json::{json, value::RawValue as RawJsonValue, Value}; +use serde_json::{ + json, + value::{to_raw_value, RawValue as RawJsonValue}, + Value, +}; use sha2::{Digest, Sha256}; use tracing::{debug, info, trace, warn}; @@ -661,14 +665,14 @@ impl ReadOnlyAccount { /// Returns None if no keys need to be uploaded. pub(crate) async fn keys_for_upload( &self, - ) -> Option<(Option, Option, OneTimeKey>>)> { + ) -> Option<(Option, BTreeMap, Raw>)> { if !self.should_upload_keys().await { return None; } let device_keys = if !self.shared() { Some(self.device_keys().await) } else { None }; - let one_time_keys = self.signed_one_time_keys().await.ok(); + let one_time_keys = self.signed_one_time_keys().await.ok().unwrap_or_default(); Some((device_keys, one_time_keys)) } @@ -845,15 +849,20 @@ impl ReadOnlyAccount { /// # Panic /// /// Panics if the json value can't be serialized. - pub async fn sign_json(&self, json: Value) -> String { + pub async fn sign_json(&self, mut json: Value) -> String { + let object = json.as_object_mut().expect("Canonical json value isn't an object"); + object.remove("unsigned"); + object.remove("signatures"); + let canonical_json: CanonicalJsonValue = json.try_into().expect("Can't canonicalize the json value"); + self.sign(&canonical_json.to_string()).await } pub(crate) async fn signed_one_time_keys_helper( &self, - ) -> Result, OneTimeKey>, ()> { + ) -> Result, Raw>, ()> { let one_time_keys = self.one_time_keys().await; let mut one_time_key_map = BTreeMap::new(); @@ -881,7 +890,10 @@ impl ReadOnlyAccount { DeviceKeyAlgorithm::SignedCurve25519, key_id.as_str().into(), ), - OneTimeKey::SignedKey(signed_key), + Raw::from_json( + to_raw_value(&OneTimeKey::SignedKey(signed_key)) + .expect("Couldn't serialize a new signed key"), + ), ); } @@ -893,7 +905,7 @@ impl ReadOnlyAccount { /// If no one-time keys need to be uploaded returns an empty error. pub(crate) async fn signed_one_time_keys( &self, - ) -> Result, OneTimeKey>, ()> { + ) -> Result, Raw>, ()> { let _ = self.generate_one_time_keys().await?; self.signed_one_time_keys_helper().await } @@ -929,6 +941,7 @@ impl ReadOnlyAccount { inner: Arc::new(Mutex::new(session)), session_id: session_id.into(), sender_key: their_identity_key.into(), + created_using_fallback_key: their_one_time_key.fallback, creation_time: Arc::new(now), last_use_time: Arc::new(now), }) @@ -948,7 +961,7 @@ impl ReadOnlyAccount { pub(crate) async fn create_outbound_session( &self, device: ReadOnlyDevice, - key_map: &BTreeMap, OneTimeKey>, + key_map: &BTreeMap, Raw>, ) -> Result { let one_time_key = key_map.values().next().ok_or_else(|| { SessionCreationError::OneTimeKeyMissing( @@ -957,23 +970,24 @@ impl ReadOnlyAccount { ) })?; - let one_time_key = match one_time_key { - OneTimeKey::SignedKey(k) => k, - OneTimeKey::Key(_) => { + let one_time_key: SignedKey = match one_time_key.deserialize() { + Ok(OneTimeKey::SignedKey(k)) => k, + Ok(OneTimeKey::Key(_)) => { return Err(SessionCreationError::OneTimeKeyNotSigned( device.user_id().to_owned(), device.device_id().into(), )); } - _ => { + Ok(_) => { return Err(SessionCreationError::OneTimeKeyUnknown( device.user_id().to_owned(), device.device_id().into(), )); } + Err(e) => return Err(SessionCreationError::InvalidJson(e)), }; - device.verify_one_time_key(one_time_key).map_err(|e| { + device.verify_one_time_key(&one_time_key).map_err(|e| { SessionCreationError::InvalidSignature( device.user_id().to_owned(), device.device_id().into(), @@ -988,7 +1002,7 @@ impl ReadOnlyAccount { ) })?; - self.create_outbound_session_helper(curve_key, one_time_key).await.map_err(|e| { + self.create_outbound_session_helper(curve_key, &one_time_key).await.map_err(|e| { SessionCreationError::OlmError( device.user_id().to_owned(), device.device_id().into(), @@ -1029,6 +1043,7 @@ impl ReadOnlyAccount { inner: Arc::new(Mutex::new(session)), session_id: session_id.into(), sender_key: their_identity_key.into(), + created_using_fallback_key: false, creation_time: Arc::new(now), last_use_time: Arc::new(now), }) @@ -1178,15 +1193,19 @@ mod test { let one_time_keys = account .keys_for_upload() .await - .and_then(|(_, k)| k) + .map(|(_, k)| k) .expect("Initial keys can't be generated"); + assert!(!one_time_keys.is_empty()); + let second_one_time_keys = account .keys_for_upload() .await - .and_then(|(_, k)| k) + .map(|(_, k)| k) .expect("Second round of one-time keys isn't generated"); + assert!(!second_one_time_keys.is_empty()); + let device_key_ids: BTreeSet<&DeviceKeyId> = one_time_keys.keys().map(Deref::deref).collect(); let second_device_key_ids: BTreeSet<&DeviceKeyId> = @@ -1197,16 +1216,16 @@ mod test { account.mark_keys_as_published().await; account.update_uploaded_key_count(50); - let third_one_time_keys = account.keys_for_upload().await.and_then(|(_, k)| k); + let third_one_time_keys = account.keys_for_upload().await.map(|(_, k)| k).unwrap(); - assert!(third_one_time_keys.is_none()); + assert!(third_one_time_keys.is_empty()); account.update_uploaded_key_count(0); let fourth_one_time_keys = account .keys_for_upload() .await - .and_then(|(_, k)| k) + .map(|(_, k)| k) .expect("Fourth round of one-time keys isn't generated"); let fourth_device_key_ids: BTreeSet<&DeviceKeyId> = diff --git a/crates/matrix-sdk-crypto/src/olm/group_sessions/inbound.rs b/crates/matrix-sdk-crypto/src/olm/group_sessions/inbound.rs index f966649b4..f7c00a680 100644 --- a/crates/matrix-sdk-crypto/src/olm/group_sessions/inbound.rs +++ b/crates/matrix-sdk-crypto/src/olm/group_sessions/inbound.rs @@ -379,7 +379,7 @@ impl InboundGroupSession { ); if let Some(decrypted_content) = - decrypted_object.get_mut("content").map(|c| c.as_object_mut()).flatten() + decrypted_object.get_mut("content").and_then(|c| c.as_object_mut()) { if !decrypted_content.contains_key("m.relates_to") { let content = serde_json::to_value(&event.content)?; diff --git a/crates/matrix-sdk-crypto/src/olm/session.rs b/crates/matrix-sdk-crypto/src/olm/session.rs index 9e3c563d2..d80d9b16e 100644 --- a/crates/matrix-sdk-crypto/src/olm/session.rs +++ b/crates/matrix-sdk-crypto/src/olm/session.rs @@ -49,6 +49,7 @@ pub struct Session { pub(crate) inner: Arc>, pub(crate) session_id: Arc, pub(crate) sender_key: Arc, + pub(crate) created_using_fallback_key: bool, pub(crate) creation_time: Arc, pub(crate) last_use_time: Arc, } @@ -183,6 +184,7 @@ impl Session { PickledSession { pickle: SessionPickle::from(pickle), sender_key: self.sender_key.to_string(), + created_using_fallback_key: self.created_using_fallback_key, creation_time: *self.creation_time, last_use_time: *self.last_use_time, } @@ -221,6 +223,7 @@ impl Session { our_identity_keys, inner: Arc::new(Mutex::new(session)), session_id: session_id.into(), + created_using_fallback_key: pickle.created_using_fallback_key, sender_key: pickle.sender_key.into(), creation_time: Arc::new(pickle.creation_time), last_use_time: Arc::new(pickle.last_use_time), @@ -244,6 +247,9 @@ pub struct PickledSession { pub pickle: SessionPickle, /// The curve25519 key of the other user that we share this session with. pub sender_key: String, + /// Was the session created using a fallback key. + #[serde(default)] + pub created_using_fallback_key: bool, /// The relative time elapsed since the session was created. #[serde(deserialize_with = "deserialize_instant", serialize_with = "serialize_instant")] pub creation_time: Instant, 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 2960be0ff..ef977bcbe 100644 --- a/crates/matrix-sdk-crypto/src/session_manager/group_sessions.rs +++ b/crates/matrix-sdk-crypto/src/session_manager/group_sessions.rs @@ -477,11 +477,10 @@ impl GroupSessionManager { let devices: Vec = devices .into_iter() - .map(|(_, d)| { + .flat_map(|(_, d)| { d.into_iter() .filter(|d| matches!(outbound.is_shared_with(d), ShareState::NotShared)) }) - .flatten() .collect(); let key_content = outbound.as_content().await; diff --git a/crates/matrix-sdk-crypto/src/session_manager/sessions.rs b/crates/matrix-sdk-crypto/src/session_manager/sessions.rs index cd3ad82a4..0579aa5fd 100644 --- a/crates/matrix-sdk-crypto/src/session_manager/sessions.rs +++ b/crates/matrix-sdk-crypto/src/session_manager/sessions.rs @@ -124,7 +124,7 @@ impl SessionManager { /// /// If the device was wedged this will queue up a dummy to-device message. async fn check_if_unwedged(&self, user_id: &UserId, device_id: &DeviceId) -> OlmResult<()> { - if self.wedged_devices.get(user_id).map(|d| d.remove(device_id)).flatten().is_some() { + if self.wedged_devices.get(user_id).and_then(|d| d.remove(device_id)).is_some() { if let Some(device) = self.store.get_device(user_id, device_id).await? { let content = AnyToDeviceEventContent::Dummy(ToDeviceDummyEventContent::new()); let (_, content) = device.encrypt(content).await?; @@ -298,9 +298,6 @@ impl SessionManager { } }; - changes.sessions.push(session); - new_sessions.entry(user_id).or_default().insert(device_id); - self.key_request_machine.retry_keyshare(user_id, device_id); if let Err(e) = self.check_if_unwedged(user_id, device_id).await { @@ -309,6 +306,9 @@ impl SessionManager { user_id, device_id, e ); } + + changes.sessions.push(session); + new_sessions.entry(user_id).or_default().insert(device_id); } } diff --git a/crates/matrix-sdk-crypto/src/store/mod.rs b/crates/matrix-sdk-crypto/src/store/mod.rs index 371ba4a11..963c8b1d5 100644 --- a/crates/matrix-sdk-crypto/src/store/mod.rs +++ b/crates/matrix-sdk-crypto/src/store/mod.rs @@ -347,8 +347,8 @@ impl Store { let devices = self.inner.get_user_devices(user_id).await?; let own_identity = - self.inner.get_user_identity(&self.user_id).await?.map(|i| i.own().cloned()).flatten(); - let device_owner_identity = self.inner.get_user_identity(user_id).await.ok().flatten(); + self.inner.get_user_identity(&self.user_id).await?.and_then(|i| i.own().cloned()); + let device_owner_identity = self.inner.get_user_identity(user_id).await?; Ok(UserDevices { inner: devices, @@ -364,7 +364,7 @@ impl Store { device_id: &DeviceId, ) -> Result> { let own_identity = - self.inner.get_user_identity(&self.user_id).await?.map(|i| i.own().cloned()).flatten(); + self.inner.get_user_identity(&self.user_id).await?.and_then(|i| i.own().cloned()); let device_owner_identity = self.inner.get_user_identity(user_id).await?; Ok(self.inner.get_device(user_id, device_id).await?.map(|d| Device { diff --git a/crates/matrix-sdk-test/Cargo.toml b/crates/matrix-sdk-test/Cargo.toml index 1d813a8fd..e3a43cbfe 100644 --- a/crates/matrix-sdk-test/Cargo.toml +++ b/crates/matrix-sdk-test/Cargo.toml @@ -18,6 +18,10 @@ appservice = [] http = "0.2.4" lazy_static = "1.4.0" matrix-sdk-test-macros = { version = "0.1.0", path = "../matrix-sdk-test-macros" } -ruma = { git = "https://github.com/ruma/ruma", rev = "6c4892664", features = ["client-api-c"] } serde = "1.0.126" serde_json = "1.0.64" + +[dependencies.ruma] +git = "https://github.com/ruma/ruma/" +rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d" +features = ["client-api-c"] diff --git a/crates/matrix-sdk/Cargo.toml b/crates/matrix-sdk/Cargo.toml index 04ab67689..db07da680 100644 --- a/crates/matrix-sdk/Cargo.toml +++ b/crates/matrix-sdk/Cargo.toml @@ -75,8 +75,8 @@ version = "0.11.3" default_features = false [dependencies.ruma] -git = "https://github.com/ruma/ruma" -rev = "6c4892664" +git = "https://github.com/ruma/ruma/" +rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d" features = ["client-api-c", "compat", "unstable-pre-spec"] [dependencies.tokio-stream] diff --git a/crates/matrix-sdk/src/encryption/mod.rs b/crates/matrix-sdk/src/encryption/mod.rs index cead36d1e..3507540da 100644 --- a/crates/matrix-sdk/src/encryption/mod.rs +++ b/crates/matrix-sdk/src/encryption/mod.rs @@ -526,15 +526,21 @@ impl Client { /// # anyhow::Result::<()>::Ok(()) }); #[cfg(feature = "encryption")] pub async fn bootstrap_cross_signing(&self, auth_data: Option>) -> Result<()> { + use serde_json::value::to_raw_value; + let olm = self.olm_machine().await.ok_or(Error::AuthenticationRequired)?; let (request, signature_request) = olm.bootstrap_cross_signing(false).await?; + let to_raw = |k| { + Raw::from_json(to_raw_value(&k).expect("Can't serialize newly created cross signing keys")) + }; + let request = assign!(UploadSigningKeysRequest::new(), { auth: auth_data, - master_key: request.master_key, - self_signing_key: request.self_signing_key, - user_signing_key: request.user_signing_key, + master_key: request.master_key.map(to_raw), + self_signing_key: request.self_signing_key.map(to_raw), + user_signing_key: request.user_signing_key.map(to_raw), }); self.send(request, None).await?; @@ -887,9 +893,9 @@ impl Client { request: &upload_keys::Request, ) -> Result { debug!( - "Uploading encryption keys device keys: {}, one-time-keys: {}", - request.device_keys.is_some(), - request.one_time_keys.as_ref().map_or(0, |k| k.len()) + device_keys = request.device_keys.is_some(), + one_time_key_count = request.one_time_keys.len(), + "Uploading public encryption keys", ); let response = self.send(request.clone(), None).await?;