Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crates/matrix-sdk-indexeddb/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ All notable changes to this project will be documented in this file.

## [Unreleased] - ReleaseDate

### Features

- Expose implementations of `EventCacheStore` and `MediaStore` and add a
composite type for initializing all stores with a single function - i.e.,
`IndexeddbStores::open`. Additionally, allow feature flags for each of the
stores to be used independent of and in combination with the others.
([#5946](https://github.com/matrix-org/matrix-rust-sdk/pull/5946))

### Bug Fixes

- Ensure that encrypted tests are run with a `StoreCipher`. This happened to reveal tests which fail in an
Expand Down
13 changes: 8 additions & 5 deletions crates/matrix-sdk-indexeddb/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ default-target = "wasm32-unknown-unknown"
rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]

[features]
default = ["e2e-encryption", "state-store", "event-cache-store"]
event-cache-store = ["dep:matrix-sdk-base", "media-store"]
media-store = ["dep:matrix-sdk-base"]
state-store = ["dep:matrix-sdk-base", "growable-bloom-filter"]
e2e-encryption = ["dep:matrix-sdk-base", "dep:matrix-sdk-crypto"]
default = ["e2e-encryption", "state-store", "event-cache-store", "media-store"]
event-cache-store = ["dep:matrix-sdk-base", "media-store", "indexed-type-serializer"]
media-store = ["dep:matrix-sdk-base", "indexed-type-serializer"]
state-store = ["dep:matrix-sdk-base", "growable-bloom-filter", "safe-encode-traits"]
e2e-encryption = ["dep:matrix-sdk-base", "dep:matrix-sdk-crypto", "safe-encode-serializer"]
safe-encode-traits = []
safe-encode-serializer = ["dep:matrix-sdk-crypto", "safe-encode-traits"]
indexed-type-serializer = ["safe-encode-serializer"]
testing = ["matrix-sdk-crypto?/testing"]
experimental-encrypted-state-events = [
"matrix-sdk-crypto?/experimental-encrypted-state-events"
Expand Down
12 changes: 11 additions & 1 deletion crates/matrix-sdk-indexeddb/src/event_cache_store/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
error::IndexeddbEventCacheStoreError, migrations::open_and_upgrade_db,
IndexeddbEventCacheStore,
},
serializer::{IndexedTypeSerializer, SafeEncodeSerializer},
serializer::{indexed_type::IndexedTypeSerializer, safe_encode::types::SafeEncodeSerializer},
};

/// A type for conveniently building an [`IndexeddbEventCacheStore`]
Expand Down Expand Up @@ -56,6 +56,16 @@ impl IndexeddbEventCacheStoreBuilder {
self
}

/// Create a new [`IndexeddbEventCacheStoreBuilder`] where the database name
/// is constructed by joining the given prefix with
/// [`Self::DEFAULT_DATABASE_NAME`] and separated by `::`.
pub fn with_prefix(prefix: &str) -> Self {
Self {
database_name: format!("{}::{}", prefix, Self::DEFAULT_DATABASE_NAME),
store_cipher: None,
}
}

