diff --git a/matrix_sdk_crypto/src/key_request.rs b/matrix_sdk_crypto/src/key_request.rs index 8c53f551..69cdb4c2 100644 --- a/matrix_sdk_crypto/src/key_request.rs +++ b/matrix_sdk_crypto/src/key_request.rs @@ -87,7 +87,7 @@ impl Deref for Device { } /// An error describing why a key share request won't be honored. -#[derive(Debug, Clone, Error)] +#[derive(Debug, Clone, Error, PartialEq)] pub enum KeyshareDecision { /// The key request is from a device that we don't own, we're only sharing /// sessions that we know the requesting device already was supposed to get. @@ -582,11 +582,12 @@ mod test { use std::{convert::TryInto, sync::Arc}; use crate::{ + identities::{LocalTrust, ReadOnlyDevice}, olm::Account, store::{MemoryStore, Store}, }; - use super::KeyRequestMachine; + use super::{Device, KeyRequestMachine, KeyshareDecision}; fn alice_id() -> UserId { user_id!("@alice:example.org") @@ -596,6 +597,14 @@ mod test { "JLAFKJWSCS".into() } + fn bob_id() -> UserId { + user_id!("@bob:example.org") + } + + fn bob_device_id() -> DeviceIdBox { + "ILMLKASTES".into() + } + fn room_id() -> RoomId { room_id!("!test:example.org") } @@ -604,6 +613,10 @@ mod test { Account::new(&alice_id(), &alice_device_id()) } + fn bob_account() -> Account { + Account::new(&bob_id(), &bob_device_id()) + } + fn get_machine() -> KeyRequestMachine { let user_id = Arc::new(alice_id()); let store = Store::new(user_id.clone(), Box::new(MemoryStore::new())); @@ -785,4 +798,74 @@ mod test { assert_eq!(second_session.first_known_index().await, 0); } + + #[async_test] + async fn should_share_key_test() { + let machine = get_machine(); + let account = account(); + + let own_device = Device { + store: machine.store.clone(), + inner: ReadOnlyDevice::from_account(&account).await, + own_identity: None, + device_owner_identity: None, + }; + + // We don't share keys with untrusted devices. + assert_eq!( + machine + .should_share_session(&own_device, None) + .expect_err("Should not share with untrusted"), + KeyshareDecision::UntrustedDevice + ); + own_device.set_trust_state(LocalTrust::Verified); + // Now we do want to share the keys. + assert!(machine.should_share_session(&own_device, None).is_ok()); + + let bob_device = Device { + store: machine.store.clone(), + inner: ReadOnlyDevice::from_account(&bob_account()).await, + own_identity: None, + device_owner_identity: None, + }; + + // We don't share sessions with other user's devices if no outbound + // session was provided. + assert_eq!( + machine + .should_share_session(&bob_device, None) + .expect_err("Should not share with other."), + KeyshareDecision::MissingOutboundSession + ); + + let (session, _) = account + .create_group_session_pair_with_defaults(&room_id()) + .await + .unwrap(); + + // We don't share sessions with other user's devices if the session + // wasn't shared in the first place. + assert_eq!( + machine + .should_share_session(&bob_device, Some(&session)) + .expect_err("Should not share with other unless shared."), + KeyshareDecision::OutboundSessionNotShared + ); + + bob_device.set_trust_state(LocalTrust::Verified); + + // We don't share sessions with other user's devices if the session + // wasn't shared in the first place even if the device is trusted. + assert_eq!( + machine + .should_share_session(&bob_device, Some(&session)) + .expect_err("Should not share with other unless shared."), + KeyshareDecision::OutboundSessionNotShared + ); + + session.mark_shared_with(bob_device.user_id(), bob_device.device_id()); + assert!(machine + .should_share_session(&bob_device, Some(&session)) + .is_ok()); + } } diff --git a/matrix_sdk_crypto/src/olm/group_sessions/outbound.rs b/matrix_sdk_crypto/src/olm/group_sessions/outbound.rs index 78c900c2..64b1229b 100644 --- a/matrix_sdk_crypto/src/olm/group_sessions/outbound.rs +++ b/matrix_sdk_crypto/src/olm/group_sessions/outbound.rs @@ -28,7 +28,7 @@ use matrix_sdk_common::{ room::{encrypted::EncryptedEventContent, encryption::EncryptionEventContent}, AnyMessageEventContent, EventContent, }, - identifiers::{DeviceIdBox, EventEncryptionAlgorithm, RoomId, UserId}, + identifiers::{DeviceId, DeviceIdBox, EventEncryptionAlgorithm, RoomId, UserId}, instant::Instant, locks::Mutex, }; @@ -276,6 +276,13 @@ impl OutboundGroupSession { pub(crate) fn shared_with(&self) -> &DashSet<(UserId, DeviceIdBox)> { &self.shared_with_set } + + /// Mark that the session was shared with the given user/device pair. + #[allow(dead_code)] + pub fn mark_shared_with(&self, user_id: &UserId, device_id: &DeviceId) { + self.shared_with_set + .insert((user_id.to_owned(), device_id.to_owned())); + } } #[cfg(not(tarpaulin_include))]