crypto: Remove the third Device variant.

master
Damir Jelić 2020-10-01 12:15:13 +02:00
parent c8ca93c924
commit 1d8f01ef11
6 changed files with 162 additions and 192 deletions

View File

@ -24,10 +24,9 @@ use matrix_sdk_common::{
use crate::{ use crate::{
error::{EventError, MegolmResult, OlmResult}, error::{EventError, MegolmResult, OlmResult},
key_request::Device,
olm::{Account, OutboundGroupSession}, olm::{Account, OutboundGroupSession},
store::{Result as StoreResult, Store}, store::Store,
EncryptionSettings, OlmError, ToDeviceRequest, Device, EncryptionSettings, OlmError, ToDeviceRequest,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -54,28 +53,6 @@ impl GroupSessionManager {
} }
} }
async fn get_user_devices(&self, user_id: &UserId) -> StoreResult<Vec<Device>> {
let devices = self.store.get_user_devices(user_id).await?;
let own_identity = self
.store
.get_user_identity(self.account.user_id())
.await?
.map(|i| i.own().cloned())
.flatten();
let device_owner_identity = self.store.get_user_identity(user_id).await.ok().flatten();
Ok(devices
.devices()
.map(|d| Device {
inner: d.clone(),
store: self.store.clone(),
own_identity: own_identity.clone(),
device_owner_identity: device_owner_identity.clone(),
})
.collect())
}
pub fn invalidate_group_session(&self, room_id: &RoomId) -> bool { pub fn invalidate_group_session(&self, room_id: &RoomId) -> bool {
self.outbound_group_sessions.remove(room_id).is_some() self.outbound_group_sessions.remove(room_id).is_some()
} }
@ -178,11 +155,16 @@ impl GroupSessionManager {
// caller mark them as sent using an UUID. // caller mark them as sent using an UUID.
session.mark_as_shared(); session.mark_as_shared();
let mut devices = Vec::new(); let mut devices: Vec<Device> = Vec::new();
for user_id in session.users_to_share_with() { for user_id in session.users_to_share_with() {
let mut user_devices = self.get_user_devices(&user_id).await?; let user_devices = self.store.get_user_devices(&user_id).await?;
devices.extend(user_devices.drain(..).filter(|d| !d.is_blacklisted())) devices.extend(
user_devices
.devices()
.map(|d| d.clone())
.filter(|d| !d.is_blacklisted()),
)
} }
let mut requests = Vec::new(); let mut requests = Vec::new();

View File

@ -14,7 +14,7 @@
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
convert::TryFrom, convert::{TryFrom, TryInto},
ops::Deref, ops::Deref,
sync::{ sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
@ -26,13 +26,17 @@ use atomic::Atomic;
use matrix_sdk_common::{ use matrix_sdk_common::{
api::r0::keys::SignedKey, api::r0::keys::SignedKey,
encryption::DeviceKeys, encryption::DeviceKeys,
events::{room::encrypted::EncryptedEventContent, EventType}, events::{
forwarded_room_key::ForwardedRoomKeyEventContent, room::encrypted::EncryptedEventContent,
EventType,
},
identifiers::{DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, UserId}, identifiers::{DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, UserId},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{json, Value}; use serde_json::{json, Value};
use tracing::warn; use tracing::warn;
use crate::olm::InboundGroupSession;
#[cfg(test)] #[cfg(test)]
use crate::{OlmMachine, ReadOnlyAccount}; use crate::{OlmMachine, ReadOnlyAccount};
@ -115,7 +119,6 @@ impl Device {
/// * `event_type` - The type of the event. /// * `event_type` - The type of the event.
/// ///
/// * `content` - The content of the event that should be encrypted. /// * `content` - The content of the event that should be encrypted.
#[cfg(test)]
pub(crate) async fn encrypt( pub(crate) async fn encrypt(
&self, &self,
event_type: EventType, event_type: EventType,
@ -125,6 +128,31 @@ impl Device {
.encrypt(&**self.verification_machine.store, event_type, content) .encrypt(&**self.verification_machine.store, event_type, content)
.await .await
} }
/// Encrypt the given inbound group session as a forwarded room key for this
/// device.
pub async fn encrypt_session(
&self,
session: InboundGroupSession,
) -> OlmResult<EncryptedEventContent> {
let export = session.export().await;
let content: ForwardedRoomKeyEventContent = if let Ok(c) = export.try_into() {
c
} else {
// TODO remove this panic.
panic!(
"Can't share session {} with device {} {}, key export can't \
be converted to a forwarded room key content",
session.session_id(),
self.user_id(),
self.device_id()
);
};
let content = serde_json::to_value(content)?;
self.encrypt(EventType::ForwardedRoomKey, content).await
}
} }
/// A read only view over all devices belonging to a user. /// A read only view over all devices belonging to a user.

View File

@ -126,7 +126,7 @@ impl IdentityManager {
continue; continue;
} }
let device = self.store.get_device(&user_id, device_id).await?; let device = self.store.get_readonly_device(&user_id, device_id).await?;
let device = if let Some(mut device) = device { let device = if let Some(mut device) = device {
if let Err(e) = device.update_device(device_keys) { if let Err(e) = device.update_device(device_keys) {
@ -157,7 +157,7 @@ impl IdentityManager {
let current_devices: HashSet<&DeviceId> = let current_devices: HashSet<&DeviceId> =
device_map.keys().map(|id| id.as_ref()).collect(); device_map.keys().map(|id| id.as_ref()).collect();
let stored_devices = self.store.get_user_devices(&user_id).await.unwrap(); let stored_devices = self.store.get_readonly_devices(&user_id).await?;
let stored_devices_set: HashSet<&DeviceId> = stored_devices.keys().collect(); let stored_devices_set: HashSet<&DeviceId> = stored_devices.keys().collect();
let deleted_devices = stored_devices_set.difference(&current_devices); let deleted_devices = stored_devices_set.difference(&current_devices);
@ -364,7 +364,9 @@ pub(crate) mod test {
use crate::{ use crate::{
identities::IdentityManager, identities::IdentityManager,
machine::test::response_from_file, machine::test::response_from_file,
store::{MemoryStore, Store}, olm::ReadOnlyAccount,
store::{CryptoStore, MemoryStore, Store},
verification::VerificationMachine,
}; };
fn user_id() -> UserId { fn user_id() -> UserId {
@ -381,7 +383,14 @@ pub(crate) mod test {
fn manager() -> IdentityManager { fn manager() -> IdentityManager {
let user_id = Arc::new(user_id()); let user_id = Arc::new(user_id());
let store = Store::new(user_id.clone(), Arc::new(Box::new(MemoryStore::new()))); let account = ReadOnlyAccount::new(&user_id, &device_id());
let store: Arc<Box<dyn CryptoStore>> = Arc::new(Box::new(MemoryStore::new()));
let verification = VerificationMachine::new(account, store);
let store = Store::new(
user_id.clone(),
Arc::new(Box::new(MemoryStore::new())),
verification,
);
IdentityManager::new(user_id, Arc::new(device_id()), store) IdentityManager::new(user_id, Arc::new(device_id()), store)
} }
@ -566,7 +575,7 @@ pub(crate) mod test {
let device = manager let device = manager
.store .store
.get_device(&other_user, "SKISMLNIMH".into()) .get_readonly_device(&other_user, "SKISMLNIMH".into())
.await .await
.unwrap() .unwrap()
.unwrap(); .unwrap();
@ -598,7 +607,7 @@ pub(crate) mod test {
let device = manager let device = manager
.store .store
.get_device(&other_user, "SKISMLNIMH".into()) .get_readonly_device(&other_user, "SKISMLNIMH".into())
.await .await
.unwrap() .unwrap()
.unwrap(); .unwrap();

View File

@ -20,12 +20,10 @@
// If we don't trust the device store an object that remembers the request and // If we don't trust the device store an object that remembers the request and
// let the users introspect that object. // let the users introspect that object.
#![allow(dead_code)]
use dashmap::DashMap; use dashmap::DashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{value::to_raw_value, Value}; use serde_json::value::to_raw_value;
use std::{collections::BTreeMap, convert::TryInto, ops::Deref, sync::Arc}; use std::{collections::BTreeMap, sync::Arc};
use thiserror::Error; use thiserror::Error;
use tracing::{error, info, instrument, trace, warn}; use tracing::{error, info, instrument, trace, warn};
@ -33,7 +31,6 @@ use matrix_sdk_common::{
api::r0::to_device::DeviceIdOrAllDevices, api::r0::to_device::DeviceIdOrAllDevices,
events::{ events::{
forwarded_room_key::ForwardedRoomKeyEventContent, forwarded_room_key::ForwardedRoomKeyEventContent,
room::encrypted::EncryptedEventContent,
room_key_request::{Action, RequestedKeyInfo, RoomKeyRequestEventContent}, room_key_request::{Action, RequestedKeyInfo, RoomKeyRequestEventContent},
AnyToDeviceEvent, EventType, ToDeviceEvent, AnyToDeviceEvent, EventType, ToDeviceEvent,
}, },
@ -44,67 +41,12 @@ use matrix_sdk_common::{
use crate::{ use crate::{
error::OlmResult, error::OlmResult,
identities::{OwnUserIdentity, ReadOnlyDevice, UserIdentities},
olm::{InboundGroupSession, OutboundGroupSession}, olm::{InboundGroupSession, OutboundGroupSession},
requests::{OutgoingRequest, ToDeviceRequest}, requests::{OutgoingRequest, ToDeviceRequest},
store::{CryptoStoreError, Store}, store::{CryptoStoreError, Store},
Device,
}; };
pub struct Device {
pub(crate) inner: ReadOnlyDevice,
pub(crate) store: Store,
pub(crate) own_identity: Option<OwnUserIdentity>,
pub(crate) device_owner_identity: Option<UserIdentities>,
}
impl Device {
/// Encrypt the given inbound group session as a forwarded room key for this
/// device.
pub async fn encrypt_session(
&self,
session: InboundGroupSession,
) -> OlmResult<EncryptedEventContent> {
let export = session.export().await;
let content: ForwardedRoomKeyEventContent = if let Ok(c) = export.try_into() {
c
} else {
// TODO remove this panic.
panic!(
"Can't share session {} with device {} {}, key export can't \
be converted to a forwarded room key content",
session.session_id(),
self.user_id(),
self.device_id()
);
};
let content = serde_json::to_value(content)?;
self.encrypt(EventType::ForwardedRoomKey, content).await
}
fn trust_state(&self) -> bool {
self.inner
.trust_state(&self.own_identity, &self.device_owner_identity)
}
pub async fn encrypt(
&self,
event_type: EventType,
content: Value,
) -> OlmResult<EncryptedEventContent> {
self.inner.encrypt(&*self.store, event_type, content).await
}
}
impl Deref for Device {
type Target = ReadOnlyDevice;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
/// An error describing why a key share request won't be honored. /// An error describing why a key share request won't be honored.
#[derive(Debug, Clone, Error, PartialEq)] #[derive(Debug, Clone, Error, PartialEq)]
pub enum KeyshareDecision { pub enum KeyshareDecision {
@ -282,14 +224,8 @@ impl KeyRequestMachine {
let device = self let device = self
.store .store
.get_device_and_users(&event.sender, &event.content.requesting_device_id) .get_device(&event.sender, &event.content.requesting_device_id)
.await? .await?;
.map(|(d, o, u)| Device {
inner: d,
store: self.store.clone(),
own_identity: o,
device_owner_identity: u,
});
if let Some(device) = device { if let Some(device) = device {
if let Err(e) = self.should_share_session( if let Err(e) = self.should_share_session(
@ -614,10 +550,11 @@ mod test {
use crate::{ use crate::{
identities::{LocalTrust, ReadOnlyDevice}, identities::{LocalTrust, ReadOnlyDevice},
olm::{Account, ReadOnlyAccount}, olm::{Account, ReadOnlyAccount},
store::{MemoryStore, Store}, store::{CryptoStore, MemoryStore, Store},
verification::VerificationMachine,
}; };
use super::{Device, KeyRequestMachine, KeyshareDecision}; use super::{KeyRequestMachine, KeyshareDecision};
fn alice_id() -> UserId { fn alice_id() -> UserId {
user_id!("@alice:example.org") user_id!("@alice:example.org")
@ -649,7 +586,10 @@ mod test {
fn bob_machine() -> KeyRequestMachine { fn bob_machine() -> KeyRequestMachine {
let user_id = Arc::new(bob_id()); let user_id = Arc::new(bob_id());
let store = Store::new(user_id.clone(), Arc::new(Box::new(MemoryStore::new()))); let account = ReadOnlyAccount::new(&user_id, &alice_device_id());
let store: Arc<Box<dyn CryptoStore>> = Arc::new(Box::new(MemoryStore::new()));
let verification = VerificationMachine::new(account, store.clone());
let store = Store::new(user_id.clone(), store, verification);
KeyRequestMachine::new( KeyRequestMachine::new(
user_id, user_id,
@ -659,9 +599,14 @@ mod test {
) )
} }
fn get_machine() -> KeyRequestMachine { async fn get_machine() -> KeyRequestMachine {
let user_id = Arc::new(alice_id()); let user_id = Arc::new(alice_id());
let store = Store::new(user_id.clone(), Arc::new(Box::new(MemoryStore::new()))); let account = ReadOnlyAccount::new(&user_id, &alice_device_id());
let device = ReadOnlyDevice::from_account(&account).await;
let store: Arc<Box<dyn CryptoStore>> = Arc::new(Box::new(MemoryStore::new()));
let verification = VerificationMachine::new(account, store.clone());
let store = Store::new(user_id.clone(), store, verification);
store.save_devices(&[device]).await.unwrap();
KeyRequestMachine::new( KeyRequestMachine::new(
user_id, user_id,
@ -671,16 +616,16 @@ mod test {
) )
} }
#[test] #[async_test]
fn create_machine() { async fn create_machine() {
let machine = get_machine(); let machine = get_machine().await;
assert!(machine.outgoing_to_device_requests().is_empty()); assert!(machine.outgoing_to_device_requests().is_empty());
} }
#[async_test] #[async_test]
async fn create_key_request() { async fn create_key_request() {
let machine = get_machine(); let machine = get_machine().await;
let account = account(); let account = account();
let (_, session) = account let (_, session) = account
@ -721,7 +666,7 @@ mod test {
#[async_test] #[async_test]
async fn receive_forwarded_key() { async fn receive_forwarded_key() {
let machine = get_machine(); let machine = get_machine().await;
let account = account(); let account = account();
let (_, session) = account let (_, session) = account
@ -848,15 +793,15 @@ mod test {
#[async_test] #[async_test]
async fn should_share_key_test() { async fn should_share_key_test() {
let machine = get_machine(); let machine = get_machine().await;
let account = account(); let account = account();
let own_device = Device { let own_device = machine
store: machine.store.clone(), .store
inner: ReadOnlyDevice::from_account(&account).await, .get_device(&alice_id(), &alice_device_id())
own_identity: None, .await
device_owner_identity: None, .unwrap()
}; .unwrap();
// We don't share keys with untrusted devices. // We don't share keys with untrusted devices.
assert_eq!( assert_eq!(
@ -869,12 +814,15 @@ mod test {
// Now we do want to share the keys. // Now we do want to share the keys.
assert!(machine.should_share_session(&own_device, None).is_ok()); assert!(machine.should_share_session(&own_device, None).is_ok());
let bob_device = Device { let bob_device = ReadOnlyDevice::from_account(&bob_account()).await;
store: machine.store.clone(), machine.store.save_devices(&[bob_device]).await.unwrap();
inner: ReadOnlyDevice::from_account(&bob_account()).await,
own_identity: None, let bob_device = machine
device_owner_identity: None, .store
}; .get_device(&bob_id(), &bob_device_id())
.await
.unwrap()
.unwrap();
// We don't share sessions with other user's devices if no outbound // We don't share sessions with other user's devices if no outbound
// session was provided. // session was provided.
@ -918,7 +866,7 @@ mod test {
#[async_test] #[async_test]
async fn key_share_cycle() { async fn key_share_cycle() {
let alice_machine = get_machine(); let alice_machine = get_machine().await;
let alice_account = Account { let alice_account = Account {
inner: account(), inner: account(),
store: alice_machine.store.clone(), store: alice_machine.store.clone(),

View File

@ -127,7 +127,7 @@ impl OlmMachine {
let store = Arc::new(store); let store = Arc::new(store);
let verification_machine = VerificationMachine::new(account.clone(), store.clone()); let verification_machine = VerificationMachine::new(account.clone(), store.clone());
let store = Store::new(user_id.clone(), store); let store = Store::new(user_id.clone(), store, verification_machine.clone());
let device_id: Arc<DeviceIdBox> = Arc::new(device_id); let device_id: Arc<DeviceIdBox> = Arc::new(device_id);
let outbound_group_sessions = Arc::new(DashMap::new()); let outbound_group_sessions = Arc::new(DashMap::new());
let key_request_machine = KeyRequestMachine::new( let key_request_machine = KeyRequestMachine::new(
@ -430,7 +430,7 @@ impl OlmMachine {
for (user_id, user_devices) in &response.one_time_keys { for (user_id, user_devices) in &response.one_time_keys {
for (device_id, key_map) in user_devices { for (device_id, key_map) in user_devices {
let device = match self.store.get_device(&user_id, device_id).await { let device = match self.store.get_readonly_device(&user_id, device_id).await {
Ok(Some(d)) => d, Ok(Some(d)) => d,
Ok(None) => { Ok(None) => {
warn!( warn!(
@ -889,16 +889,7 @@ impl OlmMachine {
user_id: &UserId, user_id: &UserId,
device_id: &DeviceId, device_id: &DeviceId,
) -> StoreResult<Option<Device>> { ) -> StoreResult<Option<Device>> {
Ok(self self.store.get_device(user_id, device_id).await
.store
.get_device_and_users(user_id, device_id)
.await?
.map(|(d, o, u)| Device {
inner: d,
verification_machine: self.verification_machine.clone(),
own_identity: o,
device_owner_identity: u,
}))
} }
/// Get a map holding all the devices of an user. /// Get a map holding all the devices of an user.
@ -925,22 +916,7 @@ impl OlmMachine {
/// # }); /// # });
/// ``` /// ```
pub async fn get_user_devices(&self, user_id: &UserId) -> StoreResult<UserDevices> { pub async fn get_user_devices(&self, user_id: &UserId) -> StoreResult<UserDevices> {
let devices = self.store.get_user_devices(user_id).await?; self.store.get_user_devices(user_id).await
let own_identity = self
.store
.get_user_identity(self.user_id())
.await?
.map(|i| i.own().cloned())
.flatten();
let device_owner_identity = self.store.get_user_identity(user_id).await.ok().flatten();
Ok(UserDevices {
inner: devices,
verification_machine: self.verification_machine.clone(),
own_identity,
device_owner_identity,
})
} }
/// Import the given room keys into our store. /// Import the given room keys into our store.

View File

@ -70,13 +70,13 @@ use matrix_sdk_common_macros::async_trait;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use matrix_sdk_common_macros::send_sync; use matrix_sdk_common_macros::send_sync;
use super::{ use crate::{
identities::{OwnUserIdentity, ReadOnlyDevice, UserIdentities}, error::SessionUnpicklingError,
identities::{Device, ReadOnlyDevice, UserDevices, UserIdentities},
olm::{InboundGroupSession, ReadOnlyAccount, Session}, olm::{InboundGroupSession, ReadOnlyAccount, Session},
verification::VerificationMachine,
}; };
use crate::error::SessionUnpicklingError;
/// A `CryptoStore` specific result type. /// A `CryptoStore` specific result type.
pub type Result<T> = std::result::Result<T, CryptoStoreError>; pub type Result<T> = std::result::Result<T, CryptoStoreError>;
@ -90,48 +90,77 @@ pub type Result<T> = std::result::Result<T, CryptoStoreError>;
pub(crate) struct Store { pub(crate) struct Store {
user_id: Arc<UserId>, user_id: Arc<UserId>,
inner: Arc<Box<dyn CryptoStore>>, inner: Arc<Box<dyn CryptoStore>>,
verification_machine: VerificationMachine,
} }
impl Store { impl Store {
pub fn new(user_id: Arc<UserId>, store: Arc<Box<dyn CryptoStore>>) -> Self { pub fn new(
user_id: Arc<UserId>,
store: Arc<Box<dyn CryptoStore>>,
verification_machine: VerificationMachine,
) -> Self {
Self { Self {
user_id, user_id,
inner: store, inner: store,
verification_machine,
} }
} }
pub async fn get_device_and_users( pub async fn get_readonly_device(
&self, &self,
user_id: &UserId, user_id: &UserId,
device_id: &DeviceId, device_id: &DeviceId,
) -> Result< ) -> Result<Option<ReadOnlyDevice>> {
Option<( self.inner.get_device(user_id, device_id).await
ReadOnlyDevice, }
Option<OwnUserIdentity>,
Option<UserIdentities>, pub async fn get_readonly_devices(&self, user_id: &UserId) -> Result<ReadOnlyUserDevices> {
)>, self.inner.get_user_devices(user_id).await
> { }
let device = self.get_device(user_id, device_id).await?;
pub async fn get_user_devices(&self, user_id: &UserId) -> Result<UserDevices> {
let device = if let Some(d) = device { let devices = self.inner.get_user_devices(user_id).await?;
d
} else { let own_identity = self
return Ok(None); .inner
}; .get_user_identity(&self.user_id)
.await?
let own_identity = self .map(|i| i.own().cloned())
.get_user_identity(&self.user_id) .flatten();
.await let device_owner_identity = self.inner.get_user_identity(user_id).await.ok().flatten();
.ok()
.flatten() Ok(UserDevices {
.map(|i| i.own().cloned()) inner: devices,
.flatten(); verification_machine: self.verification_machine.clone(),
let device_owner_identity = self.get_user_identity(user_id).await.ok().flatten(); own_identity,
device_owner_identity,
Ok(Some((device, own_identity, device_owner_identity))) })
}
pub async fn get_device(
&self,
user_id: &UserId,
device_id: &DeviceId,
) -> Result<Option<Device>> {
let own_identity = self
.get_user_identity(&self.user_id)
.await?
.map(|i| i.own().cloned())
.flatten();
let device_owner_identity = self.get_user_identity(user_id).await?;
Ok(self
.inner
.get_device(user_id, device_id)
.await?
.map(|d| Device {
inner: d,
verification_machine: self.verification_machine.clone(),
own_identity,
device_owner_identity,
}))
} }
#[allow(dead_code)]
pub async fn get_object<V: for<'b> Deserialize<'b>>(&self, key: &str) -> Result<Option<V>> { pub async fn get_object<V: for<'b> Deserialize<'b>>(&self, key: &str) -> Result<Option<V>> {
if let Some(value) = self.get_value(key).await? { if let Some(value) = self.get_value(key).await? {
Ok(Some(serde_json::from_str(&value)?)) Ok(Some(serde_json::from_str(&value)?))
@ -140,13 +169,11 @@ impl Store {
} }
} }
#[allow(dead_code)]
pub async fn save_object(&self, key: &str, value: &impl Serialize) -> Result<()> { pub async fn save_object(&self, key: &str, value: &impl Serialize) -> Result<()> {
let value = serde_json::to_string(value)?; let value = serde_json::to_string(value)?;
self.save_value(key.to_owned(), value).await self.save_value(key.to_owned(), value).await
} }
#[allow(dead_code)]
pub async fn delete_object(&self, key: &str) -> Result<()> { pub async fn delete_object(&self, key: &str) -> Result<()> {
self.inner.remove_value(key).await?; self.inner.remove_value(key).await?;
Ok(()) Ok(())