/// Sets the store cipher to use when encrypting data before it is persisted
/// to the IndexedDB database. By default, no store cipher is used -
/// i.e., data is not encrypted before it is persisted.
Expand Down
2 changes: 1 addition & 1 deletion crates/matrix-sdk-indexeddb/src/event_cache_store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use crate::{
transaction::IndexeddbEventCacheStoreTransaction,
types::{ChunkType, InBandEvent, Lease, OutOfBandEvent},
},
serializer::{Indexed, IndexedTypeSerializer},
serializer::indexed_type::{traits::Indexed, IndexedTypeSerializer},
transaction::TransactionError,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,17 @@ use crate::{
types::{Chunk, Event, Gap, Lease, Position},
},
serializer::{
Indexed, IndexedKey, IndexedKeyComponentBounds, IndexedPrefixKeyBounds,
IndexedPrefixKeyComponentBounds, MaybeEncrypted, SafeEncodeSerializer,
INDEXED_KEY_LOWER_CHARACTER, INDEXED_KEY_LOWER_STRING, INDEXED_KEY_UPPER_CHARACTER,
INDEXED_KEY_UPPER_STRING,
indexed_type::{
constants::{
INDEXED_KEY_LOWER_CHARACTER, INDEXED_KEY_LOWER_STRING, INDEXED_KEY_UPPER_CHARACTER,
INDEXED_KEY_UPPER_STRING,
},
traits::{
Indexed, IndexedKey, IndexedKeyComponentBounds, IndexedPrefixKeyBounds,
IndexedPrefixKeyComponentBounds,
},
},
safe_encode::types::{MaybeEncrypted, SafeEncodeSerializer},
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ use crate::{
},
types::{Chunk, ChunkType, Event, Gap, Lease, Position},
},
serializer::{
Indexed, IndexedKeyRange, IndexedPrefixKeyBounds, IndexedPrefixKeyComponentBounds,
serializer::indexed_type::{
range::IndexedKeyRange,
traits::{Indexed, IndexedPrefixKeyBounds, IndexedPrefixKeyComponentBounds},
IndexedTypeSerializer,
},
transaction::{Transaction, TransactionError},
Expand Down
166 changes: 166 additions & 0 deletions crates/matrix-sdk-indexeddb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,156 @@ pub use state_store::{
MigrationConflictStrategy,
};

#[cfg(feature = "event-cache-store")]
pub use crate::event_cache_store::{
IndexeddbEventCacheStore, IndexeddbEventCacheStoreBuilder, IndexeddbEventCacheStoreError,
};
#[cfg(feature = "media-store")]
pub use crate::media_store::{
IndexeddbMediaStore, IndexeddbMediaStoreBuilder, IndexeddbMediaStoreError,
};

/// Structure containing implementations of every type
/// of store using IndexedDB for persistent storage.
///
/// Note that each of the stores is behind a feature flag and will
/// only be available when its corresponding flag is set.
pub struct IndexeddbStores {
/// An IndexedDB-backed implementation of [`CryptoStore`][1]
///
/// [1]: matrix_sdk_crypto::store::CryptoStore
#[cfg(feature = "e2e-encryption")]
pub crypto: IndexeddbCryptoStore,
/// An IndexedDB-backed implementation of [`StateStore`][1]
///
/// [1]: matrix_sdk_base::store::StateStore
#[cfg(feature = "state-store")]
pub state: IndexeddbStateStore,
/// An IndexedDB-backed implementation of [`EventCacheStore`][1]
///
/// [1]: matrix_sdk_base::event_cache::store::EventCacheStore
#[cfg(feature = "event-cache-store")]
pub event_cache: IndexeddbEventCacheStore,
/// An IndexedDB-backed implementation of [`MediaStore`][1]
///
/// [1]: matrix_sdk_base::media::store::MediaStore
#[cfg(feature = "media-store")]
pub media: IndexeddbMediaStore,
}

impl IndexeddbStores {
/// Opens and returns all stores using the given database name and,
/// optionally, a passphrase.
///
/// If `e2e-encryption` and `state-store` features are not enabled,
/// `passphrase` is ignored. Otherwise `passphrase` is used to import or
/// create a [`StoreCipher`][1] which encrypts contents of all stores.
///
/// Note that each of the stores is behind a feature flag and will only be
/// opened when the corresponding flag is set.
///
/// [1]: matrix_sdk_store_encryption::StoreCipher
pub async fn open(
name: &str,
#[allow(unused_variables)] passphrase: Option<&str>,
) -> Result<Self, OpenStoreError> {
#[cfg(all(feature = "e2e-encryption", feature = "state-store"))]
if let Some(passphrase) = passphrase {
return Self::open_with_passphrase(name, passphrase).await;
}

Self::open_without_passphrase(name).await
}

/// Opens and returns all stores using the given database name. Contents of
/// the stores are NOT encrypted.
///
/// Note that each of the stores is behind a feature flag and will only be
/// opened when the corresponding flag is set.
#[allow(clippy::unused_async)]
pub async fn open_without_passphrase(name: &str) -> Result<Self, OpenStoreError> {
#[cfg(feature = "state-store")]
let state = IndexeddbStateStore::builder()
.name(name.to_owned())
.build()
.await
.map_err(StoreError::from)?;

#[cfg(feature = "e2e-encryption")]
let crypto = IndexeddbCryptoStore::open_with_name(name).await?;

#[cfg(feature = "event-cache-store")]
let event_cache = IndexeddbEventCacheStoreBuilder::with_prefix(name).build().await?;

#[cfg(feature = "media-store")]
let media = IndexeddbMediaStoreBuilder::with_prefix(name).build().await?;

Ok(Self {
#[cfg(feature = "state-store")]
state,
#[cfg(feature = "e2e-encryption")]
crypto,
#[cfg(feature = "event-cache-store")]
event_cache,
#[cfg(feature = "media-store")]
media,
})
}

/// Opens and returns all stores using the given database name and
/// passphrase. Passphrase is used to import or create a [`StoreCipher`][1]
/// which encrypts contents of all stores.
///
/// Note that [`IndexeddbEventCacheStore`] and [`IndexeddbMediaStore`] are
/// behind feature flags and will only be opened when their
/// corresponding flags are set.
///
/// [1]: matrix_sdk_store_encryption::StoreCipher
#[cfg(all(feature = "e2e-encryption", feature = "state-store"))]
pub async fn open_with_passphrase(
name: &str,
passphrase: &str,
) -> Result<Self, OpenStoreError> {
let state = IndexeddbStateStore::builder()
.name(name.to_owned())
.passphrase(passphrase.to_owned())
.build()
.await
.map_err(StoreError::from)?;
let store_cipher =
state.store_cipher.clone().ok_or(OpenStoreError::FailedToLoadStoreCipher)?;

let crypto =
IndexeddbCryptoStore::open_with_store_cipher(name, Some(store_cipher.clone())).await?;

#[cfg(feature = "event-cache-store")]
let event_cache = IndexeddbEventCacheStoreBuilder::with_prefix(name)
.store_cipher(store_cipher.clone())
.build()
.await?;

#[cfg(feature = "media-store")]
let media = IndexeddbMediaStoreBuilder::with_prefix(name)
.store_cipher(store_cipher.clone())
.build()
.await?;

Ok(Self {
state,
crypto,
#[cfg(feature = "event-cache-store")]
event_cache,
#[cfg(feature = "media-store")]
media,
})
}
}

/// Create a [`IndexeddbStateStore`] and a [`IndexeddbCryptoStore`] that use the
/// same name and passphrase.
#[deprecated(
note = "this function only opens state and crypto stores, use `IndexeddbStores::open()` instead."
)]
#[cfg(all(feature = "e2e-encryption", feature = "state-store"))]
pub async fn open_stores_with_name(
name: &str,
Expand Down Expand Up @@ -75,4 +223,22 @@ pub enum OpenStoreError {
#[cfg(feature = "e2e-encryption")]
#[error(transparent)]
Crypto(#[from] IndexeddbCryptoStoreError),

/// An error occurred while trying to load a [`StoreCipher`][1] from a
/// passphrase
///
/// [1]: matrix_sdk_store_encryption::StoreCipher
#[cfg(feature = "e2e-encryption")]
#[error("failed to load store cipher")]
FailedToLoadStoreCipher,

/// An error occurred with the event cache store implementation.
#[cfg(feature = "event-cache-store")]
#[error(transparent)]
Event(#[from] IndexeddbEventCacheStoreError),

/// An error occurred with the media store implementation.
#[cfg(feature = "media-store")]
#[error(transparent)]
Media(#[from] IndexeddbMediaStoreError),
}
12 changes: 11 additions & 1 deletion crates/matrix-sdk-indexeddb/src/media_store/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
media_store::{
error::IndexeddbMediaStoreError, migrations::open_and_upgrade_db, IndexeddbMediaStore,
},
serializer::{IndexedTypeSerializer, SafeEncodeSerializer},
serializer::{indexed_type::IndexedTypeSerializer, safe_encode::types::SafeEncodeSerializer},
};

/// A type for conveniently building an [`IndexeddbMediaStore`]
Expand All @@ -44,6 +44,16 @@ impl IndexeddbMediaStoreBuilder {
/// [`IndexeddbMediaStore`]
pub const DEFAULT_DATABASE_NAME: &'static str = "media";

/// Create a new [`IndexeddbMediaStoreBuilder`] where the database name is
/// constructed by joining the given prefix with
/// [`Self::DEFAULT_DATABASE_NAME`] and separated by `::`.
pub fn with_prefix(prefix: &str) -> Self {
Self {
database_name: format!("{}::{}", prefix, Self::DEFAULT_DATABASE_NAME),
store_cipher: None,
}
}

/// Sets the name of the IndexedDB database which will be opened. This
/// defaults to [`Self::DEFAULT_DATABASE_NAME`].
pub fn database_name(mut self, name: String) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion crates/matrix-sdk-indexeddb/src/media_store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use crate::{
transaction::IndexeddbMediaStoreTransaction,
types::{Lease, Media, MediaCleanupTime, MediaContent, MediaMetadata, UnixTime},
},
serializer::{Indexed, IndexedTypeSerializer},
serializer::indexed_type::{traits::Indexed, IndexedTypeSerializer},
transaction::TransactionError,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ use crate::{
serializer::indexed_types::{IndexedMediaContentId, IndexedMediaContentSize},
types::UnixTime,
},
serializer::{
indexed_type::constants::{INDEXED_KEY_LOWER_UUID, INDEXED_KEY_UPPER_UUID},
INDEXED_KEY_UPPER_DURATION_SECONDS,
serializer::indexed_type::constants::{
INDEXED_KEY_LOWER_UUID, INDEXED_KEY_UPPER_DURATION_SECONDS, INDEXED_KEY_UPPER_UUID,
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,13 @@ use crate::{
types::{Lease, MediaCleanupTime, MediaContent, MediaMetadata, UnixTime},
},
serializer::{
Indexed, IndexedKey, IndexedKeyComponentBounds, IndexedPrefixKeyComponentBounds,
MaybeEncrypted, SafeEncodeSerializer, INDEXED_KEY_LOWER_STRING, INDEXED_KEY_UPPER_STRING,
indexed_type::{
constants::{INDEXED_KEY_LOWER_STRING, INDEXED_KEY_UPPER_STRING},
traits::{
Indexed, IndexedKey, IndexedKeyComponentBounds, IndexedPrefixKeyComponentBounds,
},
},
safe_encode::types::{MaybeEncrypted, SafeEncodeSerializer},
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ use crate::{
},
types::{Lease, Media, MediaCleanupTime, MediaContent, MediaMetadata, UnixTime},
},
serializer::{IndexedKeyRange, IndexedPrefixKeyComponentBounds, IndexedTypeSerializer},
serializer::indexed_type::{
range::IndexedKeyRange, traits::IndexedPrefixKeyComponentBounds, IndexedTypeSerializer,
},
transaction::{Transaction, TransactionError},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use thiserror::Error;
use traits::{Indexed, IndexedKey};
use wasm_bindgen::JsValue;

use crate::serializer::SafeEncodeSerializer;
use crate::serializer::safe_encode::types::SafeEncodeSerializer;

#[derive(Debug, Error)]
pub enum IndexedTypeSerializerError<IndexingError> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
// limitations under the License

use crate::serializer::{
Indexed, IndexedKey, IndexedKeyBounds, IndexedPrefixKeyBounds, SafeEncodeSerializer,
indexed_type::traits::{Indexed, IndexedKey, IndexedKeyBounds, IndexedPrefixKeyBounds},
safe_encode::types::SafeEncodeSerializer,
};

/// Representation of a range of keys of type `K`. This is loosely
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License

use crate::serializer::SafeEncodeSerializer;
use crate::serializer::safe_encode::types::SafeEncodeSerializer;

/// A conversion trait for preparing high-level types into indexed types
/// which are better suited for storage in IndexedDB.
Expand Down
Loading
Loading