crypto: Simplify and test the group session invalidation logic.
parent
23ac00c8ec
commit
19d513e3c0
|
@ -21,7 +21,7 @@ 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, AnyMessageEventContent, EventType},
|
||||||
identifiers::{DeviceId, RoomId, UserId},
|
identifiers::{RoomId, UserId},
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
@ -70,15 +70,6 @@ impl GroupSessionManager {
|
||||||
pub fn invalidate_sessions_new_devices(&self, users: &HashSet<&UserId>) {
|
pub fn invalidate_sessions_new_devices(&self, users: &HashSet<&UserId>) {
|
||||||
for session in self.outbound_group_sessions.iter() {
|
for session in self.outbound_group_sessions.iter() {
|
||||||
if users.iter().any(|u| session.contains_recipient(u)) {
|
if users.iter().any(|u| session.contains_recipient(u)) {
|
||||||
session.invalidate_session()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invalidate the sessions that were sent to the given user/device pair.
|
|
||||||
pub fn invalidate_sessions(&self, user_id: &UserId, device_id: &DeviceId) {
|
|
||||||
for session in self.outbound_group_sessions.iter() {
|
|
||||||
if session.is_shared_with(user_id, device_id) {
|
|
||||||
session.invalidate_session();
|
session.invalidate_session();
|
||||||
|
|
||||||
if !session.shared() {
|
if !session.shared() {
|
||||||
|
|
|
@ -112,7 +112,7 @@ impl IdentityManager {
|
||||||
&self,
|
&self,
|
||||||
device_keys_map: &BTreeMap<UserId, BTreeMap<DeviceIdBox, DeviceKeys>>,
|
device_keys_map: &BTreeMap<UserId, BTreeMap<DeviceIdBox, DeviceKeys>>,
|
||||||
) -> StoreResult<Vec<ReadOnlyDevice>> {
|
) -> StoreResult<Vec<ReadOnlyDevice>> {
|
||||||
let mut users_with_new_devices = HashSet::new();
|
let mut users_with_new_or_deleted_devices = HashSet::new();
|
||||||
let mut changed_devices = Vec::new();
|
let mut changed_devices = Vec::new();
|
||||||
|
|
||||||
for (user_id, device_map) in device_keys_map {
|
for (user_id, device_map) in device_keys_map {
|
||||||
|
@ -158,7 +158,7 @@ impl IdentityManager {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
info!("Adding a new device to the device store {:?}", device);
|
info!("Adding a new device to the device store {:?}", device);
|
||||||
users_with_new_devices.insert(user_id);
|
users_with_new_or_deleted_devices.insert(user_id);
|
||||||
device
|
device
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -173,9 +173,8 @@ impl IdentityManager {
|
||||||
let deleted_devices = stored_devices_set.difference(¤t_devices);
|
let deleted_devices = stored_devices_set.difference(¤t_devices);
|
||||||
|
|
||||||
for device_id in deleted_devices {
|
for device_id in deleted_devices {
|
||||||
|
users_with_new_or_deleted_devices.insert(user_id);
|
||||||
if let Some(device) = stored_devices.get(device_id) {
|
if let Some(device) = stored_devices.get(device_id) {
|
||||||
self.group_manager
|
|
||||||
.invalidate_sessions(device.user_id(), device.device_id());
|
|
||||||
device.mark_as_deleted();
|
device.mark_as_deleted();
|
||||||
self.store.delete_device(device).await?;
|
self.store.delete_device(device).await?;
|
||||||
}
|
}
|
||||||
|
@ -183,7 +182,7 @@ impl IdentityManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.group_manager
|
self.group_manager
|
||||||
.invalidate_sessions_new_devices(&users_with_new_devices);
|
.invalidate_sessions_new_devices(&users_with_new_or_deleted_devices);
|
||||||
|
|
||||||
Ok(changed_devices)
|
Ok(changed_devices)
|
||||||
}
|
}
|
||||||
|
@ -369,7 +368,7 @@ pub(crate) mod test {
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::keys::get_keys::Response as KeyQueryResponse,
|
api::r0::keys::get_keys::Response as KeyQueryResponse,
|
||||||
identifiers::{user_id, DeviceIdBox, UserId},
|
identifiers::{room_id, user_id, DeviceIdBox, RoomId, UserId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use matrix_sdk_test::async_test;
|
use matrix_sdk_test::async_test;
|
||||||
|
@ -397,6 +396,10 @@ pub(crate) mod test {
|
||||||
"WSKKLTJZCL".into()
|
"WSKKLTJZCL".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn room_id() -> RoomId {
|
||||||
|
room_id!("!test:localhost")
|
||||||
|
}
|
||||||
|
|
||||||
fn manager() -> IdentityManager {
|
fn manager() -> IdentityManager {
|
||||||
let user_id = Arc::new(user_id());
|
let user_id = Arc::new(user_id());
|
||||||
let account = ReadOnlyAccount::new(&user_id, &device_id());
|
let account = ReadOnlyAccount::new(&user_id, &device_id());
|
||||||
|
@ -642,4 +645,78 @@ pub(crate) mod test {
|
||||||
|
|
||||||
assert!(identity.is_device_signed(&device).is_ok())
|
assert!(identity.is_device_signed(&device).is_ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_test]
|
||||||
|
async fn test_session_invalidation() {
|
||||||
|
let manager = manager();
|
||||||
|
let room_id = room_id();
|
||||||
|
let user_id = other_user_id();
|
||||||
|
let device_id: DeviceIdBox = "SKISMLNIMH".into();
|
||||||
|
|
||||||
|
manager
|
||||||
|
.group_manager
|
||||||
|
.create_outbound_group_session(&room_id, Default::default())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let session = manager
|
||||||
|
.group_manager
|
||||||
|
.get_outbound_group_session(&room_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
session.add_recipient(&user_id);
|
||||||
|
session.mark_as_shared();
|
||||||
|
|
||||||
|
assert!(!session.invalidated());
|
||||||
|
assert!(!session.expired());
|
||||||
|
|
||||||
|
// Receiving a new device invalidates the session.
|
||||||
|
manager
|
||||||
|
.receive_keys_query_response(&other_key_query())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(session.invalidated());
|
||||||
|
|
||||||
|
manager
|
||||||
|
.group_manager
|
||||||
|
.create_outbound_group_session(&room_id, Default::default())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let session = manager
|
||||||
|
.group_manager
|
||||||
|
.get_outbound_group_session(&room_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
session.add_recipient(&user_id);
|
||||||
|
session.mark_as_shared();
|
||||||
|
|
||||||
|
assert!(!session.invalidated());
|
||||||
|
assert!(!session.expired());
|
||||||
|
|
||||||
|
let device = manager
|
||||||
|
.store
|
||||||
|
.get_device(&user_id, &device_id)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(!device.deleted());
|
||||||
|
|
||||||
|
let response = KeyQueryResponse::try_from(response_from_file(&json!({
|
||||||
|
"device_keys": {
|
||||||
|
user_id: {}
|
||||||
|
},
|
||||||
|
"failures": {},
|
||||||
|
})))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Noticing that a device got deleted invalidates the session as well
|
||||||
|
manager
|
||||||
|
.receive_keys_query_response(&response)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(device.deleted());
|
||||||
|
assert!(session.invalidated());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue