use indexed_db_futures::{
Build, error::OpenDbError, query_source::QuerySource, transaction::TransactionMode,
};
use matrix_sdk_crypto::olm::InboundGroupSession;
use tracing::{debug, info};
use wasm_bindgen::JsValue;
use crate::{
IndexeddbCryptoStoreError,
crypto_store::{
Result,
migrations::{MigrationDb, do_schema_upgrade, old_keys, v7},
},
serializer::SafeEncodeSerializer,
};
pub(crate) async fn data_migrate(name: &str, serializer: &SafeEncodeSerializer) -> Result<()> {
let db = MigrationDb::new(name, 8).await?;
let txn = db
.transaction(old_keys::INBOUND_GROUP_SESSIONS_V2)
.with_mode(TransactionMode::Readwrite)
.build()?;
let store = txn.object_store(old_keys::INBOUND_GROUP_SESSIONS_V2)?;
let row_count = store.count().await?;
info!(row_count, "Fixing inbound group session data keys");
if let Some(mut cursor) = store.open_cursor().await? {
let mut idx = 0;
let mut updated = 0;
let mut deleted = 0;
while let Some(value) = cursor.next_record::<JsValue>().await? {
idx += 1;
let old_key =
cursor.key::<JsValue>()?.ok_or(matrix_sdk_crypto::CryptoStoreError::Backend(
"inbound_group_sessions2 cursor has no key".into(),
))?;
let idb_object: v7::InboundGroupSessionIndexedDbObject2 =
serde_wasm_bindgen::from_value(value)?;
let pickled_session =
serializer.deserialize_value_from_bytes(&idb_object.pickled_session)?;
let session = InboundGroupSession::from_pickle(pickled_session)
.map_err(|e| IndexeddbCryptoStoreError::CryptoStoreError(e.into()))?;
if idx % 100 == 0 {
debug!("Migrating session {idx} of {row_count}");
}
let new_key = serializer.encode_key(
old_keys::INBOUND_GROUP_SESSIONS_V2,
(&session.room_id, session.session_id()),
);
if new_key != old_key {
cursor.delete()?;
let new_value = store.get::<JsValue, _, _>(&new_key).await?;
if new_value.is_none() {
store
.add(&serde_wasm_bindgen::to_value(&idb_object)?)
.with_key(new_key)
.build()?;
updated += 1;
} else {
deleted += 1;
}
}
}
debug!(
"Migrated {row_count} sessions: {updated} keys updated \
and {deleted} obsolete entries deleted."
);
}
txn.commit().await?;
Ok(())
}
pub(crate) async fn schema_bump(name: &str) -> Result<(), OpenDbError> {
do_schema_upgrade(name, 8, |_, _| {
Ok(())
})
.await
}