mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-16 20:49:05 -04:00
first batch of data for testing encrypted sled store
This commit is contained in:
@@ -50,7 +50,7 @@ use sled::{
|
||||
use tracing::debug;
|
||||
|
||||
use super::OpenStoreError;
|
||||
use crate::encode_key::{EncodeKey, ENCODE_SEPARATOR};
|
||||
use crate::encode_key::{EncodeKey, EncodeSecureKey, ENCODE_SEPARATOR};
|
||||
|
||||
const DATABASE_VERSION: u8 = 4;
|
||||
|
||||
@@ -156,41 +156,18 @@ impl EncodeSecureKey for RequestedKeyInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for UserId {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let user_id = store_cipher.hash_key(table_name, self.as_bytes());
|
||||
|
||||
[user_id.as_slice(), &[0xff]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for ReadOnlyDevice {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
(self.user_id(), self.device_id()).encode_secure(table_name, store_cipher)
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for str {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let key = store_cipher.hash_key(table_name, self.as_bytes());
|
||||
[key.as_slice(), &[ENCODE_SEPARATOR]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for OutboundGroupSession {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
self.room_id().encode_secure(table_name, store_cipher)
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for RoomId {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let room_id = store_cipher.hash_key(table_name, self.as_bytes());
|
||||
|
||||
[room_id.as_slice(), &[ENCODE_SEPARATOR]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for InboundGroupSession {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
(self.room_id(), self.sender_key(), self.session_id())
|
||||
@@ -198,24 +175,6 @@ impl EncodeSecureKey for InboundGroupSession {
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for (&RoomId, &str, &str) {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let first = store_cipher.hash_key(table_name, self.0.as_bytes());
|
||||
let second = store_cipher.hash_key(table_name, self.1.as_bytes());
|
||||
let third = store_cipher.hash_key(table_name, self.2.as_bytes());
|
||||
|
||||
[
|
||||
first.as_slice(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
second.as_slice(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
third.as_slice(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for Session {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let sender_key =
|
||||
@@ -227,9 +186,6 @@ impl EncodeSecureKey for Session {
|
||||
}
|
||||
}
|
||||
|
||||
trait EncodeSecureKey {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AccountInfo {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
use matrix_sdk_common::ruma::{
|
||||
events::{secret::request::SecretName, GlobalAccountDataEventType, StateEventType},
|
||||
events::{secret::request::SecretName, GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType},
|
||||
receipt::ReceiptType,
|
||||
EventEncryptionAlgorithm,
|
||||
DeviceId, EventId, MxcUri, RoomId, TransactionId, UserId,
|
||||
};
|
||||
use matrix_sdk_store_encryption::StoreCipher;
|
||||
|
||||
|
||||
pub const ENCODE_SEPARATOR: u8 = 0xff;
|
||||
|
||||
pub trait EncodeKey {
|
||||
@@ -70,6 +75,26 @@ impl EncodeKey for SecretName {
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeKey for ReceiptType {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let s: &str = self.as_ref();
|
||||
s.encode()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeKey for EventEncryptionAlgorithm {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let s: &str = self.as_ref();
|
||||
s.encode()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeKey for RoomAccountDataEventType {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.to_string().encode()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeKey for UserId {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.as_str().encode()
|
||||
@@ -78,15 +103,13 @@ impl EncodeKey for UserId {
|
||||
|
||||
impl<A, B> EncodeKey for (A, B)
|
||||
where
|
||||
A: AsRef<str>,
|
||||
B: AsRef<str>,
|
||||
A: EncodeKey,
|
||||
B: EncodeKey,
|
||||
{
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
[
|
||||
self.0.as_ref().as_bytes(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
self.1.as_ref().as_bytes(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
self.0.encode(),
|
||||
self.1.encode(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
@@ -94,18 +117,15 @@ where
|
||||
|
||||
impl<A, B, C> EncodeKey for (A, B, C)
|
||||
where
|
||||
A: AsRef<str>,
|
||||
B: AsRef<str>,
|
||||
C: AsRef<str>,
|
||||
A: EncodeKey,
|
||||
B: EncodeKey,
|
||||
C: EncodeKey,
|
||||
{
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
[
|
||||
self.0.as_ref().as_bytes(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
self.1.as_ref().as_bytes(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
self.2.as_ref().as_bytes(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
self.0.encode(),
|
||||
self.1.encode(),
|
||||
self.2.encode(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
@@ -113,21 +133,17 @@ where
|
||||
|
||||
impl<A, B, C, D> EncodeKey for (A, B, C, D)
|
||||
where
|
||||
A: AsRef<str>,
|
||||
B: AsRef<str>,
|
||||
C: AsRef<str>,
|
||||
D: AsRef<str>,
|
||||
A: EncodeKey,
|
||||
B: EncodeKey,
|
||||
C: EncodeKey,
|
||||
D: EncodeKey,
|
||||
{
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
[
|
||||
self.0.as_ref().as_bytes(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
self.1.as_ref().as_bytes(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
self.2.as_ref().as_bytes(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
self.3.as_ref().as_bytes(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
self.0.encode(),
|
||||
self.1.encode(),
|
||||
self.2.encode(),
|
||||
self.3.encode(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
@@ -145,9 +161,143 @@ impl EncodeKey for GlobalAccountDataEventType {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "state-store")]
|
||||
pub fn encode_key_with_usize<A: AsRef<str>>(s: A, i: usize) -> Vec<u8> {
|
||||
// FIXME: Not portable across architectures
|
||||
[s.as_ref().as_bytes(), &[ENCODE_SEPARATOR], i.to_be_bytes().as_ref(), &[ENCODE_SEPARATOR]]
|
||||
.concat()
|
||||
|
||||
pub trait EncodeSecureKey {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8>;
|
||||
}
|
||||
|
||||
|
||||
impl<T: EncodeSecureKey + ?Sized> EncodeSecureKey for &T {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
T::encode_secure(self, table_name, store_cipher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EncodeSecureKey + ?Sized> EncodeSecureKey for Box<T> {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
T::encode_secure(self, table_name, store_cipher)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl EncodeSecureKey for UserId {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let user_id = store_cipher.hash_key(table_name, self.as_bytes());
|
||||
|
||||
[user_id.as_slice(), &[ENCODE_SEPARATOR]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for str {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let key = store_cipher.hash_key(table_name, self.as_bytes());
|
||||
[key.as_slice(), &[ENCODE_SEPARATOR]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for String {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let key = store_cipher.hash_key(table_name, self.as_bytes());
|
||||
[key.as_slice(), &[ENCODE_SEPARATOR]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for RoomId {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let room_id = store_cipher.hash_key(table_name, self.as_bytes());
|
||||
|
||||
[room_id.as_slice(), &[ENCODE_SEPARATOR]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for EventId {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let event_id = store_cipher.hash_key(table_name, self.as_bytes());
|
||||
|
||||
[event_id.as_slice(), &[ENCODE_SEPARATOR]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for ReceiptType {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
let event_id = store_cipher.hash_key(table_name, self.as_str().as_bytes());
|
||||
|
||||
[event_id.as_slice(), &[ENCODE_SEPARATOR]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for GlobalAccountDataEventType {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
[
|
||||
store_cipher.hash_key(table_name, self.to_string().as_bytes()).as_slice(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for StateEventType {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
[
|
||||
store_cipher.hash_key(table_name, self.to_string().as_bytes()).as_slice(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeSecureKey for RoomAccountDataEventType {
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
[
|
||||
store_cipher.hash_key(table_name, self.to_string().as_bytes()).as_slice(),
|
||||
&[ENCODE_SEPARATOR],
|
||||
].concat()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<A, B> EncodeSecureKey for (A, B)
|
||||
where
|
||||
A: EncodeSecureKey,
|
||||
B: EncodeSecureKey,
|
||||
{
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
[
|
||||
self.0.encode_secure(table_name, store_cipher),
|
||||
self.1.encode_secure(table_name, store_cipher),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C> EncodeSecureKey for (A, B, C)
|
||||
where
|
||||
A: EncodeSecureKey,
|
||||
B: EncodeSecureKey,
|
||||
C: EncodeSecureKey,
|
||||
{
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
[
|
||||
self.0.encode_secure(table_name, store_cipher),
|
||||
self.1.encode_secure(table_name, store_cipher),
|
||||
self.2.encode_secure(table_name, store_cipher),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C, D> EncodeSecureKey for (A, B, C, D)
|
||||
where
|
||||
A: EncodeSecureKey,
|
||||
B: EncodeSecureKey,
|
||||
C: EncodeSecureKey,
|
||||
D: EncodeSecureKey,
|
||||
{
|
||||
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
|
||||
[
|
||||
self.0.encode_secure(table_name, store_cipher),
|
||||
self.1.encode_secure(table_name, store_cipher),
|
||||
self.2.encode_secure(table_name, store_cipher),
|
||||
self.3.encode_secure(table_name, store_cipher),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ use tracing::{info, warn};
|
||||
|
||||
#[cfg(feature = "crypto-store")]
|
||||
use super::OpenStoreError;
|
||||
use crate::encode_key::{encode_key_with_usize, EncodeKey, ENCODE_SEPARATOR};
|
||||
use crate::encode_key::{EncodeSecureKey, EncodeKey, ENCODE_SEPARATOR};
|
||||
#[cfg(feature = "crypto-store")]
|
||||
pub use crate::CryptoStore;
|
||||
|
||||
@@ -109,6 +109,32 @@ impl Into<StoreError> for SledStoreError {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const SESSION: &str = "session";
|
||||
const ACCOUNT_DATA: &str = "account-data";
|
||||
const MEMBER: &str = "member";
|
||||
const PROFILE: &str = "profile";
|
||||
const ROOM_STATE: &str = "room-state";
|
||||
const PRESENCE: &str = "presence";
|
||||
const ROOM: &str = "room";
|
||||
const ROOM_INFO: &str = "room-info";
|
||||
const DISPLAY_NAME: &str = "display-name";
|
||||
const JOINED_USER_ID: &str = "joined-user-id";
|
||||
const INVITED_USER_ID: &str = "invited-user-ids";
|
||||
const ROOM_ACCOUNT_DATA: &str = "room-account-data";
|
||||
const STRIPPED_ROOM: &str = "stripped-room";
|
||||
const STRIPPED_ROOM_INFO: &str = "stripped-room-info";
|
||||
const STRIPPED_ROOM_MEMBER: &str = "stripped-room-member";
|
||||
const STRIPPED_ROOM_STATE: &str = "stripped-room-state";
|
||||
const ROOM_USER_RECEIPT: &str = "room-user-receipt";
|
||||
const ROOM_EVENT_RECEIPT: &str = "room-event-receipt";
|
||||
const MEDIA: &str = "media";
|
||||
const CUSTOM: &str = "custom";
|
||||
const TIMELINE: &str = "timeline";
|
||||
const TIMELINE_METADTA: &str = "timeline-metadata";
|
||||
const ROOM_EVENT_ID_POSITION: &str = "room-event-id-to-position";
|
||||
|
||||
|
||||
type Result<A, E = SledStoreError> = std::result::Result<A, E>;
|
||||
|
||||
/// Get the value at `position` in encoded `key`.
|
||||
@@ -118,12 +144,20 @@ type Result<A, E = SledStoreError> = std::result::Result<A, E>;
|
||||
/// wasn't encoded in a tuple, use `0`.
|
||||
///
|
||||
/// Returns `None` if there is no key at `position`.
|
||||
pub fn decode_key_value(key: &[u8], position: usize) -> Option<String> {
|
||||
fn decode_key_value(key: &[u8], position: usize) -> Option<String> {
|
||||
let values: Vec<&[u8]> = key.split(|v| *v == ENCODE_SEPARATOR).collect();
|
||||
|
||||
values.get(position).map(|s| String::from_utf8_lossy(s).to_string())
|
||||
}
|
||||
|
||||
|
||||
pub fn encode_key_with_usize<A: AsRef<str>>(s: A, i: usize) -> Vec<u8> {
|
||||
// FIXME: Not portable across architectures
|
||||
[s.as_ref().as_bytes(), &[ENCODE_SEPARATOR], i.to_be_bytes().as_ref(), &[ENCODE_SEPARATOR]]
|
||||
.concat()
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SledStore {
|
||||
path: Option<PathBuf>,
|
||||
@@ -164,34 +198,34 @@ impl std::fmt::Debug for SledStore {
|
||||
|
||||
impl SledStore {
|
||||
fn open_helper(db: Db, path: Option<PathBuf>, store_cipher: Option<StoreCipher>) -> Result<Self> {
|
||||
let session = db.open_tree("session")?;
|
||||
let account_data = db.open_tree("account_data")?;
|
||||
let session = db.open_tree(SESSION)?;
|
||||
let account_data = db.open_tree(ACCOUNT_DATA)?;
|
||||
|
||||
let members = db.open_tree("members")?;
|
||||
let profiles = db.open_tree("profiles")?;
|
||||
let display_names = db.open_tree("display_names")?;
|
||||
let joined_user_ids = db.open_tree("joined_user_ids")?;
|
||||
let invited_user_ids = db.open_tree("invited_user_ids")?;
|
||||
let members = db.open_tree(MEMBER)?;
|
||||
let profiles = db.open_tree(PROFILE)?;
|
||||
let display_names = db.open_tree(DISPLAY_NAME)?;
|
||||
let joined_user_ids = db.open_tree(JOINED_USER_ID)?;
|
||||
let invited_user_ids = db.open_tree(INVITED_USER_ID)?;
|
||||
|
||||
let room_state = db.open_tree("room_state")?;
|
||||
let room_info = db.open_tree("room_infos")?;
|
||||
let presence = db.open_tree("presence")?;
|
||||
let room_account_data = db.open_tree("room_account_data")?;
|
||||
let room_state = db.open_tree(ROOM_STATE)?;
|
||||
let room_info = db.open_tree(ROOM_INFO)?;
|
||||
let presence = db.open_tree(PRESENCE)?;
|
||||
let room_account_data = db.open_tree(ROOM_ACCOUNT_DATA)?;
|
||||
|
||||
let stripped_room_infos = db.open_tree("stripped_room_infos")?;
|
||||
let stripped_members = db.open_tree("stripped_members")?;
|
||||
let stripped_room_state = db.open_tree("stripped_room_state")?;
|
||||
let stripped_room_infos = db.open_tree(STRIPPED_ROOM_INFO)?;
|
||||
let stripped_members = db.open_tree(STRIPPED_ROOM_MEMBER)?;
|
||||
let stripped_room_state = db.open_tree(STRIPPED_ROOM_STATE)?;
|
||||
|
||||
let room_user_receipts = db.open_tree("room_user_receipts")?;
|
||||
let room_event_receipts = db.open_tree("room_event_receipts")?;
|
||||
let room_user_receipts = db.open_tree(ROOM_USER_RECEIPT)?;
|
||||
let room_event_receipts = db.open_tree(ROOM_EVENT_RECEIPT)?;
|
||||
|
||||
let media = db.open_tree("media")?;
|
||||
let media = db.open_tree(MEDIA)?;
|
||||
|
||||
let custom = db.open_tree("custom")?;
|
||||
let custom = db.open_tree(CUSTOM)?;
|
||||
|
||||
let room_timeline = db.open_tree("room_timeline")?;
|
||||
let room_timeline_metadata = db.open_tree("room_timeline_metadata")?;
|
||||
let room_event_id_to_position = db.open_tree("room_event_id_to_position")?;
|
||||
let room_timeline = db.open_tree(TIMELINE)?;
|
||||
let room_timeline_metadata = db.open_tree(TIMELINE_METADTA)?;
|
||||
let room_event_id_to_position = db.open_tree(ROOM_EVENT_ID_POSITION)?;
|
||||
|
||||
Ok(Self {
|
||||
path,
|
||||
@@ -228,6 +262,16 @@ impl SledStore {
|
||||
SledStore::open_helper(db, None, None).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
// testing only
|
||||
#[cfg(test)]
|
||||
fn open_encrypted() -> StoreResult<Self> {
|
||||
let db =
|
||||
Config::new().temporary(true).open().map_err(|e| StoreError::Backend(anyhow!(e)))?;
|
||||
|
||||
SledStore::open_helper(db, None, Some(StoreCipher::new().expect("can't create store cipher"))).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
|
||||
pub fn open_with_passphrase(path: impl AsRef<Path>, passphrase: &str) -> StoreResult<Self> {
|
||||
Self::inner_open_with_passphrase(path, passphrase).map_err(|e| e.into())
|
||||
}
|
||||
@@ -287,9 +331,21 @@ impl SledStore {
|
||||
Ok(serde_json::from_slice(event)?)
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_key<T: EncodeSecureKey + EncodeKey + ?Sized>(
|
||||
&self,
|
||||
table_name: &str,
|
||||
key: &T,
|
||||
) -> Vec<u8> {
|
||||
if let Some(store_cipher) = &*self.store_cipher {
|
||||
key.encode_secure(table_name, store_cipher).to_vec()
|
||||
} else {
|
||||
key.encode()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn save_filter(&self, filter_name: &str, filter_id: &str) -> Result<()> {
|
||||
self.session.insert(("filter", filter_name).encode(), filter_id)?;
|
||||
self.session.insert(self.encode_key(SESSION, &("filter", filter_name)), filter_id)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -297,7 +353,7 @@ impl SledStore {
|
||||
pub async fn get_filter(&self, filter_name: &str) -> Result<Option<String>> {
|
||||
Ok(self
|
||||
.session
|
||||
.get(("filter", filter_name).encode())?
|
||||
.get(self.encode_key(SESSION, &("filter", filter_name)))?
|
||||
.map(|f| String::from_utf8_lossy(&f).to_string()))
|
||||
}
|
||||
|
||||
@@ -352,25 +408,25 @@ impl SledStore {
|
||||
let profile_changes = changes.profiles.get(room);
|
||||
|
||||
for event in events.values() {
|
||||
let key = (room, &event.state_key).encode();
|
||||
let key = (room, &event.state_key);
|
||||
|
||||
match event.content.membership {
|
||||
MembershipState::Join => {
|
||||
joined.insert(key.as_slice(), event.state_key.as_str())?;
|
||||
invited.remove(key.as_slice())?;
|
||||
joined.insert(self.encode_key(JOINED_USER_ID, &key), event.state_key.as_str())?;
|
||||
invited.remove(self.encode_key(INVITED_USER_ID, &key))?;
|
||||
}
|
||||
MembershipState::Invite => {
|
||||
invited.insert(key.as_slice(), event.state_key.as_str())?;
|
||||
joined.remove(key.as_slice())?;
|
||||
invited.insert(self.encode_key(INVITED_USER_ID, &key), event.state_key.as_str())?;
|
||||
joined.remove(self.encode_key(JOINED_USER_ID, &key))?;
|
||||
}
|
||||
_ => {
|
||||
joined.remove(key.as_slice())?;
|
||||
invited.remove(key.as_slice())?;
|
||||
joined.remove(self.encode_key(JOINED_USER_ID, &key))?;
|
||||
invited.remove(self.encode_key(INVITED_USER_ID, &key))?;
|
||||
}
|
||||
}
|
||||
|
||||
members.insert(
|
||||
key.as_slice(),
|
||||
self.encode_key(MEMBER, &key),
|
||||
self.serialize_event(&event)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -379,7 +435,7 @@ impl SledStore {
|
||||
profile_changes.and_then(|p| p.get(&event.state_key))
|
||||
{
|
||||
profiles.insert(
|
||||
key.as_slice(),
|
||||
self.encode_key(PROFILE, &key),
|
||||
self.serialize_event(&profile)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -390,7 +446,7 @@ impl SledStore {
|
||||
for (room_id, ambiguity_maps) in &changes.ambiguity_maps {
|
||||
for (display_name, map) in ambiguity_maps {
|
||||
display_names.insert(
|
||||
(room_id, display_name).encode(),
|
||||
self.encode_key(DISPLAY_NAME, &(room_id, display_name)),
|
||||
self.serialize_event(&map)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -399,7 +455,7 @@ impl SledStore {
|
||||
|
||||
for (event_type, event) in &changes.account_data {
|
||||
account_data.insert(
|
||||
event_type.encode(),
|
||||
self.encode_key(ACCOUNT_DATA, event_type),
|
||||
self.serialize_event(&event)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -408,7 +464,7 @@ impl SledStore {
|
||||
for (room, events) in &changes.room_account_data {
|
||||
for (event_type, event) in events {
|
||||
room_account_data.insert(
|
||||
(room, event_type.to_string()).encode(),
|
||||
self.encode_key(ROOM_ACCOUNT_DATA, &(room, event_type)),
|
||||
self.serialize_event(&event)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -419,7 +475,7 @@ impl SledStore {
|
||||
for (event_type, events) in event_types {
|
||||
for (state_key, event) in events {
|
||||
state.insert(
|
||||
(room, event_type.to_string(), state_key).encode(),
|
||||
self.encode_key(ROOM_STATE, &(room, event_type, state_key)),
|
||||
self.serialize_event(&event)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -429,7 +485,7 @@ impl SledStore {
|
||||
|
||||
for (room_id, room_info) in &changes.room_infos {
|
||||
rooms.insert(
|
||||
room_id.encode(),
|
||||
self.encode_key(ROOM, room_id),
|
||||
self.serialize_event(room_info)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -437,7 +493,7 @@ impl SledStore {
|
||||
|
||||
for (sender, event) in &changes.presence {
|
||||
presence.insert(
|
||||
sender.encode(),
|
||||
self.encode_key(PRESENCE, sender),
|
||||
self.serialize_event(&event)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -445,7 +501,7 @@ impl SledStore {
|
||||
|
||||
for (room_id, info) in &changes.stripped_room_infos {
|
||||
striped_rooms.insert(
|
||||
room_id.encode(),
|
||||
self.encode_key(STRIPPED_ROOM_INFO, room_id),
|
||||
self.serialize_event(&info)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -454,7 +510,7 @@ impl SledStore {
|
||||
for (room, events) in &changes.stripped_members {
|
||||
for event in events.values() {
|
||||
stripped_members.insert(
|
||||
(room, event.state_key.to_string()).encode(),
|
||||
self.encode_key(STRIPPED_ROOM_MEMBER, &(room, event.state_key.to_string())),
|
||||
self.serialize_event(&event)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -465,7 +521,7 @@ impl SledStore {
|
||||
for (event_type, events) in event_types {
|
||||
for (state_key, event) in events {
|
||||
stripped_state.insert(
|
||||
(room, event_type.to_string(), state_key).encode(),
|
||||
self.encode_key(STRIPPED_ROOM_STATE, &(room, event_type.to_string(), state_key)),
|
||||
self.serialize_event(&event)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -488,7 +544,7 @@ impl SledStore {
|
||||
for (user_id, receipt) in receipts {
|
||||
// Add the receipt to the room user receipts
|
||||
if let Some(old) = room_user_receipts.insert(
|
||||
(room, receipt_type, user_id).encode(),
|
||||
self.encode_key(ROOM_USER_RECEIPT, &(room, receipt_type, user_id)),
|
||||
self.serialize_event(&(event_id, receipt))
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)? {
|
||||
@@ -497,13 +553,13 @@ impl SledStore {
|
||||
.deserialize_event(&old)
|
||||
.map_err(ConflictableTransactionError::Abort)?;
|
||||
room_event_receipts.remove(
|
||||
(room, receipt_type, old_event, user_id).encode(),
|
||||
self.encode_key(ROOM_EVENT_RECEIPT, &(room, receipt_type, old_event, user_id)),
|
||||
)?;
|
||||
}
|
||||
|
||||
// Add the receipt to the room event receipts
|
||||
room_event_receipts.insert(
|
||||
(room, receipt_type, event_id, user_id).encode(),
|
||||
self.encode_key(ROOM_EVENT_RECEIPT, &(room, receipt_type, event_id, user_id)),
|
||||
self.serialize_event(receipt)
|
||||
.map_err(ConflictableTransactionError::Abort)?,
|
||||
)?;
|
||||
@@ -529,7 +585,7 @@ impl SledStore {
|
||||
|
||||
pub async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>> {
|
||||
let db = self.clone();
|
||||
let key = user_id.encode();
|
||||
let key = self.encode_key(PRESENCE, user_id);
|
||||
spawn_blocking(move || db.presence.get(key)?.map(|e| db.deserialize_event(&e)).transpose())
|
||||
.await?
|
||||
}
|
||||
@@ -541,7 +597,7 @@ impl SledStore {
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<AnySyncStateEvent>>> {
|
||||
let db = self.clone();
|
||||
let key = (room_id, event_type.to_string(), state_key).encode();
|
||||
let key = self.encode_key(ROOM_STATE, &(room_id, event_type.to_string(), state_key));
|
||||
spawn_blocking(move || {
|
||||
db.room_state.get(key)?.map(|e| db.deserialize_event(&e)).transpose()
|
||||
})
|
||||
@@ -554,7 +610,7 @@ impl SledStore {
|
||||
event_type: StateEventType,
|
||||
) -> Result<Vec<Raw<AnySyncStateEvent>>> {
|
||||
let db = self.clone();
|
||||
let key = (room_id, event_type.to_string()).encode();
|
||||
let key = self.encode_key(ROOM_STATE, &(room_id, event_type.to_string()));
|
||||
spawn_blocking(move || {
|
||||
db.room_state
|
||||
.scan_prefix(key)
|
||||
@@ -570,7 +626,7 @@ impl SledStore {
|
||||
user_id: &UserId,
|
||||
) -> Result<Option<RoomMemberEventContent>> {
|
||||
let db = self.clone();
|
||||
let key = (room_id, user_id).encode();
|
||||
let key = self.encode_key(PROFILE, &(room_id, user_id));
|
||||
spawn_blocking(move || db.profiles.get(key)?.map(|p| db.deserialize_event(&p)).transpose())
|
||||
.await?
|
||||
}
|
||||
@@ -581,7 +637,7 @@ impl SledStore {
|
||||
state_key: &UserId,
|
||||
) -> Result<Option<MemberEvent>> {
|
||||
let db = self.clone();
|
||||
let key = (room_id, state_key).encode();
|
||||
let key = self.encode_key(MEMBER, &(room_id, state_key));
|
||||
spawn_blocking(move || db.members.get(key)?.map(|v| db.deserialize_event(&v)).transpose())
|
||||
.await?
|
||||
}
|
||||
@@ -808,60 +864,59 @@ impl SledStore {
|
||||
}
|
||||
|
||||
async fn remove_room(&self, room_id: &RoomId) -> Result<()> {
|
||||
let room_key = room_id.encode();
|
||||
|
||||
let mut members_batch = sled::Batch::default();
|
||||
for key in self.members.scan_prefix(room_key.as_slice()).keys() {
|
||||
let mut members_batch = sled::Batch::default();
|
||||
for key in self.members.scan_prefix(self.encode_key(MEMBER, room_id)).keys() {
|
||||
members_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut profiles_batch = sled::Batch::default();
|
||||
for key in self.profiles.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.profiles.scan_prefix(self.encode_key(PROFILE, room_id)).keys() {
|
||||
profiles_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut display_names_batch = sled::Batch::default();
|
||||
for key in self.display_names.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.display_names.scan_prefix(self.encode_key(DISPLAY_NAME, room_id)).keys() {
|
||||
display_names_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut joined_user_ids_batch = sled::Batch::default();
|
||||
for key in self.joined_user_ids.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.joined_user_ids.scan_prefix(self.encode_key(JOINED_USER_ID, room_id)).keys() {
|
||||
joined_user_ids_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut invited_user_ids_batch = sled::Batch::default();
|
||||
for key in self.invited_user_ids.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.invited_user_ids.scan_prefix(self.encode_key(INVITED_USER_ID, room_id)).keys() {
|
||||
invited_user_ids_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut room_state_batch = sled::Batch::default();
|
||||
for key in self.room_state.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.room_state.scan_prefix(self.encode_key(ROOM_STATE, room_id)).keys() {
|
||||
room_state_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut room_account_data_batch = sled::Batch::default();
|
||||
for key in self.room_account_data.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.room_account_data.scan_prefix(self.encode_key(ROOM_ACCOUNT_DATA, room_id)).keys() {
|
||||
room_account_data_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut stripped_members_batch = sled::Batch::default();
|
||||
for key in self.stripped_members.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.stripped_members.scan_prefix(self.encode_key(STRIPPED_ROOM_MEMBER, room_id)).keys() {
|
||||
stripped_members_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut stripped_room_state_batch = sled::Batch::default();
|
||||
for key in self.stripped_room_state.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.stripped_room_state.scan_prefix(self.encode_key(STRIPPED_ROOM, room_id)).keys() {
|
||||
stripped_room_state_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut room_user_receipts_batch = sled::Batch::default();
|
||||
for key in self.room_user_receipts.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.room_user_receipts.scan_prefix(self.encode_key(ROOM_USER_RECEIPT, room_id)).keys() {
|
||||
room_user_receipts_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut room_event_receipts_batch = sled::Batch::default();
|
||||
for key in self.room_event_receipts.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.room_event_receipts.scan_prefix(self.encode_key(ROOM_EVENT_RECEIPT, room_id)).keys() {
|
||||
room_event_receipts_batch.remove(key?)
|
||||
}
|
||||
|
||||
@@ -896,8 +951,8 @@ impl SledStore {
|
||||
room_user_receipts,
|
||||
room_event_receipts,
|
||||
)| {
|
||||
rooms.remove(room_key.as_slice())?;
|
||||
stripped_rooms.remove(room_key.as_slice())?;
|
||||
rooms.remove(self.encode_key(ROOM, room_id))?;
|
||||
stripped_rooms.remove(self.encode_key(STRIPPED_ROOM, room_id))?;
|
||||
|
||||
members.apply_batch(&members_batch)?;
|
||||
profiles.apply_batch(&profiles_batch)?;
|
||||
@@ -929,7 +984,7 @@ impl SledStore {
|
||||
room_id: &RoomId,
|
||||
) -> Result<Option<(BoxStream<StoreResult<SyncRoomEvent>>, Option<String>)>> {
|
||||
let db = self.clone();
|
||||
let key = room_id.encode();
|
||||
let key = self.encode_key("ROOM_TIMELINE_METADATA", room_id);
|
||||
let r_id = room_id.to_owned();
|
||||
let metadata: Option<TimelineMetadata> = db
|
||||
.room_timeline_metadata
|
||||
@@ -960,16 +1015,15 @@ impl SledStore {
|
||||
}
|
||||
|
||||
async fn remove_room_timeline(&self, room_id: &RoomId) -> Result<()> {
|
||||
let room_key = room_id.encode();
|
||||
info!("Remove stored timeline for {}", room_id);
|
||||
|
||||
let mut timeline_batch = sled::Batch::default();
|
||||
for key in self.room_timeline.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.room_timeline.scan_prefix(self.encode_key("ROOM_TIMELINE", &room_id)).keys() {
|
||||
timeline_batch.remove(key?)
|
||||
}
|
||||
|
||||
let mut event_id_to_position_batch = sled::Batch::default();
|
||||
for key in self.room_event_id_to_position.scan_prefix(room_key.as_slice()).keys() {
|
||||
for key in self.room_event_id_to_position.scan_prefix(self.encode_key(ROOM, &room_id)).keys() {
|
||||
event_id_to_position_batch.remove(key?)
|
||||
}
|
||||
|
||||
@@ -977,7 +1031,7 @@ impl SledStore {
|
||||
(&self.room_timeline, &self.room_timeline_metadata, &self.room_event_id_to_position)
|
||||
.transaction(
|
||||
|(room_timeline, room_timeline_metadata, room_event_id_to_position)| {
|
||||
room_timeline_metadata.remove(room_key.as_slice())?;
|
||||
room_timeline_metadata.remove(self.encode_key("ROOM_TIMELINE_METADATA", &room_id))?;
|
||||
|
||||
room_timeline.apply_batch(&timeline_batch)?;
|
||||
room_event_id_to_position.apply_batch(&event_id_to_position_batch)?;
|
||||
@@ -1002,7 +1056,6 @@ impl SledStore {
|
||||
} else {
|
||||
info!("Save new timeline batch from messages response for {}", room_id);
|
||||
}
|
||||
let room_key = room_id.encode();
|
||||
|
||||
let metadata: Option<TimelineMetadata> = if timeline.limited {
|
||||
info!(
|
||||
@@ -1014,7 +1067,7 @@ impl SledStore {
|
||||
} else {
|
||||
let metadata: Option<TimelineMetadata> = self
|
||||
.room_timeline_metadata
|
||||
.get(room_key.as_slice())?
|
||||
.get(self.encode_key("ROOM_TIMELINE_METADATA", &room_id))?
|
||||
.map(|v| serde_json::from_slice(&v).map_err(StoreError::Json))
|
||||
.transpose()?;
|
||||
if let Some(mut metadata) = metadata {
|
||||
@@ -1030,7 +1083,7 @@ impl SledStore {
|
||||
let mut delete_timeline = false;
|
||||
for event in &timeline.events {
|
||||
if let Some(event_id) = event.event_id() {
|
||||
let event_key = (room_id, event_id).encode();
|
||||
let event_key = self.encode_key("ROOM_EVENT_ID_POSITION", &(room_id, event_id));
|
||||
if self.room_event_id_to_position.contains_key(event_key)? {
|
||||
delete_timeline = true;
|
||||
break;
|
||||
@@ -1131,7 +1184,7 @@ impl SledStore {
|
||||
}
|
||||
}
|
||||
|
||||
timeline_metadata_batch.insert(room_key, serde_json::to_vec(&metadata)?);
|
||||
timeline_metadata_batch.insert(self.encode_key(TIMELINE_METADTA, &room_id), serde_json::to_vec(&metadata)?);
|
||||
}
|
||||
|
||||
let ret: Result<(), TransactionError<SledStoreError>> =
|
||||
@@ -1340,3 +1393,16 @@ mod tests {
|
||||
|
||||
statestore_integration_tests! { integration }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod encrypted_tests {
|
||||
use matrix_sdk_base::statestore_integration_tests;
|
||||
|
||||
use super::{SledStore, StateStore, StoreResult};
|
||||
|
||||
async fn get_store() -> StoreResult<impl StateStore> {
|
||||
SledStore::open_encrypted().map_err(Into::into)
|
||||
}
|
||||
|
||||
statestore_integration_tests! { integration }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user