From ebd85ebaa2ed2279add337638f9f45535df3537a Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Thu, 28 Apr 2022 17:31:09 +0200 Subject: [PATCH] feat(indexeddb): Add support for key backup v1 --- .../matrix-sdk-indexeddb/src/cryptostore.rs | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-indexeddb/src/cryptostore.rs b/crates/matrix-sdk-indexeddb/src/cryptostore.rs index b1d9b4979..408dbb334 100644 --- a/crates/matrix-sdk-indexeddb/src/cryptostore.rs +++ b/crates/matrix-sdk-indexeddb/src/cryptostore.rs @@ -65,6 +65,11 @@ mod KEYS { pub const STORE_CIPHER: &str = "store_cipher"; pub const ACCOUNT: &str = "account"; pub const PRIVATE_IDENTITY: &str = "private_identity"; + + // BACKUP v1 + pub const BACKUP_KEYS: &str = "backup_keys"; + pub const BACKUP_KEY_V1: &str = "backup_key_v1"; + pub const RECOVERY_KEY_V1: &str = "recovery_key_v1"; } /// An in-memory only store that will forget all the E2EE key once it's dropped. @@ -159,6 +164,8 @@ impl IndexeddbStore { db.create_object_store(KEYS::OUTGOING_SECRET_REQUESTS)?; db.create_object_store(KEYS::UNSENT_SECRET_REQUESTS)?; db.create_object_store(KEYS::SECRET_REQUESTS_BY_INFO)?; + + db.create_object_store(KEYS::BACKUP_KEYS)?; } Ok(()) })); @@ -270,6 +277,7 @@ impl IndexeddbStore { async fn save_changes(&self, changes: Changes) -> Result<()> { let mut stores: Vec<&str> = [ (changes.account.is_some() || changes.private_identity.is_some(), KEYS::CORE), + (changes.recovery_key.is_some() || changes.backup_version.is_some(), KEYS::BACKUP_KEYS), (!changes.sessions.is_empty(), KEYS::SESSION), ( !changes.devices.new.is_empty() @@ -311,6 +319,9 @@ impl IndexeddbStore { let private_identity_pickle = if let Some(i) = changes.private_identity { Some(i.pickle().await?) } else { None }; + let recovery_key_pickle = changes.recovery_key; + let backup_version = changes.backup_version; + if let Some(a) = &account_pickle { tx.object_store(KEYS::CORE)? .put_key_val(&JsValue::from_str(KEYS::ACCOUNT), &self.serialize_value(&a)?)?; @@ -323,6 +334,17 @@ impl IndexeddbStore { )?; } + if let Some(a) = &recovery_key_pickle { + tx.object_store(KEYS::BACKUP_KEYS)? + .put_key_val(&JsValue::from_str(KEYS::RECOVERY_KEY_V1), &self.serialize_value(&a)?)?; + } + + if let Some(a) = &backup_version { + tx.object_store(KEYS::BACKUP_KEYS)? + .put_key_val(&JsValue::from_str(KEYS::BACKUP_KEY_V1), &self.serialize_value(&a)?)?; + } + + if !changes.sessions.is_empty() { let sessions = tx.object_store(KEYS::SESSION)?; @@ -834,6 +856,34 @@ impl IndexeddbStore { tx.await.into_result().map_err(|e| e.into()) } + + async fn load_backup_keys(&self) -> Result { + let key = { + let tx = self + .inner + .transaction_on_one_with_mode( + KEYS::BACKUP_KEYS, + IdbTransactionMode::Readonly, + )?; + let store = tx.object_store(KEYS::BACKUP_KEYS)?; + + let backup_version = store + .get(&JsValue::from_str(KEYS::BACKUP_KEY_V1))? + .await? + .map(|i| self.deserialize_value(i)) + .transpose()?; + + let recovery_key = store + .get(&JsValue::from_str(KEYS::RECOVERY_KEY_V1))? + .await? + .map(|i| self.deserialize_value(i)) + .transpose()?; + + BackupKeys { backup_version, recovery_key } + }; + + Ok(key) + } } #[async_trait(?Send)] @@ -924,9 +974,8 @@ impl CryptoStore for IndexeddbStore { self.users_for_key_query() } - #[allow(clippy::todo)] async fn load_backup_keys(&self) -> Result { - todo!() + self.load_backup_keys().await.map_err(|e| e.into()) } async fn update_tracked_user(