From 9e83eaf2f5f073efcab718c427118e62a30d9958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 3 Feb 2021 16:01:58 +0100 Subject: [PATCH] crypto: Store the history visiblity with the outbound session --- matrix_sdk_base/src/client.rs | 19 +++++++------- matrix_sdk_base/src/rooms/mod.rs | 10 +++++++ matrix_sdk_base/src/rooms/stripped.rs | 11 +++++++- matrix_sdk_crypto/src/error.rs | 4 +++ .../src/olm/group_sessions/outbound.rs | 26 ++++++++++++++----- .../src/session_manager/group_sessions.rs | 20 ++++++++++---- 6 files changed, 69 insertions(+), 21 deletions(-) diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index 479608c1..0f24a8c6 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -54,8 +54,8 @@ use matrix_sdk_common::{ #[cfg(feature = "encryption")] use matrix_sdk_crypto::{ store::{CryptoStore, CryptoStoreError}, - Device, EncryptionSettings, IncomingResponse, OlmError, OlmMachine, OutgoingRequest, Sas, - ToDeviceRequest, UserDevices, + Device, EncryptionSettings, IncomingResponse, MegolmError, OlmError, OlmMachine, + OutgoingRequest, Sas, ToDeviceRequest, UserDevices, }; use tracing::{info, warn}; use zeroize::Zeroizing; @@ -1157,10 +1157,11 @@ impl BaseClient { match &*olm { Some(o) => { - let history_visiblity = self + let (history_visiblity, settings) = self .get_room(room_id) - .map(|r| r.history_visiblity()) - .unwrap_or(HistoryVisibility::Joined); + .map(|r| (r.history_visiblity(), r.encryption_settings())) + .unwrap_or((HistoryVisibility::Joined, None)); + let joined = self.store.get_joined_user_ids(room_id).await?; let invited = self.store.get_invited_user_ids(room_id).await?; @@ -1172,10 +1173,10 @@ impl BaseClient { joined.iter().chain(&invited) }; - Ok( - o.share_group_session(room_id, members, EncryptionSettings::default()) - .await?, - ) + let settings = settings.ok_or(MegolmError::EncryptionNotEnabled)?; + let settings = EncryptionSettings::new(settings, history_visiblity); + + Ok(o.share_group_session(room_id, members, settings).await?) } None => panic!("Olm machine wasn't started"), } diff --git a/matrix_sdk_base/src/rooms/mod.rs b/matrix_sdk_base/src/rooms/mod.rs index 200271a6..335139d0 100644 --- a/matrix_sdk_base/src/rooms/mod.rs +++ b/matrix_sdk_base/src/rooms/mod.rs @@ -89,6 +89,16 @@ impl RoomState { } } + /// Get the `m.room.encryption` content that enabled end to end encryption + /// in the room. + pub fn encryption_settings(&self) -> Option { + match self { + RoomState::Joined(r) => r.inner.encryption_settings(), + RoomState::Left(r) => r.inner.encryption_settings(), + RoomState::Invited(r) => r.inner.encryption_settings(), + } + } + /// Are the members for this room synced. pub fn are_members_synced(&self) -> bool { if let RoomState::Joined(r) = self { diff --git a/matrix_sdk_base/src/rooms/stripped.rs b/matrix_sdk_base/src/rooms/stripped.rs index ffcb6654..35ba4fc0 100644 --- a/matrix_sdk_base/src/rooms/stripped.rs +++ b/matrix_sdk_base/src/rooms/stripped.rs @@ -15,7 +15,10 @@ use std::sync::{Arc, Mutex as SyncMutex}; use matrix_sdk_common::{ - events::{room::history_visibility::HistoryVisibility, AnyStrippedStateEvent}, + events::{ + room::{encryption::EncryptionEventContent, history_visibility::HistoryVisibility}, + AnyStrippedStateEvent, + }, identifiers::{RoomId, UserId}, }; use serde::{Deserialize, Serialize}; @@ -96,6 +99,12 @@ impl StrippedRoom { self.inner.lock().unwrap().base_info.encryption.is_some() } + /// Get the `m.room.encryption` content that enabled end to end encryption + /// in the room. + pub fn encryption_settings(&self) -> Option { + self.inner.lock().unwrap().base_info.encryption.clone() + } + /// Get the history visiblity policy of this room. pub fn history_visibility(&self) -> HistoryVisibility { self.inner diff --git a/matrix_sdk_crypto/src/error.rs b/matrix_sdk_crypto/src/error.rs index 24d68f1c..b948eaf5 100644 --- a/matrix_sdk_crypto/src/error.rs +++ b/matrix_sdk_crypto/src/error.rs @@ -86,6 +86,10 @@ pub enum MegolmError { #[error("can't finish Olm group session operation {0}")] OlmGroupSession(#[from] OlmGroupSessionError), + /// The room where a group session should be shared is not encrypted. + #[error("The room where a group session should be shared is not encrypted")] + EncryptionNotEnabled, + /// The storage layer returned an error. #[error(transparent)] Store(#[from] CryptoStoreError), diff --git a/matrix_sdk_crypto/src/olm/group_sessions/outbound.rs b/matrix_sdk_crypto/src/olm/group_sessions/outbound.rs index 868cc41f..49aff184 100644 --- a/matrix_sdk_crypto/src/olm/group_sessions/outbound.rs +++ b/matrix_sdk_crypto/src/olm/group_sessions/outbound.rs @@ -17,6 +17,7 @@ use matrix_sdk_common::{ api::r0::to_device::DeviceIdOrAllDevices, events::room::{ encrypted::{MegolmV1AesSha2Content, MegolmV1AesSha2ContentInit}, + history_visibility::HistoryVisibility, message::Relation, }, uuid::Uuid, @@ -80,6 +81,8 @@ pub struct EncryptionSettings { pub rotation_period: Duration, /// How many messages should be sent before changing the session. pub rotation_period_msgs: u64, + /// The history visibilty of the room when the session was created. + pub history_visibility: HistoryVisibility, } impl Default for EncryptionSettings { @@ -88,12 +91,15 @@ impl Default for EncryptionSettings { algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2, rotation_period: ROTATION_PERIOD, rotation_period_msgs: ROTATION_MESSAGES, + history_visibility: HistoryVisibility::Shared, } } } -impl From<&EncryptionEventContent> for EncryptionSettings { - fn from(content: &EncryptionEventContent) -> Self { +impl EncryptionSettings { + /// Create new encryption settings using an `EncryptionEventContent` and a + /// history visiblity. + pub fn new(content: EncryptionEventContent, history_visibility: HistoryVisibility) -> Self { let rotation_period: Duration = content .rotation_period_ms .map_or(ROTATION_PERIOD, |r| Duration::from_millis(r.into())); @@ -102,12 +108,14 @@ impl From<&EncryptionEventContent> for EncryptionSettings { .map_or(ROTATION_MESSAGES, Into::into); Self { - algorithm: content.algorithm.clone(), + algorithm: content.algorithm, rotation_period, rotation_period_msgs, + history_visibility, } } } + /// Outbound group session. /// /// Outbound group sessions are used to exchange room messages between a group @@ -185,6 +193,11 @@ impl OutboundGroupSession { self.invalidated.store(true, Ordering::Relaxed) } + /// Get the encryption settings of this outbound session. + pub fn settings(&self) -> &EncryptionSettings { + &self.settings + } + /// Mark the request with the given request id as sent. /// /// This removes the request from the queue and marks the set of @@ -560,7 +573,8 @@ mod test { use std::time::Duration; use matrix_sdk_common::{ - events::room::encryption::EncryptionEventContent, identifiers::EventEncryptionAlgorithm, + events::room::{encryption::EncryptionEventContent, history_visibility::HistoryVisibility}, + identifiers::EventEncryptionAlgorithm, uint, }; @@ -569,7 +583,7 @@ mod test { #[test] fn encryption_settings_conversion() { let mut content = EncryptionEventContent::new(EventEncryptionAlgorithm::MegolmV1AesSha2); - let settings = EncryptionSettings::from(&content); + let settings = EncryptionSettings::new(content.clone(), HistoryVisibility::Joined); assert_eq!(settings.rotation_period, ROTATION_PERIOD); assert_eq!(settings.rotation_period_msgs, ROTATION_MESSAGES); @@ -577,7 +591,7 @@ mod test { content.rotation_period_ms = Some(uint!(3600)); content.rotation_period_msgs = Some(uint!(500)); - let settings = EncryptionSettings::from(&content); + let settings = EncryptionSettings::new(content, HistoryVisibility::Shared); assert_eq!(settings.rotation_period, Duration::from_millis(3600)); assert_eq!(settings.rotation_period_msgs, 500); diff --git a/matrix_sdk_crypto/src/session_manager/group_sessions.rs b/matrix_sdk_crypto/src/session_manager/group_sessions.rs index e1e3d4c2..9d9526da 100644 --- a/matrix_sdk_crypto/src/session_manager/group_sessions.rs +++ b/matrix_sdk_crypto/src/session_manager/group_sessions.rs @@ -20,7 +20,10 @@ use std::{ use dashmap::DashMap; use matrix_sdk_common::{ api::r0::to_device::DeviceIdOrAllDevices, - events::{room::encrypted::EncryptedEventContent, AnyMessageEventContent, EventType}, + events::{ + room::{encrypted::EncryptedEventContent, history_visibility::HistoryVisibility}, + AnyMessageEventContent, EventType, + }, identifiers::{DeviceId, DeviceIdBox, RoomId, UserId}, uuid::Uuid, }; @@ -218,6 +221,7 @@ impl GroupSessionManager { pub async fn collect_session_recipients( &self, users: impl Iterator, + history_visibility: HistoryVisibility, outbound: &OutboundGroupSession, ) -> OlmResult<(bool, HashMap>)> { let users: HashSet<&UserId> = users.collect(); @@ -238,6 +242,8 @@ impl GroupSessionManager { .collect::>() .is_empty(); + let visiblity_changed = outbound.settings().history_visibility != history_visibility; + let mut device_got_deleted_or_blacklisted = false; for user_id in users { @@ -245,7 +251,7 @@ impl GroupSessionManager { // If no device got deleted or blacklisted until now and no user // left check if one got deleted or blacklisted for this user. - if !device_got_deleted_or_blacklisted && !user_left { + if !(device_got_deleted_or_blacklisted || user_left || visiblity_changed) { // Devices that should receive this session let device_ids: HashSet<&DeviceId> = user_devices .keys() @@ -287,8 +293,9 @@ impl GroupSessionManager { // To protect the room history we need to rotate the session if a user // left or if a device got deleted/blacklisted, put differently if - // someone leaves or gets removed from the encrypted group. - let should_rotate = user_left || device_got_deleted_or_blacklisted; + // someone leaves or gets removed from the encrypted group or if the + // history visiblity changed. + let should_rotate = user_left || device_got_deleted_or_blacklisted || visiblity_changed; Ok((should_rotate, devices)) } @@ -308,6 +315,7 @@ impl GroupSessionManager { encryption_settings: impl Into, ) -> OlmResult>> { let encryption_settings = encryption_settings.into(); + let history_visibility = encryption_settings.history_visibility.clone(); let mut changes = Changes::default(); let (outbound, inbound) = self @@ -319,7 +327,9 @@ impl GroupSessionManager { changes.inbound_group_sessions.push(inbound); } - let (should_rotate, devices) = self.collect_session_recipients(users, &outbound).await?; + let (should_rotate, devices) = self + .collect_session_recipients(users, history_visibility, &outbound) + .await?; let outbound = if should_rotate { let (outbound, inbound) = self