crypto: Calculate the deleted devices in a key query.

master
Damir Jelić 2020-04-02 14:52:15 +02:00
parent 56084a7809
commit 913cc374d0
7 changed files with 114 additions and 28 deletions

View File

@ -39,6 +39,8 @@ zeroize = { version = "1.1.0", optional = true }
thiserror = "1.0.13" thiserror = "1.0.13"
async-trait = { version = "0.1.26", optional = true } async-trait = { version = "0.1.26", optional = true }
tracing = "0.1.13" tracing = "0.1.13"
atomic = "0.4.5"
dashmap = "3.9.1"
[dependencies.tracing-futures] [dependencies.tracing-futures]
version = "0.2.3" version = "0.2.3"

View File

@ -13,22 +13,26 @@
// limitations under the License. // limitations under the License.
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use atomic::Atomic;
use ruma_client_api::r0::keys::{DeviceKeys, KeyAlgorithm}; use ruma_client_api::r0::keys::{DeviceKeys, KeyAlgorithm};
use ruma_events::Algorithm; use ruma_events::Algorithm;
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Device { pub struct Device {
user_id: String, user_id: Arc<String>,
device_id: String, device_id: Arc<String>,
algorithms: Vec<Algorithm>, algorithms: Arc<Vec<Algorithm>>,
keys: HashMap<KeyAlgorithm, String>, keys: Arc<HashMap<KeyAlgorithm, String>>,
display_name: Option<String>, display_name: Arc<Option<String>>,
deleted: bool, deleted: Arc<AtomicBool>,
trust_state: TrustState, trust_state: Arc<Atomic<TrustState>>,
} }
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
pub enum TrustState { pub enum TrustState {
Verified, Verified,
BlackListed, BlackListed,
@ -37,7 +41,7 @@ pub enum TrustState {
} }
impl Device { impl Device {
pub fn id(&self) -> &str { pub fn device_id(&self) -> &str {
&self.device_id &self.device_id
} }
@ -56,16 +60,18 @@ impl From<&DeviceKeys> for Device {
} }
Device { Device {
user_id: device_keys.user_id.to_string(), user_id: Arc::new(device_keys.user_id.to_string()),
device_id: device_keys.device_id.clone(), device_id: Arc::new(device_keys.device_id.clone()),
algorithms: device_keys.algorithms.clone(), algorithms: Arc::new(device_keys.algorithms.clone()),
keys, keys: Arc::new(keys),
display_name: device_keys display_name: Arc::new(
.unsigned device_keys
.as_ref() .unsigned
.map(|d| d.device_display_name.clone()), .as_ref()
deleted: false, .map(|d| d.device_display_name.clone()),
trust_state: TrustState::Unset, ),
deleted: Arc::new(AtomicBool::new(false)),
trust_state: Arc::new(Atomic::new(TrustState::Unset)),
} }
} }
} }

View File

@ -240,17 +240,27 @@ impl OlmMachine {
let device = self let device = self
.store .store
.get_user_device(&user_id_string, device_id) .get_device(&user_id_string, device_id)
.await .await
.expect("Can't load device"); .expect("Can't load device");
if let Some(d) = device { if let Some(d) = device {
todo!() // TODO check what and if anything changed for the device.
} else { } else {
let device = Device::from(device_keys); let device = Device::from(device_keys);
info!("Found new device {:?}", device); info!("Found new device {:?}", device);
} }
} }
let current_devices: HashSet<&String> = device_map.keys().collect();
let stored_devices = self.store.get_user_devices(&user_id_string).await.unwrap();
let stored_devices_set: HashSet<&String> = stored_devices.keys().collect();
let deleted_devices = stored_devices_set.difference(&current_devices);
for device_id in deleted_devices {
// TODO delete devices here.
}
} }
Ok(()) Ok(())
} }

View File

