crypto: Store the history visiblity with the outbound session
parent
347f79d08c
commit
9e83eaf2f5
|
@ -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"),
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
pub fn are_members_synced(&self) -> bool {
|
||||
if let RoomState::Joined(r) = self {
|
||||
|
|
|
@ -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<EncryptionEventContent> {
|
||||
self.inner.lock().unwrap().base_info.encryption.clone()
|
||||
}
|
||||
|
||||
/// Get the history visiblity policy of this room.
|
||||
pub fn history_visibility(&self) -> HistoryVisibility {
|
||||
self.inner
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Item = &UserId>,
|
||||
history_visibility: HistoryVisibility,
|
||||
outbound: &OutboundGroupSession,
|
||||
) -> OlmResult<(bool, HashMap<UserId, Vec<Device>>)> {
|
||||
let users: HashSet<&UserId> = users.collect();
|
||||
|
@ -238,6 +242,8 @@ impl GroupSessionManager {
|
|||
.collect::<HashSet<_>>()
|
||||
.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<EncryptionSettings>,
|
||||
) -> OlmResult<Vec<Arc<ToDeviceRequest>>> {
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue