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
parent
849934b180
commit
24ce4881c7
|
@ -651,7 +651,7 @@ impl OwnUserIdentity {
|
|||
#[cfg(test)]
|
||||
pub(crate) mod test {
|
||||
use serde_json::json;
|
||||
use std::{convert::TryFrom, sync::Arc};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use matrix_sdk_common::{
|
||||
api::r0::keys::get_keys::Response as KeyQueryResponse, identifiers::user_id,
|
||||
|
@ -661,7 +661,7 @@ pub(crate) mod test {
|
|||
identities::{Device, ReadOnlyDevice},
|
||||
machine::test::response_from_file,
|
||||
olm::Account,
|
||||
store::MemoryStore,
|
||||
store::{MemoryStore, Store},
|
||||
verification::VerificationMachine,
|
||||
};
|
||||
|
||||
|
@ -884,7 +884,7 @@ pub(crate) mod test {
|
|||
|
||||
let verification_machine = VerificationMachine::new(
|
||||
Account::new(second.user_id(), second.device_id()),
|
||||
Arc::new(Box::new(MemoryStore::new())),
|
||||
Store::new(Box::new(MemoryStore::new())),
|
||||
);
|
||||
|
||||
let first = Device {
|
||||
|
|
|
@ -62,7 +62,7 @@ use super::{
|
|||
InboundGroupSession, OlmMessage, OutboundGroupSession,
|
||||
},
|
||||
requests::{IncomingResponse, KeysQueryRequest, OutgoingRequest, ToDeviceRequest},
|
||||
store::{CryptoStore, MemoryStore, Result as StoreResult},
|
||||
store::{CryptoStore, MemoryStore, Result as StoreResult, Store},
|
||||
verification::{Sas, VerificationMachine},
|
||||
};
|
||||
|
||||
|
@ -79,7 +79,7 @@ pub struct OlmMachine {
|
|||
/// Store for the encryption keys.
|
||||
/// Persists all the encryption keys so a client can resume the session
|
||||
/// without the need to create new keys.
|
||||
store: Arc<Box<dyn CryptoStore>>,
|
||||
store: Store,
|
||||
/// The currently active outbound group sessions.
|
||||
outbound_group_sessions: Arc<DashMap<RoomId, OutboundGroupSession>>,
|
||||
/// 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.
|
||||
pub fn new(user_id: &UserId, device_id: &DeviceId) -> Self {
|
||||
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);
|
||||
|
||||
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());
|
||||
|
||||
Ok(OlmMachine {
|
||||
|
|
|
@ -36,6 +36,7 @@ pub struct MemoryStore {
|
|||
users_for_key_query: Arc<DashSet<UserId>>,
|
||||
devices: DeviceStore,
|
||||
identities: Arc<DashMap<UserId, UserIdentities>>,
|
||||
values: Arc<DashMap<String, String>>,
|
||||
}
|
||||
|
||||
impl Default for MemoryStore {
|
||||
|
@ -47,6 +48,7 @@ impl Default for MemoryStore {
|
|||
users_for_key_query: Arc::new(DashSet::new()),
|
||||
devices: DeviceStore::new(),
|
||||
identities: Arc::new(DashMap::new()),
|
||||
values: Arc::new(DashMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,6 +166,15 @@ impl CryptoStore for MemoryStore {
|
|||
}
|
||||
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)]
|
||||
|
|
|
@ -49,9 +49,10 @@ pub use memorystore::MemoryStore;
|
|||
#[cfg(feature = "sqlite_cryptostore")]
|
||||
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 serde::{Deserialize, Serialize};
|
||||
use serde_json::Error as SerdeError;
|
||||
use thiserror::Error;
|
||||
use url::ParseError;
|
||||
|
@ -76,6 +77,44 @@ use super::{
|
|||
|
||||
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.
|
||||
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.
|
||||
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>>;
|
||||
}
|
||||
|
|
|
@ -1371,6 +1371,14 @@ impl CryptoStore for SqliteStore {
|
|||
|
||||
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))]
|
||||
|
|
|
@ -27,20 +27,20 @@ use matrix_sdk_common::{
|
|||
use super::sas::{content_to_request, Sas};
|
||||
use crate::{
|
||||
requests::{OutgoingRequest, ToDeviceRequest},
|
||||
store::{CryptoStore, CryptoStoreError},
|
||||
store::{CryptoStoreError, Store},
|
||||
Account, ReadOnlyDevice,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VerificationMachine {
|
||||
account: Account,
|
||||
pub(crate) store: Arc<Box<dyn CryptoStore>>,
|
||||
pub(crate) store: Store,
|
||||
verifications: Arc<DashMap<String, Sas>>,
|
||||
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
||||
}
|
||||
|
||||
impl VerificationMachine {
|
||||
pub(crate) fn new(account: Account, store: Arc<Box<dyn CryptoStore>>) -> Self {
|
||||
pub(crate) fn new(account: Account, store: Store) -> Self {
|
||||
Self {
|
||||
account,
|
||||
store,
|
||||
|
@ -221,7 +221,6 @@ mod test {
|
|||
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
|
@ -233,7 +232,7 @@ mod test {
|
|||
use super::{Sas, VerificationMachine};
|
||||
use crate::{
|
||||
requests::OutgoingRequests,
|
||||
store::{CryptoStore, MemoryStore},
|
||||
store::{CryptoStore, MemoryStore, Store},
|
||||
verification::test::{get_content_from_request, wrap_any_to_device_content},
|
||||
Account, ReadOnlyDevice,
|
||||
};
|
||||
|
@ -258,7 +257,7 @@ mod test {
|
|||
let alice = Account::new(&alice_id(), &alice_device_id());
|
||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
||||
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 alice_device = ReadOnlyDevice::from_account(&alice).await;
|
||||
|
@ -269,7 +268,7 @@ mod test {
|
|||
.await
|
||||
.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);
|
||||
machine
|
||||
.receive_event(&mut wrap_any_to_device_content(
|
||||
|
@ -286,7 +285,7 @@ mod test {
|
|||
fn create() {
|
||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
||||
let store = MemoryStore::new();
|
||||
let _ = VerificationMachine::new(alice, Arc::new(Box::new(store)));
|
||||
let _ = VerificationMachine::new(alice, Store::new(Box::new(store)));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -34,7 +34,7 @@ use matrix_sdk_common::{
|
|||
|
||||
use crate::{
|
||||
identities::{LocalTrust, ReadOnlyDevice, UserIdentities},
|
||||
store::{CryptoStore, CryptoStoreError},
|
||||
store::{CryptoStoreError, Store},
|
||||
Account, ToDeviceRequest,
|
||||
};
|
||||
|
||||
|
@ -47,7 +47,7 @@ use sas_state::{
|
|||
/// Short authentication string object.
|
||||
pub struct Sas {
|
||||
inner: Arc<Mutex<InnerSas>>,
|
||||
store: Arc<Box<dyn CryptoStore>>,
|
||||
store: Store,
|
||||
account: Account,
|
||||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
|
@ -104,7 +104,7 @@ impl Sas {
|
|||
pub(crate) fn start(
|
||||
account: Account,
|
||||
other_device: ReadOnlyDevice,
|
||||
store: Arc<Box<dyn CryptoStore>>,
|
||||
store: Store,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> (Sas, StartEventContent) {
|
||||
let (inner, content) = InnerSas::start(
|
||||
|
@ -139,7 +139,7 @@ impl Sas {
|
|||
pub(crate) fn from_start_event(
|
||||
account: Account,
|
||||
other_device: ReadOnlyDevice,
|
||||
store: Arc<Box<dyn CryptoStore>>,
|
||||
store: Store,
|
||||
event: &ToDeviceEvent<StartEventContent>,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> Result<Sas, AnyToDeviceEventContent> {
|
||||
|
@ -646,7 +646,7 @@ impl InnerSas {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::{convert::TryFrom, sync::Arc};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use matrix_sdk_common::{
|
||||
events::{EventContent, ToDeviceEvent},
|
||||
|
@ -654,7 +654,7 @@ mod test {
|
|||
};
|
||||
|
||||
use crate::{
|
||||
store::{CryptoStore, MemoryStore},
|
||||
store::{MemoryStore, Store},
|
||||
verification::test::{get_content_from_request, wrap_any_to_device_content},
|
||||
Account, ReadOnlyDevice,
|
||||
};
|
||||
|
@ -776,8 +776,8 @@ mod test {
|
|||
let bob = Account::new(&bob_id(), &bob_device_id());
|
||||
let bob_device = ReadOnlyDevice::from_account(&bob).await;
|
||||
|
||||
let alice_store: Arc<Box<dyn CryptoStore>> = Arc::new(Box::new(MemoryStore::new()));
|
||||
let bob_store: Arc<Box<dyn CryptoStore>> = Arc::new(Box::new(MemoryStore::new()));
|
||||
let alice_store = Store::new(Box::new(MemoryStore::new()));
|
||||
let bob_store = Store::new(Box::new(MemoryStore::new()));
|
||||
|
||||
bob_store
|
||||
.save_devices(&[alice_device.clone()])
|
||||
|
|
Loading…
Reference in New Issue