@ -15,8 +15,10 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use dashmap::{DashMap, ReadOnlyView};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use super::device::Device;
use super::olm::{InboundGroupSession, Session}; use super::olm::{InboundGroupSession, Session};
#[derive(Debug)] #[derive(Debug)]
@ -96,3 +98,57 @@ impl GroupSessionStore {
.and_then(|m| m.get(sender_key).and_then(|m| m.get(session_id).cloned())) .and_then(|m| m.get(sender_key).and_then(|m| m.get(session_id).cloned()))
} }
} }
#[derive(Debug)]
pub struct DeviceStore {
entries: DashMap<String, DashMap<String, Device>>,
}
pub struct UserDevices {
entries: ReadOnlyView<String, Device>,
}
impl UserDevices {
pub fn get(&self, device_id: &str) -> Option<Device> {
self.entries.get(device_id).cloned()
}
pub fn keys(&self) -> impl Iterator<Item = &String> {
self.entries.keys()
}
}
impl DeviceStore {
pub fn new() -> Self {
DeviceStore {
entries: DashMap::new(),
}
}
pub fn add(&self, device: Device) -> bool {
if !self.entries.contains_key(device.user_id()) {
self.entries
.insert(device.user_id().to_owned(), DashMap::new());
}
let mut device_map = self.entries.get_mut(device.user_id()).unwrap();
device_map
.insert(device.device_id().to_owned(), device)
.is_some()
}
pub fn get(&self, user_id: &str, device_id: &str) -> Option<Device> {
self.entries
.get(user_id)
.and_then(|m| m.get(device_id).map(|d| d.value().clone()))
}
pub fn user_devices(&self, user_id: &str) -> UserDevices {
if !self.entries.contains_key(user_id) {
self.entries.insert(user_id.to_owned(), DashMap::new());
}
UserDevices {
entries: self.entries.get(user_id).unwrap().clone().into_read_only(),
}
}
}

View File

@ -20,13 +20,14 @@ use tokio::sync::Mutex;
use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session}; use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session};
use crate::crypto::device::Device; use crate::crypto::device::Device;
use crate::crypto::memory_stores::{GroupSessionStore, SessionStore}; use crate::crypto::memory_stores::{DeviceStore, GroupSessionStore, SessionStore, UserDevices};
#[derive(Debug)] #[derive(Debug)]
pub struct MemoryStore { pub struct MemoryStore {
sessions: SessionStore, sessions: SessionStore,
inbound_group_sessions: GroupSessionStore, inbound_group_sessions: GroupSessionStore,
tracked_users: HashSet<String>, tracked_users: HashSet<String>,
devices: DeviceStore,
} }
impl MemoryStore { impl MemoryStore {
@ -35,6 +36,7 @@ impl MemoryStore {
sessions: SessionStore::new(), sessions: SessionStore::new(),
inbound_group_sessions: GroupSessionStore::new(), inbound_group_sessions: GroupSessionStore::new(),
tracked_users: HashSet::new(), tracked_users: HashSet::new(),
devices: DeviceStore::new(),
} }
} }
} }
@ -88,7 +90,11 @@ impl CryptoStore for MemoryStore {
Ok(self.tracked_users.insert(user.to_string())) Ok(self.tracked_users.insert(user.to_string()))
} }
async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>> { async fn get_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>> {
Ok(None) Ok(self.devices.get(user_id, device_id))
}
async fn get_user_devices(&self, user_id: &str) -> Result<UserDevices> {
Ok(self.devices.user_devices(user_id))
} }
} }

View File

@ -25,6 +25,7 @@ use thiserror::Error;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use super::device::Device; use super::device::Device;
use super::memory_stores::UserDevices;
use super::olm::{Account, InboundGroupSession, Session}; use super::olm::{Account, InboundGroupSession, Session};
use olm_rs::errors::{OlmAccountError, OlmGroupSessionError, OlmSessionError}; use olm_rs::errors::{OlmAccountError, OlmGroupSessionError, OlmSessionError};
use olm_rs::PicklingMode; use olm_rs::PicklingMode;
@ -82,5 +83,6 @@ pub trait CryptoStore: Debug + Send + Sync {
) -> Result<Option<Arc<Mutex<InboundGroupSession>>>>; ) -> Result<Option<Arc<Mutex<InboundGroupSession>>>>;
fn tracked_users(&self) -> &HashSet<String>; fn tracked_users(&self) -> &HashSet<String>;
async fn add_user_for_tracking(&mut self, user: &str) -> Result<bool>; async fn add_user_for_tracking(&mut self, user: &str) -> Result<bool>;
async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>>; async fn get_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>>;
async fn get_user_devices(&self, user_id: &str) -> Result<UserDevices>;
} }

View File

@ -28,7 +28,7 @@ use zeroize::Zeroizing;
use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session}; use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session};
use crate::crypto::device::Device; use crate::crypto::device::Device;
use crate::crypto::memory_stores::{GroupSessionStore, SessionStore}; use crate::crypto::memory_stores::{GroupSessionStore, SessionStore, UserDevices};
pub struct SqliteStore { pub struct SqliteStore {
user_id: Arc<String>, user_id: Arc<String>,
@ -410,7 +410,11 @@ impl CryptoStore for SqliteStore {
Ok(self.tracked_users.insert(user.to_string())) Ok(self.tracked_users.insert(user.to_string()))
} }
async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>> { async fn get_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>> {
todo!()
}
async fn get_user_devices(&self, user_id: &str) -> Result<UserDevices> {
todo!() todo!()
} }
} }