crypto: Store the history visiblity with the outbound session

This commit is contained in:
Damir Jelić 2021-02-03 16:01:58 +01:00
parent 347f79d08c
commit 9e83eaf2f5
6 changed files with 69 additions and 21 deletions

View file

@ -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"),
}

View file

@ -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 {

View file

@ -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

View file

@ -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),

View file

@ -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);

View file

@ -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