crypto: Add a method to save/load arbitrary objects from a CryptoStore.

This actually adds trait methods that save/load strings from the
CryptoStore. We add a wrapper for the CryptoStore since we can't mix
trait objects and generics, so we add generic methods to save/load
anything that implements Serialize/Deserialize.
master
Damir Jelić 2020-09-16 16:03:19 +02:00
parent 849934b180
commit 24ce4881c7
7 changed files with 87 additions and 24 deletions

View File

@ -651,7 +651,7 @@ impl OwnUserIdentity {
#[cfg(test)] #[cfg(test)]
pub(crate) mod test { pub(crate) mod test {
use serde_json::json; use serde_json::json;
use std::{convert::TryFrom, sync::Arc}; use std::convert::TryFrom;
use matrix_sdk_common::{ use matrix_sdk_common::{
api::r0::keys::get_keys::Response as KeyQueryResponse, identifiers::user_id, api::r0::keys::get_keys::Response as KeyQueryResponse, identifiers::user_id,
@ -661,7 +661,7 @@ pub(crate) mod test {
identities::{Device, ReadOnlyDevice}, identities::{Device, ReadOnlyDevice},
machine::test::response_from_file, machine::test::response_from_file,
olm::Account, olm::Account,
store::MemoryStore, store::{MemoryStore, Store},
verification::VerificationMachine, verification::VerificationMachine,
}; };
@ -884,7 +884,7 @@ pub(crate) mod test {
let verification_machine = VerificationMachine::new( let verification_machine = VerificationMachine::new(
Account::new(second.user_id(), second.device_id()), Account::new(second.user_id(), second.device_id()),
Arc::new(Box::new(MemoryStore::new())), Store::new(Box::new(MemoryStore::new())),
); );
let first = Device { let first = Device {

View File

@ -62,7 +62,7 @@ use super::{
InboundGroupSession, OlmMessage, OutboundGroupSession, InboundGroupSession, OlmMessage, OutboundGroupSession,
}, },
requests::{IncomingResponse, KeysQueryRequest, OutgoingRequest, ToDeviceRequest}, requests::{IncomingResponse, KeysQueryRequest, OutgoingRequest, ToDeviceRequest},
store::{CryptoStore, MemoryStore, Result as StoreResult}, store::{CryptoStore, MemoryStore, Result as StoreResult, Store},
verification::{Sas, VerificationMachine}, verification::{Sas, VerificationMachine},
}; };
@ -79,7 +79,7 @@ pub struct OlmMachine {
/// Store for the encryption keys. /// Store for the encryption keys.
/// Persists all the encryption keys so a client can resume the session /// Persists all the encryption keys so a client can resume the session
/// without the need to create new keys. /// without the need to create new keys.
store: Arc<Box<dyn CryptoStore>>, store: Store,
/// The currently active outbound group sessions. /// The currently active outbound group sessions.
outbound_group_sessions: Arc<DashMap<RoomId, OutboundGroupSession>>, outbound_group_sessions: Arc<DashMap<RoomId, OutboundGroupSession>>,
/// A state machine that is responsible to handle and keep track of SAS /// A state machine that is responsible to handle and keep track of SAS
@ -113,7 +113,7 @@ impl OlmMachine {
/// * `device_id` - The unique id of the device that owns this machine. /// * `device_id` - The unique id of the device that owns this machine.
pub fn new(user_id: &UserId, device_id: &DeviceId) -> Self { pub fn new(user_id: &UserId, device_id: &DeviceId) -> Self {
let store: Box<dyn CryptoStore> = Box::new(MemoryStore::new()); let store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
let store = Arc::new(store); let store = Store::new(store);
let account = Account::new(user_id, device_id); let account = Account::new(user_id, device_id);
OlmMachine { OlmMachine {
@ -161,7 +161,7 @@ impl OlmMachine {
} }
}; };
let store = Arc::new(store); let store = Store::new(store);
let verification_machine = VerificationMachine::new(account.clone(), store.clone()); let verification_machine = VerificationMachine::new(account.clone(), store.clone());
Ok(OlmMachine { Ok(OlmMachine {

View File

@ -36,6 +36,7 @@ pub struct MemoryStore {
users_for_key_query: Arc<DashSet<UserId>>, users_for_key_query: Arc<DashSet<UserId>>,
devices: DeviceStore, devices: DeviceStore,
identities: Arc<DashMap<UserId, UserIdentities>>, identities: Arc<DashMap<UserId, UserIdentities>>,
values: Arc<DashMap<String, String>>,
} }
impl Default for MemoryStore { impl Default for MemoryStore {
@ -47,6 +48,7 @@ impl Default for MemoryStore {
users_for_key_query: Arc::new(DashSet::new()), users_for_key_query: Arc::new(DashSet::new()),
devices: DeviceStore::new(), devices: DeviceStore::new(),
identities: Arc::new(DashMap::new()), identities: Arc::new(DashMap::new()),
values: Arc::new(DashMap::new()),
} }
} }
} }
@ -164,6 +166,15 @@ impl CryptoStore for MemoryStore {
} }
Ok(()) Ok(())
} }
async fn save_value(&self, key: String, value: String) -> Result<()> {
self.values.insert(key, value);
Ok(())
}
async fn get_value(&self, key: &str) -> Result<Option<String>> {
Ok(self.values.get(key).map(|v| v.to_owned()))
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -49,9 +49,10 @@ pub use memorystore::MemoryStore;
#[cfg(feature = "sqlite_cryptostore")] #[cfg(feature = "sqlite_cryptostore")]
pub use sqlite::SqliteStore; pub use sqlite::SqliteStore;
use std::{collections::HashSet, fmt::Debug, io::Error as IoError, sync::Arc}; use std::{collections::HashSet, fmt::Debug, io::Error as IoError, ops::Deref, sync::Arc};
use olm_rs::errors::{OlmAccountError, OlmGroupSessionError, OlmSessionError}; use olm_rs::errors::{OlmAccountError, OlmGroupSessionError, OlmSessionError};
use serde::{Deserialize, Serialize};
use serde_json::Error as SerdeError; use serde_json::Error as SerdeError;
use thiserror::Error; use thiserror::Error;
use url::ParseError; use url::ParseError;
@ -76,6 +77,44 @@ use super::{
use crate::error::SessionUnpicklingError; use crate::error::SessionUnpicklingError;
/// A wrapper for our CryptoStore trait object.
///
/// This is needed because we want to have a generic interface so we can
/// store/restore objects that we can serialize. Since trait objects and
/// generics don't mix let the CryptoStore store strings and this wrapper
/// adds the generic interface on top.
#[derive(Debug, Clone)]
pub(crate) struct Store(Arc<Box<dyn CryptoStore>>);
impl Store {
pub fn new(store: Box<dyn CryptoStore>) -> Self {
Self(Arc::new(store))
}
#[allow(dead_code)]
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? {
Ok(Some(serde_json::from_str(&value)?))
} else {
Ok(None)
}
}
#[allow(dead_code)]
pub async fn save_object(&self, key: &str, value: &impl Serialize) -> Result<()> {
let value = serde_json::to_string(value)?;
self.save_value(key.to_owned(), value).await
}
}
impl Deref for Store {
type Target = dyn CryptoStore;
fn deref(&self) -> &Self::Target {
&**self.0
}
}
/// 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>;
@ -250,4 +289,10 @@ pub trait CryptoStore: Debug {
/// ///
/// * `user_id` - The user for which we should get the identity. /// * `user_id` - The user for which we should get the identity.
async fn get_user_identity(&self, user_id: &UserId) -> Result<Option<UserIdentities>>; async fn get_user_identity(&self, user_id: &UserId) -> Result<Option<UserIdentities>>;
/// Save a serializeable object in the store.
async fn save_value(&self, key: String, value: String) -> Result<()>;
/// Load a serializeable object from the store.
async fn get_value(&self, key: &str) -> Result<Option<String>>;
} }

View File

@ -1371,6 +1371,14 @@ impl CryptoStore for SqliteStore {
Ok(()) Ok(())
} }
async fn save_value(&self, _key: String, _value: String) -> Result<()> {
todo!()
}
async fn get_value(&self, _key: &str) -> Result<Option<String>> {
todo!()
}
} }
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]

