diff --git a/crates/matrix-sdk-sqlite/Cargo.toml b/crates/matrix-sdk-sqlite/Cargo.toml index 0b5b9404d..4d7c73d21 100644 --- a/crates/matrix-sdk-sqlite/Cargo.toml +++ b/crates/matrix-sdk-sqlite/Cargo.toml @@ -33,6 +33,7 @@ rmp-serde = "1.1.1" ruma = { workspace = true } rusqlite = "0.28.0" serde = { workspace = true } +serde_json = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["fs"] } tracing = { workspace = true } @@ -45,7 +46,6 @@ matrix-sdk-base = { path = "../matrix-sdk-base", features = ["testing"] } matrix-sdk-crypto = { path = "../matrix-sdk-crypto", features = ["testing"] } matrix-sdk-test = { path = "../../testing/matrix-sdk-test" } once_cell = { workspace = true } -serde_json = { workspace = true } tempfile = "3.3.0" tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } diff --git a/crates/matrix-sdk-sqlite/migrations/004_drop_outbound_group_sessions.sql b/crates/matrix-sdk-sqlite/migrations/004_drop_outbound_group_sessions.sql new file mode 100644 index 000000000..5cef67c6d --- /dev/null +++ b/crates/matrix-sdk-sqlite/migrations/004_drop_outbound_group_sessions.sql @@ -0,0 +1,5 @@ +-- Outbound group sessions in some cases might want to persist a +-- Raw, this does not work with MessagePack. Since it's fine +-- to rotate outbound group sessions let's force them to be rotated instead of +-- trying to salvage anything that was persisted. +DELETE FROM "outbound_group_session"; diff --git a/crates/matrix-sdk-sqlite/src/crypto_store.rs b/crates/matrix-sdk-sqlite/src/crypto_store.rs index 9c689b2b3..6687790e1 100644 --- a/crates/matrix-sdk-sqlite/src/crypto_store.rs +++ b/crates/matrix-sdk-sqlite/src/crypto_store.rs @@ -13,6 +13,7 @@ // limitations under the License. use std::{ + borrow::Cow, collections::HashMap, fmt, path::{Path, PathBuf}, @@ -111,28 +112,45 @@ impl SqliteCryptoStore { }) } - fn serialize_value(&self, value: &impl Serialize) -> Result> { - let serialized = rmp_serde::to_vec_named(value)?; - + fn encode_value(&self, value: Vec) -> Result> { if let Some(key) = &self.store_cipher { - let encrypted = key.encrypt_value_data(serialized)?; + let encrypted = key.encrypt_value_data(value)?; Ok(rmp_serde::to_vec_named(&encrypted)?) } else { - Ok(serialized) + Ok(value) } } - fn deserialize_value(&self, value: &[u8]) -> Result { + fn decode_value<'a>(&self, value: &'a [u8]) -> Result> { if let Some(key) = &self.store_cipher { let encrypted = rmp_serde::from_slice(value)?; let decrypted = key.decrypt_value_data(encrypted)?; - - Ok(rmp_serde::from_slice(&decrypted)?) + Ok(Cow::Owned(decrypted)) } else { - Ok(rmp_serde::from_slice(value)?) + Ok(Cow::Borrowed(value)) } } + fn serialize_json(&self, value: &impl Serialize) -> Result> { + let serialized = serde_json::to_vec(value)?; + self.encode_value(serialized) + } + + fn deserialize_json(&self, data: &[u8]) -> Result { + let decoded = self.decode_value(data)?; + Ok(serde_json::from_slice(&decoded)?) + } + + fn serialize_value(&self, value: &impl Serialize) -> Result> { + let serialized = rmp_serde::to_vec_named(value)?; + self.encode_value(serialized) + } + + fn deserialize_value(&self, value: &[u8]) -> Result { + let decoded = self.decode_value(value)?; + Ok(rmp_serde::from_slice(&decoded)?) + } + fn deserialize_pickled_inbound_group_session( &self, value: &[u8], @@ -171,7 +189,7 @@ impl SqliteCryptoStore { } } -const DATABASE_VERSION: u8 = 3; +const DATABASE_VERSION: u8 = 4; async fn run_migrations(conn: &SqliteConn) -> rusqlite::Result<()> { let kv_exists = conn @@ -227,6 +245,13 @@ async fn run_migrations(conn: &SqliteConn) -> rusqlite::Result<()> { .await?; } + if version < 4 { + conn.with_transaction(|txn| { + txn.execute_batch(include_str!("../migrations/004_drop_outbound_group_sessions.sql")) + }) + .await?; + } + conn.set_kv("version", vec![DATABASE_VERSION]).await?; Ok(()) @@ -702,7 +727,7 @@ impl CryptoStore for SqliteCryptoStore { } for (room_id, pickle) in &outbound_session_changes { - let serialized_session = this.serialize_value(&pickle)?; + let serialized_session = this.serialize_json(&pickle)?; txn.set_outbound_group_session(room_id, &serialized_session)?; } @@ -847,7 +872,7 @@ impl CryptoStore for SqliteCryptoStore { let account_info = self.get_account_info().ok_or(Error::AccountUnset)?; - let pickle = self.deserialize_value(&value)?; + let pickle = self.deserialize_json(&value)?; let session = OutboundGroupSession::from_pickle( account_info.device_id, account_info.identity_keys, diff --git a/crates/matrix-sdk-sqlite/src/error.rs b/crates/matrix-sdk-sqlite/src/error.rs index dbcb435a5..196b5cf80 100644 --- a/crates/matrix-sdk-sqlite/src/error.rs +++ b/crates/matrix-sdk-sqlite/src/error.rs @@ -62,6 +62,8 @@ pub enum Error { #[error(transparent)] Decode(rmp_serde::decode::Error), #[error(transparent)] + Json(#[from] serde_json::Error), + #[error(transparent)] Encryption(matrix_sdk_store_encryption::Error), #[error("can't save/load sessions or group sessions in the store before an account is stored")] AccountUnset,