crypto: Initial support for device tracking.
parent
5e22eb9faf
commit
56084a7809
|
@ -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<Algorithm>,
|
||||||
|
keys: HashMap<KeyAlgorithm, String>,
|
||||||
|
display_name: Option<String>,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ use super::olm::{Account, InboundGroupSession, Session};
|
||||||
use super::store::memorystore::MemoryStore;
|
use super::store::memorystore::MemoryStore;
|
||||||
#[cfg(feature = "sqlite-cryptostore")]
|
#[cfg(feature = "sqlite-cryptostore")]
|
||||||
use super::store::sqlite::SqliteStore;
|
use super::store::sqlite::SqliteStore;
|
||||||
use super::CryptoStore;
|
use super::{device::Device, CryptoStore};
|
||||||
use crate::api;
|
use crate::api;
|
||||||
|
|
||||||
use api::r0::keys;
|
use api::r0::keys;
|
||||||
|
@ -188,13 +188,71 @@ impl OlmMachine {
|
||||||
///
|
///
|
||||||
/// * `response` - The keys query response of the request that the client
|
/// * `response` - The keys query response of the request that the client
|
||||||
/// performed.
|
/// performed.
|
||||||
// TODO this should return a
|
// TODO this should return a list of changed devices.
|
||||||
#[instrument]
|
|
||||||
pub async fn receive_keys_query_response(
|
pub async fn receive_keys_query_response(
|
||||||
&mut self,
|
&mut self,
|
||||||
response: &keys::get_keys::Response,
|
response: &keys::get_keys::Response,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
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!()
|
todo!()
|
||||||
|
} else {
|
||||||
|
let device = Device::from(device_keys);
|
||||||
|
info!("Found new device {:?}", device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate new one-time keys.
|
/// Generate new one-time keys.
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
// TODO remove this.
|
// TODO remove this.
|
||||||
|
mod device;
|
||||||
mod machine;
|
mod machine;
|
||||||
mod memory_stores;
|
mod memory_stores;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -19,6 +19,7 @@ use async_trait::async_trait;
|
||||||
use tokio::sync::Mutex;
|
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::memory_stores::{GroupSessionStore, SessionStore};
|
use crate::crypto::memory_stores::{GroupSessionStore, SessionStore};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -86,4 +87,8 @@ impl CryptoStore for MemoryStore {
|
||||||
async fn add_user_for_tracking(&mut self, user: &str) -> Result<bool> {
|
async fn add_user_for_tracking(&mut self, user: &str) -> Result<bool> {
|
||||||
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>> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ use serde_json::Error as SerdeError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
use super::device::Device;
|
||||||
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;
|
||||||
|
@ -81,4 +82,5 @@ 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>>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ use tokio::sync::Mutex;
|
||||||
use zeroize::Zeroizing;
|
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::memory_stores::{GroupSessionStore, SessionStore};
|
use crate::crypto::memory_stores::{GroupSessionStore, SessionStore};
|
||||||
|
|
||||||
pub struct SqliteStore {
|
pub struct SqliteStore {
|
||||||
|
@ -406,6 +407,10 @@ impl CryptoStore for SqliteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_user_for_tracking(&mut self, user: &str) -> Result<bool> {
|
async fn add_user_for_tracking(&mut self, user: &str) -> Result<bool> {
|
||||||
|
Ok(self.tracked_users.insert(user.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_user_device(&self, user_id: &str, device_id: &str) -> Result<Option<Device>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
self.encrypted = true;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue