crypto: Store the history visiblity with the outbound session
parent
347f79d08c
commit
9e83eaf2f5
|
@ -54,8 +54,8 @@ use matrix_sdk_common::{
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
use matrix_sdk_crypto::{
|
use matrix_sdk_crypto::{
|
||||||
store::{CryptoStore, CryptoStoreError},
|
store::{CryptoStore, CryptoStoreError},
|
||||||
Device, EncryptionSettings, IncomingResponse, OlmError, OlmMachine, OutgoingRequest, Sas,
|
Device, EncryptionSettings, IncomingResponse, MegolmError, OlmError, OlmMachine,
|
||||||
ToDeviceRequest, UserDevices,
|
OutgoingRequest, Sas, ToDeviceRequest, UserDevices,
|
||||||
};
|
};
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
@ -1157,10 +1157,11 @@ impl BaseClient {
|
||||||
|
|
||||||
match &*olm {
|
match &*olm {
|
||||||
Some(o) => {
|
Some(o) => {
|
||||||
let history_visiblity = self
|
let (history_visiblity, settings) = self
|
||||||
.get_room(room_id)
|
.get_room(room_id)
|
||||||
.map(|r| r.history_visiblity())
|
.map(|r| (r.history_visiblity(), r.encryption_settings()))
|
||||||
.unwrap_or(HistoryVisibility::Joined);
|
.unwrap_or((HistoryVisibility::Joined, None));
|
||||||
|
|
||||||
let joined = self.store.get_joined_user_ids(room_id).await?;
|
let joined = self.store.get_joined_user_ids(room_id).await?;
|
||||||
let invited = self.store.get_invited_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)
|
joined.iter().chain(&invited)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(
|
let settings = settings.ok_or(MegolmError::EncryptionNotEnabled)?;
|
||||||
o.share_group_session(room_id, members, EncryptionSettings::default())
|
let settings = EncryptionSettings::new(settings, history_visiblity);
|
||||||
.await?,
|
|
||||||
)
|
Ok(o.share_group_session(room_id, members, settings).await?)
|
||||||
}
|
}
|
||||||
None => panic!("Olm machine wasn't started"),
|
None => panic!("Olm machine wasn't started"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<EncryptionEventContent> {
|
||||||
|
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.
|
/// Are the members for this room synced.
|
||||||
pub fn are_members_synced(&self) -> bool {
|
pub fn are_members_synced(&self) -> bool {
|
||||||
if let RoomState::Joined(r) = self {
|
if let RoomState::Joined(r) = self {
|
||||||
|
|
|
@ -15,7 +15,10 @@
|
||||||
use std::sync::{Arc, Mutex as SyncMutex};
|
use std::sync::{Arc, Mutex as SyncMutex};
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
events::{room::history_visibility::HistoryVisibility, AnyStrippedStateEvent},
|
events::{
|
||||||
|
room::{encryption::EncryptionEventContent, history_visibility::HistoryVisibility},
|
||||||
|
AnyStrippedStateEvent,
|
||||||
|
},
|
||||||
identifiers::{RoomId, UserId},
|
identifiers::{RoomId, UserId},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -96,6 +99,12 @@ impl StrippedRoom {
|
||||||
self.inner.lock().unwrap().base_info.encryption.is_some()
|
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<EncryptionEventContent> {
|
||||||
|
self.inner.lock().unwrap().base_info.encryption.clone()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the history visiblity policy of this room.
|
/// Get the history visiblity policy of this room.
|
||||||
pub fn history_visibility(&self) -> HistoryVisibility {
|
pub fn history_visibility(&self) -> HistoryVisibility {
|
||||||
self.inner
|
self.inner
|
||||||
|
|
|
@ -86,6 +86,10 @@ pub enum MegolmError {
|
||||||
#[error("can't finish Olm group session operation {0}")]
|
#[error("can't finish Olm group session operation {0}")]
|
||||||
OlmGroupSession(#[from] OlmGroupSessionError),
|
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.
|
/// The storage layer returned an error.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Store(#[from] CryptoStoreError),
|
Store(#[from] CryptoStoreError),
|
||||||
|
|
|
@ -17,6 +17,7 @@ use matrix_sdk_common::{
|
||||||
api::r0::to_device::DeviceIdOrAllDevices,
|
api::r0::to_device::DeviceIdOrAllDevices,
|
||||||
events::room::{
|
events::room::{
|
||||||
encrypted::{MegolmV1AesSha2Content, MegolmV1AesSha2ContentInit},
|
encrypted::{MegolmV1AesSha2Content, MegolmV1AesSha2ContentInit},
|
||||||
|
history_visibility::HistoryVisibility,
|
||||||
message::Relation,
|
message::Relation,
|
||||||
},
|
},
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
|
@ -80,6 +81,8 @@ pub struct EncryptionSettings {
|
||||||
pub rotation_period: Duration,
|
pub rotation_period: Duration,
|
||||||
/// How many messages should be sent before changing the session.
|
/// How many messages should be sent before changing the session.
|
||||||
pub rotation_period_msgs: u64,
|
pub rotation_period_msgs: u64,
|
||||||
|
/// The history visibilty of the room when the session was created.
|
||||||
|
pub history_visibility: HistoryVisibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for EncryptionSettings {
|
impl Default for EncryptionSettings {
|
||||||
|
@ -88,12 +91,15 @@ impl Default for EncryptionSettings {
|
||||||
algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
|
algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
|
||||||
rotation_period: ROTATION_PERIOD,
|
rotation_period: ROTATION_PERIOD,
|
||||||
rotation_period_msgs: ROTATION_MESSAGES,
|
rotation_period_msgs: ROTATION_MESSAGES,
|
||||||
|
history_visibility: HistoryVisibility::Shared,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&EncryptionEventContent> for EncryptionSettings {
|
impl EncryptionSettings {
|
||||||
fn from(content: &EncryptionEventContent) -> Self {
|
/// 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
|
let rotation_period: Duration = content
|
||||||
.rotation_period_ms
|
.rotation_period_ms
|
||||||
.map_or(ROTATION_PERIOD, |r| Duration::from_millis(r.into()));
|
.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);
|
.map_or(ROTATION_MESSAGES, Into::into);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
algorithm: content.algorithm.clone(),
|
algorithm: content.algorithm,
|
||||||
rotation_period,
|
rotation_period,
|
||||||
rotation_period_msgs,
|
rotation_period_msgs,
|
||||||
|
history_visibility,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Outbound group session.
|
/// Outbound group session.
|
||||||
///
|
///
|
||||||
/// Outbound group sessions are used to exchange room messages between a group
|
/// Outbound group sessions are used to exchange room messages between a group
|
||||||
|
@ -185,6 +193,11 @@ impl OutboundGroupSession {
|
||||||
self.invalidated.store(true, Ordering::Relaxed)
|
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.
|
/// Mark the request with the given request id as sent.
|
||||||
///
|
///
|
||||||
/// This removes the request from the queue and marks the set of
|
/// This removes the request from the queue and marks the set of
|
||||||
|
@ -560,7 +573,8 @@ mod test {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
events::room::encryption::EncryptionEventContent, identifiers::EventEncryptionAlgorithm,
|
events::room::{encryption::EncryptionEventContent, history_visibility::HistoryVisibility},
|
||||||
|
identifiers::EventEncryptionAlgorithm,
|
||||||
uint,
|
uint,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -569,7 +583,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn encryption_settings_conversion() {
|
fn encryption_settings_conversion() {
|
||||||
let mut content = EncryptionEventContent::new(EventEncryptionAlgorithm::MegolmV1AesSha2);
|
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, ROTATION_PERIOD);
|
||||||
assert_eq!(settings.rotation_period_msgs, ROTATION_MESSAGES);
|
assert_eq!(settings.rotation_period_msgs, ROTATION_MESSAGES);
|
||||||
|
@ -577,7 +591,7 @@ mod test {
|
||||||
content.rotation_period_ms = Some(uint!(3600));
|
content.rotation_period_ms = Some(uint!(3600));
|
||||||
content.rotation_period_msgs = Some(uint!(500));
|
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, Duration::from_millis(3600));
|
||||||
assert_eq!(settings.rotation_period_msgs, 500);
|
assert_eq!(settings.rotation_period_msgs, 500);
|
||||||
|
|
|
@ -20,7 +20,10 @@ use std::{
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::to_device::DeviceIdOrAllDevices,
|
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},
|
identifiers::{DeviceId, DeviceIdBox, RoomId, UserId},
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
|
@ -218,6 +221,7 @@ impl GroupSessionManager {
|
||||||
pub async fn collect_session_recipients(
|
pub async fn collect_session_recipients(
|
||||||
&self,
|
&self,
|
||||||
users: impl Iterator<Item = &UserId>,
|
users: impl Iterator<Item = &UserId>,
|
||||||
|
history_visibility: HistoryVisibility,
|
||||||
outbound: &OutboundGroupSession,
|
outbound: &OutboundGroupSession,
|
||||||
) -> OlmResult<(bool, HashMap<UserId, Vec<Device>>)> {
|
) -> OlmResult<(bool, HashMap<UserId, Vec<Device>>)> {
|
||||||
let users: HashSet<&UserId> = users.collect();
|
let users: HashSet<&UserId> = users.collect();
|
||||||
|
@ -238,6 +242,8 @@ impl GroupSessionManager {
|
||||||
.collect::<HashSet<_>>()
|
.collect::<HashSet<_>>()
|
||||||
.is_empty();
|
.is_empty();
|
||||||
|
|
||||||
|
let visiblity_changed = outbound.settings().history_visibility != history_visibility;
|
||||||
|
|
||||||
let mut device_got_deleted_or_blacklisted = false;
|
let mut device_got_deleted_or_blacklisted = false;
|
||||||
|
|
||||||
for user_id in users {
|
for user_id in users {
|
||||||
|
@ -245,7 +251,7 @@ impl GroupSessionManager {
|
||||||
|
|
||||||
// If no device got deleted or blacklisted until now and no user
|
// If no device got deleted or blacklisted until now and no user
|
||||||
// left check if one got deleted or blacklisted for this 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
|
// Devices that should receive this session
|
||||||
let device_ids: HashSet<&DeviceId> = user_devices
|
let device_ids: HashSet<&DeviceId> = user_devices
|
||||||
.keys()
|
.keys()
|
||||||
|
@ -287,8 +293,9 @@ impl GroupSessionManager {
|
||||||
|
|
||||||
// To protect the room history we need to rotate the session if a user
|
// 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
|
// left or if a device got deleted/blacklisted, put differently if
|
||||||
// someone leaves or gets removed from the encrypted group.
|
// someone leaves or gets removed from the encrypted group or if the
|
||||||
let should_rotate = user_left || device_got_deleted_or_blacklisted;
|
// history visiblity changed.
|
||||||
|
let should_rotate = user_left || device_got_deleted_or_blacklisted || visiblity_changed;
|
||||||
|
|
||||||
Ok((should_rotate, devices))
|
Ok((should_rotate, devices))
|
||||||
}
|
}
|
||||||
|
@ -308,6 +315,7 @@ impl GroupSessionManager {
|
||||||
encryption_settings: impl Into<EncryptionSettings>,
|
encryption_settings: impl Into<EncryptionSettings>,
|
||||||
) -> OlmResult<Vec<Arc<ToDeviceRequest>>> {
|
) -> OlmResult<Vec<Arc<ToDeviceRequest>>> {
|
||||||
let encryption_settings = encryption_settings.into();
|
let encryption_settings = encryption_settings.into();
|
||||||
|
let history_visibility = encryption_settings.history_visibility.clone();
|
||||||
let mut changes = Changes::default();
|
let mut changes = Changes::default();
|
||||||
|
|
||||||
let (outbound, inbound) = self
|
let (outbound, inbound) = self
|
||||||
|
@ -319,7 +327,9 @@ impl GroupSessionManager {
|
||||||
changes.inbound_group_sessions.push(inbound);
|
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 = if should_rotate {
|
||||||
let (outbound, inbound) = self
|
let (outbound, inbound) = self
|
||||||
|
|
Loading…
Reference in New Issue