mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-07 23:44:53 -04:00
indexeddb: migrate name and format of backup_version
The name was stupid, and this was the only string that was stored in the legacy format; we can fix both problems with a cheeky migration.
This commit is contained in:
@@ -25,6 +25,7 @@ use crate::{
|
||||
|
||||
mod old_keys;
|
||||
mod v0_to_v5;
|
||||
mod v10_to_v11;
|
||||
mod v5_to_v7;
|
||||
mod v7;
|
||||
mod v7_to_v8;
|
||||
@@ -106,8 +107,12 @@ pub async fn open_and_upgrade_db(
|
||||
v8_to_v10::schema_delete(name).await?;
|
||||
}
|
||||
|
||||
if old_version < 11 {
|
||||
v10_to_v11::data_migrate(name, serializer).await?;
|
||||
}
|
||||
|
||||
// Open and return the DB (we know it's at the latest version)
|
||||
Ok(IdbDatabase::open_u32(name, 10)?.await?)
|
||||
Ok(IdbDatabase::open_u32(name, 11)?.await?)
|
||||
}
|
||||
|
||||
async fn db_version(name: &str) -> Result<u32, IndexeddbCryptoStoreError> {
|
||||
@@ -183,7 +188,10 @@ mod tests {
|
||||
|
||||
use super::{v0_to_v5, v7::InboundGroupSessionIndexedDbObject2};
|
||||
use crate::{
|
||||
crypto_store::{keys, migrations::*, InboundGroupSessionIndexedDbObject},
|
||||
crypto_store::{
|
||||
indexeddb_serializer::MaybeEncrypted, keys, migrations::*,
|
||||
InboundGroupSessionIndexedDbObject,
|
||||
},
|
||||
IndexeddbCryptoStore,
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(doc)]
|
||||
use crate::crypto_store::keys::BACKUP_VERSION_V1;
|
||||
|
||||
/// Old format of the `inbound_group_sessions` store which lacked indexes or
|
||||
/// a sensible structure
|
||||
pub const INBOUND_GROUP_SESSIONS_V1: &str = "inbound_group_sessions";
|
||||
@@ -20,3 +23,6 @@ pub const INBOUND_GROUP_SESSIONS_V1: &str = "inbound_group_sessions";
|
||||
/// JSON-encoding and arrays of ints instead of base64.
|
||||
/// Also lacked the `backed_up_to` property+index.
|
||||
pub const INBOUND_GROUP_SESSIONS_V2: &str = "inbound_group_sessions2";
|
||||
|
||||
/// An old name for [`BACKUP_VERSION_V1`].
|
||||
pub const BACKUP_KEY_V1: &str = "backup_key_v1";
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
//! Migration code that moves from `backup_keys.backup_key_v1` to
|
||||
//! `backup_keys.backup_version_v1`, switching to a new serialization format.
|
||||
|
||||
use indexed_db_futures::IdbQuerySource;
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::IdbTransactionMode;
|
||||
|
||||
use crate::crypto_store::{
|
||||
indexeddb_serializer::IndexeddbSerializer,
|
||||
keys,
|
||||
migrations::{old_keys, MigrationDb},
|
||||
};
|
||||
|
||||
/// Migrate data from `backup_keys.backup_key_v1` to
|
||||
/// `backup_keys.backup_version_v1`.
|
||||
pub(crate) async fn data_migrate(
|
||||
name: &str,
|
||||
serializer: &IndexeddbSerializer,
|
||||
) -> crate::crypto_store::Result<()> {
|
||||
let db = MigrationDb::new(name, 11).await?;
|
||||
let txn = db.transaction_on_one_with_mode(keys::BACKUP_KEYS, IdbTransactionMode::Readwrite)?;
|
||||
let store = txn.object_store(keys::BACKUP_KEYS)?;
|
||||
|
||||
let bv = store.get(&JsValue::from_str(old_keys::BACKUP_KEY_V1))?.await?;
|
||||
|
||||
let Some(bv) = bv else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// backup_key_v1 was only ever serialized with the legacy format. Also, it's a
|
||||
// string, so if we use `deserialize_value` on it, it will be incorrectly
|
||||
// handled as a new-format object.
|
||||
let bv: String = serializer.deserialize_legacy_value(bv)?;
|
||||
|
||||
// Re-serialize as new format, then store in the new field.
|
||||
let serialized = serializer.serialize_value(&bv)?;
|
||||
store.put_key_val(&JsValue::from_str(keys::BACKUP_VERSION_V1), &serialized)?.await?;
|
||||
store.delete(&JsValue::from_str(old_keys::BACKUP_KEY_V1))?.await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -90,7 +90,11 @@ mod keys {
|
||||
|
||||
// backup v1
|
||||
pub const BACKUP_KEYS: &str = "backup_keys";
|
||||
pub const BACKUP_KEY_V1: &str = "backup_key_v1";
|
||||
|
||||
/// Indexeddb key for the key backup version that [`RECOVERY_KEY_V1`]
|
||||
/// corresponds to.
|
||||
pub const BACKUP_VERSION_V1: &str = "backup_version_v1";
|
||||
|
||||
/// Indexeddb key for the backup decryption key.
|
||||
///
|
||||
/// Known, for historical reasons, as the recovery key. Not to be confused
|
||||
@@ -479,9 +483,10 @@ impl IndexeddbCryptoStore {
|
||||
}
|
||||
|
||||
if let Some(a) = &backup_version {
|
||||
indexeddb_changes
|
||||
.get(keys::BACKUP_KEYS)
|
||||
.put(JsValue::from_str(keys::BACKUP_KEY_V1), self.serializer.serialize_value(&a)?);
|
||||
indexeddb_changes.get(keys::BACKUP_KEYS).put(
|
||||
JsValue::from_str(keys::BACKUP_VERSION_V1),
|
||||
self.serializer.serialize_value(&a)?,
|
||||
);
|
||||
}
|
||||
|
||||
if !changes.sessions.is_empty() {
|
||||
@@ -1208,7 +1213,7 @@ impl_crypto_store! {
|
||||
let store = tx.object_store(keys::BACKUP_KEYS)?;
|
||||
|
||||
let backup_version = store
|
||||
.get(&JsValue::from_str(keys::BACKUP_KEY_V1))?
|
||||
.get(&JsValue::from_str(keys::BACKUP_VERSION_V1))?
|
||||
.await?
|
||||
.map(|i| self.serializer.deserialize_value(i))
|
||||
.transpose()?;
|
||||
|
||||
Reference in New Issue
Block a user