View File

@ -27,20 +27,20 @@ use matrix_sdk_common::{
use super::sas::{content_to_request, Sas}; use super::sas::{content_to_request, Sas};
use crate::{ use crate::{
requests::{OutgoingRequest, ToDeviceRequest}, requests::{OutgoingRequest, ToDeviceRequest},
store::{CryptoStore, CryptoStoreError}, store::{CryptoStoreError, Store},
Account, ReadOnlyDevice, Account, ReadOnlyDevice,
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct VerificationMachine { pub struct VerificationMachine {
account: Account, account: Account,
pub(crate) store: Arc<Box<dyn CryptoStore>>, pub(crate) store: Store,
verifications: Arc<DashMap<String, Sas>>, verifications: Arc<DashMap<String, Sas>>,
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>, outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
} }
impl VerificationMachine { impl VerificationMachine {
pub(crate) fn new(account: Account, store: Arc<Box<dyn CryptoStore>>) -> Self { pub(crate) fn new(account: Account, store: Store) -> Self {
Self { Self {
account, account,
store, store,
@ -221,7 +221,6 @@ mod test {
use std::{ use std::{
convert::TryFrom, convert::TryFrom,
sync::Arc,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -233,7 +232,7 @@ mod test {
use super::{Sas, VerificationMachine}; use super::{Sas, VerificationMachine};
use crate::{ use crate::{
requests::OutgoingRequests, requests::OutgoingRequests,
store::{CryptoStore, MemoryStore}, store::{CryptoStore, MemoryStore, Store},
verification::test::{get_content_from_request, wrap_any_to_device_content}, verification::test::{get_content_from_request, wrap_any_to_device_content},
Account, ReadOnlyDevice, Account, ReadOnlyDevice,
}; };
@ -258,7 +257,7 @@ mod test {
let alice = Account::new(&alice_id(), &alice_device_id()); let alice = Account::new(&alice_id(), &alice_device_id());
let bob = Account::new(&bob_id(), &bob_device_id()); let bob = Account::new(&bob_id(), &bob_device_id());
let store = MemoryStore::new(); let store = MemoryStore::new();
let bob_store: Arc<Box<dyn CryptoStore>> = Arc::new(Box::new(MemoryStore::new())); let bob_store = Store::new(Box::new(MemoryStore::new()));
let bob_device = ReadOnlyDevice::from_account(&bob).await; let bob_device = ReadOnlyDevice::from_account(&bob).await;
let alice_device = ReadOnlyDevice::from_account(&alice).await; let alice_device = ReadOnlyDevice::from_account(&alice).await;
@ -269,7 +268,7 @@ mod test {
.await .await
.unwrap(); .unwrap();
let machine = VerificationMachine::new(alice, Arc::new(Box::new(store))); let machine = VerificationMachine::new(alice, Store::new(Box::new(store)));
let (bob_sas, start_content) = Sas::start(bob, alice_device, bob_store, None); let (bob_sas, start_content) = Sas::start(bob, alice_device, bob_store, None);
machine machine
.receive_event(&mut wrap_any_to_device_content( .receive_event(&mut wrap_any_to_device_content(
@ -286,7 +285,7 @@ mod test {
fn create() { fn create() {
let alice = Account::new(&alice_id(), &alice_device_id()); let alice = Account::new(&alice_id(), &alice_device_id());
let store = MemoryStore::new(); let store = MemoryStore::new();
let _ = VerificationMachine::new(alice, Arc::new(Box::new(store))); let _ = VerificationMachine::new(alice, Store::new(Box::new(store)));
} }
#[tokio::test] #[tokio::test]

View File

@ -34,7 +34,7 @@ use matrix_sdk_common::{
use crate::{ use crate::{
identities::{LocalTrust, ReadOnlyDevice, UserIdentities}, identities::{LocalTrust, ReadOnlyDevice, UserIdentities},
store::{CryptoStore, CryptoStoreError}, store::{CryptoStoreError, Store},
Account, ToDeviceRequest, Account, ToDeviceRequest,
}; };
@ -47,7 +47,7 @@ use sas_state::{
/// Short authentication string object. /// Short authentication string object.
pub struct Sas { pub struct Sas {
inner: Arc<Mutex<InnerSas>>, inner: Arc<Mutex<InnerSas>>,
store: Arc<Box<dyn CryptoStore>>, store: Store,
account: Account, account: Account,
other_device: ReadOnlyDevice, other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
@ -104,7 +104,7 @@ impl Sas {
pub(crate) fn start( pub(crate) fn start(
account: Account, account: Account,
other_device: ReadOnlyDevice, other_device: ReadOnlyDevice,
store: Arc<Box<dyn CryptoStore>>, store: Store,
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
) -> (Sas, StartEventContent) { ) -> (Sas, StartEventContent) {
let (inner, content) = InnerSas::start( let (inner, content) = InnerSas::start(
@ -139,7 +139,7 @@ impl Sas {
pub(crate) fn from_start_event( pub(crate) fn from_start_event(
account: Account, account: Account,
other_device: ReadOnlyDevice, other_device: ReadOnlyDevice,
store: Arc<Box<dyn CryptoStore>>, store: Store,
event: &ToDeviceEvent<StartEventContent>, event: &ToDeviceEvent<StartEventContent>,
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
) -> Result<Sas, AnyToDeviceEventContent> { ) -> Result<Sas, AnyToDeviceEventContent> {
@ -646,7 +646,7 @@ impl InnerSas {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::{convert::TryFrom, sync::Arc}; use std::convert::TryFrom;
use matrix_sdk_common::{ use matrix_sdk_common::{
events::{EventContent, ToDeviceEvent}, events::{EventContent, ToDeviceEvent},
@ -654,7 +654,7 @@ mod test {
}; };
use crate::{ use crate::{
store::{CryptoStore, MemoryStore}, store::{MemoryStore, Store},
verification::test::{get_content_from_request, wrap_any_to_device_content}, verification::test::{get_content_from_request, wrap_any_to_device_content},
Account, ReadOnlyDevice, Account, ReadOnlyDevice,
}; };
@ -776,8 +776,8 @@ mod test {
let bob = Account::new(&bob_id(), &bob_device_id()); let bob = Account::new(&bob_id(), &bob_device_id());
let bob_device = ReadOnlyDevice::from_account(&bob).await; let bob_device = ReadOnlyDevice::from_account(&bob).await;
let alice_store: Arc<Box<dyn CryptoStore>> = Arc::new(Box::new(MemoryStore::new())); let alice_store = Store::new(Box::new(MemoryStore::new()));
let bob_store: Arc<Box<dyn CryptoStore>> = Arc::new(Box::new(MemoryStore::new())); let bob_store = Store::new(Box::new(MemoryStore::new()));
bob_store bob_store
.save_devices(&[alice_device.clone()]) .save_devices(&[alice_device.clone()])