Skip to content

Commit

Permalink
clear caches when our device key is updated
Browse files Browse the repository at this point in the history
  • Loading branch information
uhoreg committed Jun 10, 2024
1 parent c3f4a73 commit 304bcf3
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 9 deletions.
29 changes: 23 additions & 6 deletions crates/matrix-sdk-indexeddb/src/crypto_store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,10 @@ impl IndexeddbCryptoStore {

/// Process all the changes and do all encryption/serialization before the
/// actual transaction.
async fn prepare_for_transaction(&self, changes: &Changes) -> Result<PendingIndexeddbChanges> {
async fn prepare_for_transaction(
&self,
changes: &Changes,
) -> Result<(PendingIndexeddbChanges, bool)> {
let mut indexeddb_changes = PendingIndexeddbChanges::new();

let private_identity_pickle =
Expand Down Expand Up @@ -534,7 +537,17 @@ impl IndexeddbCryptoStore {

let mut device_store = indexeddb_changes.get(keys::DEVICES);

let account_info = self.get_static_account();
let mut clear_caches = false;
for device in device_changes.new.iter().chain(&device_changes.changed) {
// if our own device key changes, we need to clear the
// session cache because the sessions contain a copy of our
// device key
if account_info.clone().is_some_and(|info| {
info.user_id == device.user_id() && info.device_id == device.device_id()
}) {
clear_caches = true;
}
let key =
self.serializer.encode_key(keys::DEVICES, (device.user_id(), device.device_id()));
let device = self.serializer.serialize_value(&device)?;
Expand Down Expand Up @@ -617,7 +630,7 @@ impl IndexeddbCryptoStore {
}
}

Ok(indexeddb_changes)
Ok((indexeddb_changes, clear_caches))
}
}

Expand Down Expand Up @@ -697,7 +710,7 @@ impl_crypto_store! {
// TODO: #2000 should make this lock go away, or change its shape.
let _guard = self.save_changes_lock.lock().await;

let indexeddb_changes = self.prepare_for_transaction(&changes).await?;
let (indexeddb_changes, clear_caches) = self.prepare_for_transaction(&changes).await?;

let stores = indexeddb_changes.touched_stores();

Expand All @@ -713,9 +726,13 @@ impl_crypto_store! {

tx.await.into_result()?;

// all good, let's update our caches:indexeddb
for session in changes.sessions {
self.session_cache.add(session).await;
if clear_caches {
self.clear_caches().await;
} else {
// all good, let's update our caches:indexeddb
for session in changes.sessions {
self.session_cache.add(session).await;
}
}

Ok(())
Expand Down
58 changes: 55 additions & 3 deletions crates/matrix-sdk-sqlite/src/crypto_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,9 +780,11 @@ impl CryptoStore for SqliteCryptoStore {
}

let this = self.clone();
self.acquire()
let clear_caches = self
.acquire()
.await?
.with_transaction(move |txn| {
let mut clear_caches = false;
if let Some(pickled_private_identity) = &pickled_private_identity {
let serialized_private_identity =
this.serialize_value(pickled_private_identity)?;
Expand All @@ -804,7 +806,16 @@ impl CryptoStore for SqliteCryptoStore {
txn.set_kv("backup_version_v1", &serialized_backup_version)?;
}

let account_info = this.get_static_account();
for device in changes.devices.new.iter().chain(&changes.devices.changed) {
// if our own device key changes, we need to clear the
// session cache because the sessions contain a copy of our
// device key
if account_info.clone().is_some_and(|info| {
info.user_id == device.user_id() && info.device_id == device.device_id()
}) {
clear_caches = true;
}
let user_id = this.encode_key("device", device.user_id().as_bytes());
let device_id = this.encode_key("device", device.device_id().as_bytes());
let data = this.serialize_value(&device)?;
Expand Down Expand Up @@ -875,10 +886,14 @@ impl CryptoStore for SqliteCryptoStore {
txn.set_secret(&secret_name, &value)?;
}

Ok::<_, Error>(())
Ok::<_, Error>(clear_caches)
})
.await?;

if clear_caches {
self.clear_caches().await;
}

Ok(())
}

Expand Down Expand Up @@ -1347,7 +1362,8 @@ mod tests {
mod encrypted_tests {
use matrix_sdk_crypto::{
cryptostore_integration_tests, cryptostore_integration_tests_time,
store::{Changes, CryptoStore as _, PendingChanges},
store::{Changes, CryptoStore as _, DeviceChanges, PendingChanges},
ReadOnlyDevice,
};
use matrix_sdk_test::async_test;
use once_cell::sync::Lazy;
Expand Down Expand Up @@ -1393,6 +1409,42 @@ mod encrypted_tests {
);
}

#[async_test]
async fn cache_cleared_after_device_update() {
let store = get_store("cache_cleared_after_device_update", None).await;
// Given we created a session and saved it in the store
let (account, session) = cryptostore_integration_tests::get_account_and_session().await;
let sender_key = session.sender_key.to_base64();

store
.save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
.await
.expect("Can't save account");

let changes = Changes { sessions: vec![session.clone()], ..Default::default() };
store.save_changes(changes).await.unwrap();

store.session_cache.get(&sender_key).expect("We should have a session");

// When we save a new version of our device keys
store
.save_changes(Changes {
devices: DeviceChanges {
new: vec![ReadOnlyDevice::from_account(&account)],
..Default::default()
},
..Default::default()
})
.await
.unwrap();

// Then the session is no longer in the cache
assert!(
store.session_cache.get(&sender_key).is_none(),
"Session should not be in the cache!"
);
}

cryptostore_integration_tests!();
cryptostore_integration_tests_time!();
}

0 comments on commit 304bcf3

Please sign in to comment.