diff --git a/src/crypto/device.rs b/src/crypto/device.rs new file mode 100644 index 00000000..fe8ff498 --- /dev/null +++ b/src/crypto/device.rs @@ -0,0 +1,71 @@ +// Copyright 2020 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::collections::HashMap; + +use ruma_client_api::r0::keys::{DeviceKeys, KeyAlgorithm}; +use ruma_events::Algorithm; + +#[derive(Debug)] +pub struct Device { + user_id: String, + device_id: String, + algorithms: Vec, + keys: HashMap, + display_name: Option, + deleted: bool, + trust_state: TrustState, +} + +#[derive(Debug)] +pub enum TrustState { + Verified, + BlackListed, + Ignored, + Unset, +} + +impl Device { + pub fn id(&self) -> &str { + &self.device_id + } + + pub fn user_id(&self) -> &str { + &self.user_id + } +} + +impl From<&DeviceKeys> for Device { + fn from(device_keys: &DeviceKeys) -> Self { + let mut keys = HashMap::new(); + + for (key_id, key) in device_keys.keys.iter() { + let key_id = key_id.0; + keys.insert(key_id, key.clone()); + } + + Device { + user_id: device_keys.user_id.to_string(), + device_id: device_keys.device_id.clone(), + algorithms: device_keys.algorithms.clone(), + keys, + display_name: device_keys + .unsigned + .as_ref() + .map(|d| d.device_display_name.clone()), + deleted: false, + trust_state: TrustState::Unset, + } + } +} diff --git a/src/crypto/machine.rs b/src/crypto/machine.rs index ba975101..abfd8196 100644 --- a/src/crypto/machine.rs +++ b/src/crypto/machine.rs @@ -25,7 +25,7 @@ use super::olm::{Account, InboundGroupSession, Session}; use super::store::memorystore::MemoryStore; #[cfg(feature = "sqlite-cryptostore")] use super::store::sqlite::SqliteStore; -use super::CryptoStore; +use super::{device::Device, CryptoStore}; use crate::api; use api::r0::keys; @@ -188,13 +188,71 @@ impl OlmMachine { /// /// * `response` - The keys query response of the request that the client /// performed. - // TODO this should return a - #[instrument] + // TODO this should return a list of changed devices. pub async fn receive_keys_query_response( &mut self, response: &keys::get_keys::Response, ) -> Result<()> { - todo!() + for (user_id, device_map) in &response.device_keys { + let user_id_string = user_id.to_string(); + self.users_for_key_query.remove(&user_id_string); + + for (device_id, device_keys) in device_map.iter() { + // We don't need our own device in the device store. + if user_id == &self.user_id && device_id == &self.device_id { + continue; + } + + if user_id != &device_keys.user_id || device_id != &device_keys.device_id { + warn!( + "Mismatch in device keys payload of device {} from user {}", + device_keys.device_id, device_keys.user_id + ); + continue; + } + + let curve_key_id = + AlgorithmAndDeviceId(KeyAlgorithm::Curve25519, device_id.to_owned()); + let ed_key_id = AlgorithmAndDeviceId(KeyAlgorithm::Ed25519, device_id.to_owned()); + + let sender_key = if let Some(k) = device_keys.keys.get(&curve_key_id) { + k + } else { + continue; + }; + + let signing_key = if let Some(k) = device_keys.keys.get(&ed_key_id) { + k + } else { + continue; + }; + + if self + .verify_json(user_id, device_id, signing_key, &mut json!(&device_keys)) + .is_err() + { + warn!( + "Failed to verify the device key signatures for {} {}", + user_id, device_id + ); + continue; + } + + let device = self + .store + .get_user_device(&user_id_string, device_id) + .await + .expect("Can't load device"); + + if let Some(d) = device { + todo!() + } else { + let device = Device::from(device_keys); + info!("Found new device {:?}", device); + } + } + } + Ok(()) } /// Generate new one-time keys. diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index a16a4205..01df02bc 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -14,6 +14,7 @@ mod error; // TODO remove this. +mod device; mod machine; mod memory_stores; #[allow(dead_code)] diff --git a/src/crypto/store/memorystore.rs b/src/crypto/store/memorystore.rs index 34540748..2c522cf7 100644 --- a/src/crypto/store/memorystore.rs +++ b/src/crypto/store/memorystore.rs @@ -19,6 +19,7 @@ use async_trait::async_trait; use tokio::sync::Mutex; use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session}; +use crate::crypto::device::Device; use crate::crypto::memory_stores::{GroupSessionStore, SessionStore}; #[derive(Debug)] @@ -86,4 +87,8 @@ impl CryptoStore for MemoryStore { async fn add_user_for_tracking(&mut self, user: &str) -> Result { Ok(self.tracked_users.insert(user.to_string())) } + + async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result> { + Ok(None) + } } diff --git a/src/crypto/store/mod.rs b/src/crypto/store/mod.rs index 3279aa74..718116b9 100644 --- a/src/crypto/store/mod.rs +++ b/src/crypto/store/mod.rs @@ -24,6 +24,7 @@ use serde_json::Error as SerdeError; use thiserror::Error; use tokio::sync::Mutex; +use super::device::Device; use super::olm::{Account, InboundGroupSession, Session}; use olm_rs::errors::{OlmAccountError, OlmGroupSessionError, OlmSessionError}; use olm_rs::PicklingMode; @@ -81,4 +82,5 @@ pub trait CryptoStore: Debug + Send + Sync { ) -> Result>>>; fn tracked_users(&self) -> &HashSet; async fn add_user_for_tracking(&mut self, user: &str) -> Result; + async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result>; } diff --git a/src/crypto/store/sqlite.rs b/src/crypto/store/sqlite.rs index ca39c4de..bf2117de 100644 --- a/src/crypto/store/sqlite.rs +++ b/src/crypto/store/sqlite.rs @@ -27,6 +27,7 @@ use tokio::sync::Mutex; use zeroize::Zeroizing; use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session}; +use crate::crypto::device::Device; use crate::crypto::memory_stores::{GroupSessionStore, SessionStore}; pub struct SqliteStore { @@ -406,6 +407,10 @@ impl CryptoStore for SqliteStore { } async fn add_user_for_tracking(&mut self, user: &str) -> Result { + Ok(self.tracked_users.insert(user.to_string())) + } + + async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result> { todo!() } } diff --git a/src/models/room.rs b/src/models/room.rs index 6b983b7f..2d64e07a 100644 --- a/src/models/room.rs +++ b/src/models/room.rs @@ -242,7 +242,8 @@ impl Room { } } - fn handle_encryption_event(&mut self, event: &EncryptionEvent) -> bool { + fn handle_encryption_event(&mut self, _: &EncryptionEvent) -> bool { + // TODO store the encryption settings. self.encrypted = true; true }