From addb455d16bec9caff13b455b92de7ffaca05557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 30 Apr 2020 17:10:12 +0200 Subject: [PATCH] crypto: Add all the missing docs and deny missing docs from now on. --- matrix_sdk_crypto/src/error.rs | 49 +++++- matrix_sdk_crypto/src/lib.rs | 11 ++ matrix_sdk_crypto/src/machine.rs | 193 +++++++++++++++++---- matrix_sdk_crypto/src/memory_stores.rs | 1 + matrix_sdk_crypto/src/olm.rs | 15 +- matrix_sdk_crypto/src/store/memorystore.rs | 10 +- matrix_sdk_crypto/src/store/mod.rs | 53 ++++-- matrix_sdk_crypto/src/store/sqlite.rs | 37 +++- 8 files changed, 298 insertions(+), 71 deletions(-) diff --git a/matrix_sdk_crypto/src/error.rs b/matrix_sdk_crypto/src/error.rs index cdc57119..fac57a56 100644 --- a/matrix_sdk_crypto/src/error.rs +++ b/matrix_sdk_crypto/src/error.rs @@ -19,36 +19,59 @@ use thiserror::Error; use super::store::CryptoStoreError; -pub type OlmResult = std::result::Result; -pub type MegolmResult = std::result::Result; -pub type VerificationResult = std::result::Result; +pub type OlmResult = Result; +pub type MegolmResult = Result; +/// Error representing a failure during a device to device cryptographic +/// operation. #[derive(Error, Debug)] pub enum OlmError { + /// The event that should have been decrypted is malformed. #[error(transparent)] EventError(#[from] EventError), + + /// The received decrypted event couldn't be deserialized. #[error(transparent)] JsonError(#[from] SerdeError), + + /// The underlying Olm session operation returned an error. #[error("can't finish Olm Session operation {0}")] OlmSession(#[from] OlmSessionError), + + /// The underlying group session operation returned an error. #[error("can't finish Olm Session operation {0}")] OlmGroupSession(#[from] OlmGroupSessionError), + + /// The storage layer returned an error. #[error("failed to read or write to the crypto store {0}")] Store(#[from] CryptoStoreError), + + /// The session with a device has become corrupted. #[error("decryption failed likely because a Olm session was wedged")] SessionWedged, } +/// Error representing a failure during a group encryption operation. #[derive(Error, Debug)] pub enum MegolmError { - #[error("decryption failed because the session to decrypt the message is missing")] - MissingSession, - #[error(transparent)] - JsonError(#[from] SerdeError), + /// The event that should have been decrypted is malformed. #[error(transparent)] EventError(#[from] EventError), + + /// The received decrypted event couldn't be deserialized. + #[error(transparent)] + JsonError(#[from] SerdeError), + + /// Decryption failed because the session needed to decrypt the event is + /// missing. + #[error("decryption failed because the session to decrypt the message is missing")] + MissingSession, + + /// The underlying group session operation returned an error. #[error("can't finish Olm group session operation {0}")] OlmGroupSession(#[from] OlmGroupSessionError), + + /// The storage layer returned an error. #[error(transparent)] Store(#[from] CryptoStoreError), } @@ -57,30 +80,40 @@ pub enum MegolmError { pub enum EventError { #[error("the Olm message has a unsupported type")] UnsupportedOlmType, + #[error("the Encrypted message has been encrypted with a unsupported algorithm.")] UnsupportedAlgorithm, + #[error("the provided JSON value isn't an object")] NotAnObject, + #[error("the Encrypted message doesn't contain a ciphertext for our device")] MissingCiphertext, + #[error("the Encrypted message is missing the signing key of the sender")] MissingSigningKey, + #[error("the Encrypted message is missing the field {0}")] MissingField(String), + #[error("the sender of the plaintext doesn't match the sender of the encrypted message.")] MissmatchedSender, + #[error("the keys of the message don't match the keys in our database.")] MissmatchedKeys, } #[derive(Error, Debug)] -pub enum SignatureError { +pub(crate) enum SignatureError { #[error("the provided JSON value isn't an object")] NotAnObject, + #[error("the provided JSON object doesn't contain a signatures field")] NoSignatureFound, + #[error("the provided JSON object can't be converted to a canonical representation")] CanonicalJsonError(CjsonError), + #[error("the signature didn't match the provided key")] VerificationError, } diff --git a/matrix_sdk_crypto/src/lib.rs b/matrix_sdk_crypto/src/lib.rs index 1d4065f7..3e65406a 100644 --- a/matrix_sdk_crypto/src/lib.rs +++ b/matrix_sdk_crypto/src/lib.rs @@ -15,6 +15,17 @@ //! This is the encryption part of the matrix-sdk. It contains a state machine //! that will aid in adding encryption support to a client library. +#![deny( + missing_debug_implementations, + dead_code, + missing_docs, + trivial_casts, + trivial_numeric_casts, + unused_extern_crates, + unused_import_braces, + unused_qualifications +)] + mod device; mod error; mod machine; diff --git a/matrix_sdk_crypto/src/machine.rs b/matrix_sdk_crypto/src/machine.rs index 038e1286..30f84d6c 100644 --- a/matrix_sdk_crypto/src/machine.rs +++ b/matrix_sdk_crypto/src/machine.rs @@ -21,17 +21,15 @@ use std::result::Result as StdResult; use std::sync::atomic::{AtomicU64, Ordering}; use uuid::Uuid; -use super::error::{ - EventError, MegolmError, MegolmResult, OlmError, OlmResult, SignatureError, VerificationResult, -}; +use super::error::{EventError, MegolmError, MegolmResult, OlmError, OlmResult, SignatureError}; use super::olm::{ Account, GroupSessionKey, IdentityKeys, InboundGroupSession, OlmMessage, OlmUtility, OutboundGroupSession, Session, }; use super::store::memorystore::MemoryStore; #[cfg(feature = "sqlite-cryptostore")] -use super::store::{sqlite::SqliteStore, Result as StoreError}; -use super::{device::Device, CryptoStore}; +use super::store::sqlite::SqliteStore; +use super::{device::Device, store::Result as StoreError, CryptoStore}; use matrix_sdk_types::api; use matrix_sdk_types::events::{ @@ -60,8 +58,13 @@ use cjson; use serde_json::{json, Value}; use tracing::{debug, error, info, instrument, trace, warn}; +/// A map from the algorithm and device id to a one-time key. +/// +/// These keys need to be periodically uploaded to the server. pub type OneTimeKeys = BTreeMap; +/// State machine implementation of the Olm/Megolm encryption protocol used for +/// Matrix end to end encryption. pub struct OlmMachine { /// The unique user id that owns this account. user_id: UserId, @@ -75,7 +78,7 @@ pub struct OlmMachine { /// client to upload new keys. uploaded_signed_key_count: Option, /// Store for the encryption keys. - /// Persists all the encrytpion 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. store: Box, /// Set of users that we need to query keys for. This is a subset of @@ -103,7 +106,16 @@ impl OlmMachine { const MAX_TO_DEVICE_MESSAGES: usize = 20; - /// Create a new account. + /// Create a new memory based OlmMachine. + /// + /// The created machine will keep the encryption keys only in memory and + /// once the object is dropped the keys will be lost. + /// + /// # Arguments + /// + /// * `user_id` - The unique id of the user that owns this machine. + /// + /// * `device_id` - The unique id of the device that owns this machine. pub fn new(user_id: &UserId, device_id: &str) -> Self { OlmMachine { user_id: user_id.clone(), @@ -116,17 +128,28 @@ impl OlmMachine { } } - #[cfg(feature = "sqlite-cryptostore")] - #[instrument(skip(path, passphrase))] - pub async fn new_with_sqlite_store>( + /// Create a new OlmMachine with the given `CryptoStore`. + /// + /// The created machine will keep the encryption keys only in memory and + /// once the object is dropped the keys will be lost. + /// + /// If the store already contains encryption keys for the given user/device + /// pair those will be re-used. Otherwise new ones will be created and + /// stored. + /// + /// # Arguments + /// + /// * `user_id` - The unique id of the user that owns this machine. + /// + /// * `device_id` - The unique id of the device that owns this machine. + /// + /// * `store` - A `Cryptostore` implementation that will be used to store + /// the encryption keys. + pub async fn new_with_store( user_id: &UserId, device_id: &str, - path: P, - passphrase: String, + mut store: impl CryptoStore + 'static, ) -> StoreError { - let mut store = - SqliteStore::open_with_passphrase(&user_id, device_id, path, passphrase).await?; - let account = match store.load_account().await? { Some(a) => { debug!("Restored account"); @@ -149,6 +172,29 @@ impl OlmMachine { }) } + #[cfg(feature = "sqlite-cryptostore")] + #[instrument(skip(path, passphrase))] + /// Create a new machine with the default crypto store. + /// + /// The default store uses a SQLite database to store the encryption keys. + /// + /// # Arguments + /// + /// * `user_id` - The unique id of the user that owns this machine. + /// + /// * `device_id` - The unique id of the device that owns this machine. + pub async fn new_with_default_store>( + user_id: &UserId, + device_id: &str, + path: P, + passphrase: String, + ) -> StoreError { + let store = + SqliteStore::open_with_passphrase(&user_id, device_id, path, passphrase).await?; + + OlmMachine::new_with_store(user_id, device_id, store).await + } + /// The unique user id that owns this identity. pub fn user_id(&self) -> &UserId { &self.user_id @@ -182,6 +228,7 @@ impl OlmMachine { } } + /// Update the count of one-time keys that are currently on the server. fn update_key_count(&mut self, count: u64) { match &self.uploaded_signed_key_count { Some(c) => c.store(count, Ordering::Relaxed), @@ -225,6 +272,25 @@ impl OlmMachine { Ok(()) } + /// Get the user/device pairs for which no Olm session exists. + /// + /// Returns a map from the user id, to a map from the device id to a key + /// algorithm. + /// + /// This can be used to make a key claiming request to the server. + /// + /// Sessions need to be established between devices so group sessions for a + /// room can be shared with them. + /// + /// This should be called every time a group session needs to be shared. + /// + /// The response of a successful key claiming requests needs to be passed to + /// the `OlmMachine` with the `receive_keys_claim_response()`. + /// + /// # Arguments + /// + /// `users` - The list of users that we should check if we lack a session + /// with one of their devices. pub async fn get_missing_sessions( &mut self, users: impl Iterator, @@ -251,11 +317,11 @@ impl OlmMachine { if is_missing { if !missing.contains_key(user_id) { - missing.insert(user_id.clone(), BTreeMap::new()); + let _ = missing.insert(user_id.clone(), BTreeMap::new()); } let user_map = missing.get_mut(user_id).unwrap(); - user_map.insert( + let _ = user_map.insert( device.device_id().to_owned(), KeyAlgorithm::SignedCurve25519, ); @@ -266,6 +332,12 @@ impl OlmMachine { Ok(missing) } + /// Receive a successful key claim response and create new Olm sessions with + /// the claimed keys. + /// + /// # Arguments + /// + /// * `response` - The response containing the claimed one-time keys. pub async fn receive_keys_claim_response( &mut self, response: &keys::claim_keys::Response, @@ -620,7 +692,7 @@ impl OlmMachine { device_id: &str, user_key: &str, json: &mut Value, - ) -> VerificationResult<()> { + ) -> Result<(), SignatureError> { let json_object = json.as_object_mut().ok_or(SignatureError::NotAnObject)?; let unsigned = json_object.remove("unsigned"); let signatures = json_object.remove("signatures"); @@ -685,7 +757,11 @@ impl OlmMachine { Ok((device_keys, one_time_keys)) } - async fn try_decrypt_olm_event( + /// Try to decrypt an Olm message. + /// + /// This try to decrypt an Olm message using all the sessions we share + /// have with the given sender. + async fn try_decrypt_olm_message( &mut self, sender: &UserId, sender_key: &str, @@ -755,10 +831,10 @@ impl OlmMachine { ) -> OlmResult<(EventJson, String)> { // First try to decrypt using an existing session. let plaintext = if let Some(p) = self - .try_decrypt_olm_event(sender, sender_key, &message) + .try_decrypt_olm_message(sender, sender_key, &message) .await? { - // Decryption succeeded, destructure the plaintext out of the + // Decryption succeeded, de-structure the plaintext out of the // Option. p } else { @@ -815,6 +891,8 @@ impl OlmMachine { Ok(self.parse_decrypted_to_device_event(sender, &plaintext)?) } + /// Parse a decrypted Olm message, check that the plaintext and encrypted + /// senders match and that the message was meant for us. fn parse_decrypted_to_device_event( &self, sender: &UserId, @@ -913,7 +991,7 @@ impl OlmMachine { debug!("Decrypted a to-device event {:?}", decrypted_event); - // Handle the decrypted event, e.g. fetch out megolm sessions out of + // Handle the decrypted event, e.g. fetch out Megolm sessions out of // the event. self.handle_decrypted_to_device_event( &content.sender_key, @@ -929,6 +1007,7 @@ impl OlmMachine { } } + /// Create a group session from a room key and add it to our crypto store. async fn add_room_key( &mut self, sender_key: &str, @@ -945,7 +1024,7 @@ impl OlmMachine { &event.content.room_id, session_key, )?; - self.store.save_inbound_group_session(session).await?; + let _ = self.store.save_inbound_group_session(session).await?; Ok(()) } _ => { @@ -958,6 +1037,10 @@ impl OlmMachine { } } + /// Create a new outbound group session. + /// + /// This also creates a matching inbound group session and saves that one in + /// the store. async fn create_outbound_group_session(&mut self, room_id: &RoomId) -> OlmResult<()> { let session = OutboundGroupSession::new(room_id); let identity_keys = self.account.identity_keys(); @@ -971,15 +1054,38 @@ impl OlmMachine { &room_id, session.session_key().await, )?; - self.store + let _ = self + .store .save_inbound_group_session(inbound_session) .await?; - self.outbound_group_sessions + let _ = self + .outbound_group_sessions .insert(room_id.to_owned(), session); Ok(()) } + /// Encrypt a room message for the given room. + /// + /// Beware that a group session needs to be shared before this method can be + /// called using the `share_group_session()` method. + /// + /// Since group sessions can expire or become invalid if the room membership + /// changes client authors should check with the + /// `should_share_group_session()` method if a new group session needs to + /// be shared. + /// + /// # Arguments + /// + /// * `room_id` - The id of the room for which the message should be + /// encrypted. + /// + /// * `content` - The plaintext content of the message that should be + /// encrypted. + /// + /// # Panics + /// + /// Panics if a group session for the given room wasn't shared beforehand. pub async fn encrypt( &self, room_id: &RoomId, @@ -1023,6 +1129,7 @@ impl OlmMachine { )) } + /// Encrypt some JSON content using the given Olm session. async fn olm_encrypt( &mut self, mut session: Session, @@ -1155,7 +1262,7 @@ impl OlmMachine { user_map.push((session.clone(), device.clone())); } else { warn!( - "Trying to encrypt a megolm session for user + "Trying to encrypt a Megolm session for user {} on device {}, but no Olm session is found", user_id, device.device_id() @@ -1211,6 +1318,15 @@ impl OlmMachine { // TODO } + /// Receive and properly handle a decrypted to-device event. + /// + /// # Arguments + /// + /// * `sender_key` - The sender (curve25519) key of the event sender. + /// + /// * `signing_key` - The signing (ed25519) key of the event sender. + /// + /// * `event` - The decrypted to-device event. async fn handle_decrypted_to_device_event( &mut self, sender_key: &str, @@ -1246,14 +1362,17 @@ impl OlmMachine { // TODO handle to-device verification events here. } - #[instrument(skip(response))] /// Handle a sync response and update the internal state of the Olm machine. /// - /// This will decrypt to-device events but will not touch room messages. + /// This will decrypt to-device events but will not touch events in the room + /// timeline. + /// + /// To decrypt an event from the room timeline call `decrypt_room_event()`. /// /// # Arguments /// /// * `response` - The sync latest sync response. + #[instrument(skip(response))] pub async fn receive_sync_response(&mut self, response: &mut SyncResponse) { let one_time_key_count = response .device_one_time_keys_count @@ -1304,6 +1423,11 @@ impl OlmMachine { } } + /// Decrypt an event from a room timeline. + /// + /// # Arguments + /// + /// * `event` - The event that should be decrypted. pub async fn decrypt_room_event( &mut self, event: &EncryptedEvent, @@ -1319,7 +1443,7 @@ impl OlmMachine { .store .get_inbound_group_session(&room_id, &content.sender_key, &content.session_id) .await?; - // TODO check if the olm session is wedged and re-request the key. + // TODO check if the Olm session is wedged and re-request the key. let session = session.ok_or(MegolmError::MissingSession)?; let (plaintext, _) = session.decrypt(content.ciphertext.clone()).await?; @@ -1349,7 +1473,7 @@ impl OlmMachine { ); let decrypted_event = serde_json::from_value::>(decrypted_value)?; - trace!("Successfully decrypted megolm event {:?}", decrypted_event); + trace!("Successfully decrypted Megolm event {:?}", decrypted_event); // TODO set the encryption info on the event (is it verified, was it // decrypted, sender key...) @@ -1358,6 +1482,11 @@ impl OlmMachine { /// Update the tracked users. /// + /// # Arguments + /// + /// * `users` - An iterator over user ids that should be marked for + /// tracking. + /// /// This will only not already seen users for a key query and user tracking. /// If the user is already known to the Olm machine it will not be /// considered for a key query. @@ -1384,12 +1513,14 @@ impl OlmMachine { } } - /// Should a key query be done. + /// Should the client perform a key query request. pub fn should_query_keys(&self) -> bool { !self.users_for_key_query.is_empty() } /// Get the set of users that we need to query keys for. + /// + /// Returns a hash set of users that need to be queried for keys. pub fn users_for_key_query(&self) -> HashSet { self.users_for_key_query.clone() } diff --git a/matrix_sdk_crypto/src/memory_stores.rs b/matrix_sdk_crypto/src/memory_stores.rs index af880754..2dd20511 100644 --- a/matrix_sdk_crypto/src/memory_stores.rs +++ b/matrix_sdk_crypto/src/memory_stores.rs @@ -133,6 +133,7 @@ pub struct DeviceStore { } /// A read only view over all devices belonging to a user. +#[derive(Debug)] pub struct UserDevices { entries: ReadOnlyView, } diff --git a/matrix_sdk_crypto/src/olm.rs b/matrix_sdk_crypto/src/olm.rs index 80264438..c6294177 100644 --- a/matrix_sdk_crypto/src/olm.rs +++ b/matrix_sdk_crypto/src/olm.rs @@ -38,9 +38,10 @@ pub use olm_rs::{ use matrix_sdk_types::api::r0::keys::SignedKey; use matrix_sdk_types::identifiers::RoomId; -/// The Olm account. +/// Account holding identity keys for which sessions can be created. +/// /// An account is the central identity for encrypted communication between two -/// devices. It holds the two identity key pairs for a device. +/// devices. #[derive(Clone)] pub struct Account { inner: Arc>, @@ -66,7 +67,7 @@ impl Default for Account { } impl Account { - /// Create a new account. + /// Create a fresh new account, this will generate the identity key-pair. pub fn new() -> Self { let account = OlmAccount::new(); let identity_keys = account.parsed_identity_keys(); @@ -242,10 +243,8 @@ impl PartialEq for Account { } } -/// The Olm Session. -/// -/// Sessions are used to exchange encrypted messages between two -/// accounts/devices. +/// Cryptographic session that enables secure communication between two +/// `Account`s #[derive(Clone)] pub struct Session { inner: Arc>, @@ -378,7 +377,7 @@ impl PartialEq for Session { /// The private session key of a group session. /// Can be used to create a new inbound group session. -#[derive(Clone, Serialize, Zeroize)] +#[derive(Clone, Debug, Serialize, Zeroize)] #[zeroize(drop)] pub struct GroupSessionKey(pub String); diff --git a/matrix_sdk_crypto/src/store/memorystore.rs b/matrix_sdk_crypto/src/store/memorystore.rs index f274f88d..3cd422c9 100644 --- a/matrix_sdk_crypto/src/store/memorystore.rs +++ b/matrix_sdk_crypto/src/store/memorystore.rs @@ -54,7 +54,7 @@ impl CryptoStore for MemoryStore { async fn save_sessions(&mut self, sessions: &[Session]) -> Result<()> { for session in sessions { - self.sessions.add(session.clone()).await; + let _ = self.sessions.add(session.clone()).await; } Ok(()) @@ -93,7 +93,7 @@ impl CryptoStore for MemoryStore { } async fn delete_device(&self, device: Device) -> Result<()> { - self.devices.remove(device.user_id(), device.device_id()); + let _ = self.devices.remove(device.user_id(), device.device_id()); Ok(()) } @@ -103,7 +103,7 @@ impl CryptoStore for MemoryStore { async fn save_devices(&self, devices: &[Device]) -> Result<()> { for device in devices { - self.devices.add(device.clone()); + let _ = self.devices.add(device.clone()); } Ok(()) @@ -157,7 +157,7 @@ mod test { .unwrap(); let mut store = MemoryStore::new(); - store + let _ = store .save_inbound_group_session(inbound.clone()) .await .unwrap(); @@ -212,6 +212,6 @@ mod test { let tracked_users = store.tracked_users(); - tracked_users.contains(device.user_id()); + let _ = tracked_users.contains(device.user_id()); } } diff --git a/matrix_sdk_crypto/src/store/mod.rs b/matrix_sdk_crypto/src/store/mod.rs index 85dec8ed..8d2a7655 100644 --- a/matrix_sdk_crypto/src/store/mod.rs +++ b/matrix_sdk_crypto/src/store/mod.rs @@ -37,33 +37,54 @@ pub mod sqlite; use sqlx::Error as SqlxError; #[derive(Error, Debug)] +/// The crypto store's error type. pub enum CryptoStoreError { - #[error("can't read or write from the store")] - Io(#[from] IoError), - #[error("can't finish Olm Account operation {0}")] - OlmAccount(#[from] OlmAccountError), - #[error("can't finish Olm Session operation {0}")] - OlmSession(#[from] OlmSessionError), - #[error("can't finish Olm GruoupSession operation {0}")] - OlmGroupSession(#[from] OlmGroupSessionError), - #[error("URL can't be parsed")] - UrlParse(#[from] ParseError), - #[error("error serializing data for the database")] - Serialization(#[from] SerdeError), - #[error("can't load session timestamps")] - SessionTimestampError, - #[error("can't save/load sessions or group sessions in the store before a account is stored")] + /// The account that owns the sessions, group sessions, and devices wasn't + /// found. + #[error("can't save/load sessions or group sessions in the store before an account is stored")] AccountUnset, + + /// SQL error occurred. // TODO flatten the SqlxError to make it easier for other store // implementations. #[cfg(feature = "sqlite-cryptostore")] - #[error("database error")] + #[error(transparent)] DatabaseError(#[from] SqlxError), + + /// An IO error occurred. + #[error(transparent)] + Io(#[from] IoError), + + /// The underlying Olm Account operation returned an error. + #[error(transparent)] + OlmAccount(#[from] OlmAccountError), + + /// The underlying Olm session operation returned an error. + #[error(transparent)] + OlmSession(#[from] OlmSessionError), + + /// The underlying Olm group session operation returned an error. + #[error(transparent)] + OlmGroupSession(#[from] OlmGroupSessionError), + + /// A session time-stamp couldn't be loaded. + #[error("can't load session timestamps")] + SessionTimestampError, + + /// The store failed to (de)serialize a data type. + #[error(transparent)] + Serialization(#[from] SerdeError), + + /// An error occurred while parsing an URL. + #[error(transparent)] + UrlParse(#[from] ParseError), } pub type Result = std::result::Result; #[async_trait] +/// Trait abstracting a store that the `OlmMachine` uses to store cryptographic +/// keys. pub trait CryptoStore: Debug + Send + Sync { /// Load an account that was previously stored. async fn load_account(&mut self) -> Result>; diff --git a/matrix_sdk_crypto/src/store/sqlite.rs b/matrix_sdk_crypto/src/store/sqlite.rs index bf73c0d7..0c5b263a 100644 --- a/matrix_sdk_crypto/src/store/sqlite.rs +++ b/matrix_sdk_crypto/src/store/sqlite.rs @@ -35,6 +35,7 @@ use matrix_sdk_types::api::r0::keys::KeyAlgorithm; use matrix_sdk_types::events::Algorithm; use matrix_sdk_types::identifiers::{DeviceId, RoomId, UserId}; +/// SQLite based implementation of a `CryptoStore`. pub struct SqliteStore { user_id: Arc, device_id: Arc, @@ -53,6 +54,17 @@ pub struct SqliteStore { static DATABASE_NAME: &str = "matrix-sdk-crypto.db"; impl SqliteStore { + /// Open a new `SqliteStore`. + /// + /// # Arguments + /// + /// * `user_id` - The unique id of the user for which the store should be + /// opened. + /// + /// * `device_id` - The unique id of the device for which the store should + /// be opened. + /// + /// * `path` - The path where the database file should reside in. pub async fn open>( user_id: &UserId, device_id: &str, @@ -61,6 +73,20 @@ impl SqliteStore { SqliteStore::open_helper(user_id, device_id, path, None).await } + /// Open a new `SqliteStore`. + /// + /// # Arguments + /// + /// * `user_id` - The unique id of the user for which the store should be + /// opened. + /// + /// * `device_id` - The unique id of the device for which the store should + /// be opened. + /// + /// * `path` - The path where the database file should reside in. + /// + /// * `passphrase` - The passphrase that should be used to securely store + /// the encryption keys. pub async fn open_with_passphrase>( user_id: &UserId, device_id: &str, @@ -321,7 +347,8 @@ impl SqliteStore { for row in rows { let device_row_id = row.0; - let user_id = if let Ok(u) = UserId::try_from(&row.1 as &str) { + let user_id: &str = &row.1; + let user_id = if let Ok(u) = UserId::try_from(user_id) { u } else { continue; @@ -339,7 +366,10 @@ impl SqliteStore { let algorithms = algorithm_rows .iter() - .map(|row| Algorithm::from(&row.0 as &str)) + .map(|row| { + let algorithm: &str = &row.0; + Algorithm::from(algorithm) + }) .collect::>(); let key_rows: Vec<(String, String)> = @@ -351,7 +381,8 @@ impl SqliteStore { let mut keys = BTreeMap::new(); for row in key_rows { - let algorithm = if let Ok(a) = KeyAlgorithm::try_from(&row.0 as &str) { + let algorithm: &str = &row.0; + let algorithm = if let Ok(a) = KeyAlgorithm::try_from(algorithm) { a } else { continue;