diff --git a/Cargo.toml b/Cargo.toml index 576ab7008e..48b0870fe4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,14 +6,24 @@ members = [ "keystore", "keystore-dump", "mls-provider", - "interop" -, "decode"] + "interop", + "decode", +] exclude = [ "extras/webdriver-installation", - "extras/keystore-regression-versions" + "extras/keystore-regression-versions", ] resolver = "2" +[workspace.lints.clippy] +missing_safety_doc = "deny" +undocumented_unsafe_blocks = "deny" + +[workspace.lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(wasm_bindgen_unstable_test_coverage)', +] } + [workspace.dependencies] async-lock = "3.4" async-recursion = "1" @@ -26,7 +36,12 @@ const_format = "0.2" core-crypto = { path = "crypto" } core-crypto-keystore = { path = "keystore" } core-crypto-macros = { path = "crypto-macros" } -derive_more = { version = "0.99", features = ["from", "into", "deref", "deref_mut"] } +derive_more = { version = "0.99", features = [ + "from", + "into", + "deref", + "deref_mut", +] } futures-util = "0.3" hex = "0.4" idb = "0.6" @@ -37,7 +52,7 @@ log-reload = "0.1.0" mls-crypto-provider = { path = "mls-provider" } pem = "3.0" rand = { version = "0.8", features = ["getrandom"] } -rexie = "0.6.1" # TODO: remove once migration tests have been moved to rexie +rexie = "0.6.1" # TODO: remove once migration tests have been moved to rexie schnellru = "0.2" serde = "1.0" serde_json = "1.0" diff --git a/crypto-ffi/Cargo.toml b/crypto-ffi/Cargo.toml index 60a7926564..a722d05e28 100644 --- a/crypto-ffi/Cargo.toml +++ b/crypto-ffi/Cargo.toml @@ -16,6 +16,9 @@ name = "uniffi-bindgen" path = "uniffi-bindgen.rs" required-features = ["uniffi/cli"] +[lints] +workspace = true + [features] default = ["proteus"] proteus = [ @@ -81,11 +84,9 @@ wasm-opt = [ "--detect-features", ] -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = [ - 'cfg(wasm_bindgen_unstable_test_coverage)', -] } - [dev-dependencies] testing_logger = "0.1.1" -tokio = { version = "1.43.0", default-features = false, features = ["macros", "rt"] } +tokio = { version = "1.43.0", default-features = false, features = [ + "macros", + "rt", +] } diff --git a/crypto-ffi/src/wasm/mod.rs b/crypto-ffi/src/wasm/mod.rs index 9f5e091fcb..a51256554f 100644 --- a/crypto-ffi/src/wasm/mod.rs +++ b/crypto-ffi/src/wasm/mod.rs @@ -1183,6 +1183,13 @@ pub struct CoreCryptoWasmLogger { ctx: JsValue, } +// SAFETY: WASM only ever runs in a single-threaded context, so this is intrinsically thread-safe. +// If that invariant ever varies, we may need to rethink this (but more likely that would be addressed +// upstream where the types are defined). +unsafe impl Send for CoreCryptoWasmLogger {} +// SAFETY: WASM only ever runs in a single-threaded context, so this is intrinsically thread-safe. +unsafe impl Sync for CoreCryptoWasmLogger {} + #[wasm_bindgen] #[derive(Debug, Clone, Copy)] #[repr(u8)] @@ -1385,9 +1392,8 @@ Please make all callbacks `async` or manually return a `Promise` via `Promise.re // SAFETY: All callback instances are wrapped into Arc so this is safe to mark unsafe impl Send for MlsTransportProvider {} +// SAFETY: All callback instances are wrapped into Arc so this is safe to mark unsafe impl Sync for MlsTransportProvider {} -unsafe impl Send for CoreCryptoWasmLogger {} -unsafe impl Sync for CoreCryptoWasmLogger {} #[async_trait::async_trait(?Send)] impl MlsTransport for MlsTransportProvider { diff --git a/crypto-macros/Cargo.toml b/crypto-macros/Cargo.toml index 14633bb419..624a6678ce 100644 --- a/crypto-macros/Cargo.toml +++ b/crypto-macros/Cargo.toml @@ -9,6 +9,9 @@ license = "GPL-3.0-only" [lib] proc-macro = true +[lints] +workspace = true + [dependencies] syn = { version = "2", features = ["full"] } quote = "1" diff --git a/crypto-macros/src/entity_derive/derive_impl.rs b/crypto-macros/src/entity_derive/derive_impl.rs index be65cff1ba..8992b541e7 100644 --- a/crypto-macros/src/entity_derive/derive_impl.rs +++ b/crypto-macros/src/entity_derive/derive_impl.rs @@ -92,6 +92,7 @@ impl KeyStoreEntityFlattened { conn: &mut Self::ConnectionType, params: crate::entities::EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query = #find_all_query.to_string() + ¶ms.to_sql(); @@ -120,6 +121,7 @@ impl KeyStoreEntityFlattened { conn: &mut Self::ConnectionType, id: &crate::entities::StringEntityId, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; @@ -152,7 +154,8 @@ impl KeyStoreEntityFlattened { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row(&#count_query, [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row(&#count_query, [], |r| r.get(0)).map_err(Into::into) } } } diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 265ff5a191..261d39b351 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -11,10 +11,25 @@ publish = false name = "core_crypto" crate-type = ["lib", "cdylib"] +[lints] +workspace = true + [features] default = ["proteus", "cryptobox-migrate"] -proteus = ["dep:proteus-wasm", "dep:proteus-traits", "core-crypto-keystore/proteus-keystore"] -cryptobox-migrate = ["proteus", "proteus-wasm?/cryptobox-identity", "dep:async-fs", "dep:futures-lite", "dep:rexie", "dep:idb", "dep:base64"] +proteus = [ + "dep:proteus-wasm", + "dep:proteus-traits", + "core-crypto-keystore/proteus-keystore", +] +cryptobox-migrate = [ + "proteus", + "proteus-wasm?/cryptobox-identity", + "dep:async-fs", + "dep:futures-lite", + "dep:rexie", + "dep:idb", + "dep:base64", +] # for test/bench all ciphersuites test-all-cipher = [] # execute benches with also real db to better see overhead @@ -58,7 +73,10 @@ proteus-traits = { workspace = true, optional = true } sha2 = "0.10.8" [target.'cfg(not(target_family = "wasm"))'.dependencies] -sysinfo = { version = "0.32", default-features = false, features = ["apple-app-store", "system"] } +sysinfo = { version = "0.32", default-features = false, features = [ + "apple-app-store", + "system", +] } async-fs = { version = "2.1", optional = true } futures-lite = { version = "2.6", optional = true } @@ -105,7 +123,12 @@ version = "0.5" features = ["async_std", "html_reports"] [package.metadata.wasm-pack.profile.release] -wasm-opt = ["-Os", "--enable-mutable-globals", "--enable-threads", "--detect-features"] +wasm-opt = [ + "-Os", + "--enable-mutable-globals", + "--enable-threads", + "--detect-features", +] [[bench]] name = "key_package" @@ -141,6 +164,3 @@ anyhow = "1.0.95" # is available on the command line. If not, we should replace this with # `vergen-gix` or `vergen-git2`. vergen-gitcl = { version = "1.0.2", features = ["build", "cargo"] } - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(wasm_bindgen_unstable_test_coverage)'] } diff --git a/decode/Cargo.toml b/decode/Cargo.toml index f7396067a8..2d59185760 100644 --- a/decode/Cargo.toml +++ b/decode/Cargo.toml @@ -4,8 +4,11 @@ version = "0.1.0" edition = "2021" license = "GPL-3.0-only" +[lints] +workspace = true + [dependencies] clap = { version = "4.5.27", features = ["derive"] } -proteus-wasm = { workspace = true, features = ["serde"]} +proteus-wasm = { workspace = true, features = ["serde"] } base64 = { workspace = true } openmls = { workspace = true } diff --git a/extras/keystore-regression-versions/Cargo.toml b/extras/keystore-regression-versions/Cargo.toml index 42b2e65284..310c8cd68b 100644 --- a/extras/keystore-regression-versions/Cargo.toml +++ b/extras/keystore-regression-versions/Cargo.toml @@ -13,4 +13,3 @@ rand = "0.8" clap = { version = "4", features = ["derive"] } cfg-if = "1" indicatif = { version = "0.17", features = ["futures"] } - diff --git a/extras/webdriver-installation/Cargo.toml b/extras/webdriver-installation/Cargo.toml index a268aeca87..d1814d4848 100644 --- a/extras/webdriver-installation/Cargo.toml +++ b/extras/webdriver-installation/Cargo.toml @@ -20,7 +20,12 @@ url = "2.3" reqwest = { version = "0.11", features = ["json", "stream"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -chrono = { version = "0.4", default-features = false, features = ["std", "clock", "wasmbind", "serde"] } +chrono = { version = "0.4", default-features = false, features = [ + "std", + "clock", + "wasmbind", + "serde", +] } semver = { version = "1.0", features = ["serde"] } tempfile = "3.3" futures-util = "0.3" diff --git a/interop/Cargo.toml b/interop/Cargo.toml index 1dba856dd9..9b19531046 100644 --- a/interop/Cargo.toml +++ b/interop/Cargo.toml @@ -11,9 +11,12 @@ proteus = [ "dep:proteus", "dep:proteus-wasm", "core-crypto/cryptobox-migrate", - "core-crypto/proteus" + "core-crypto/proteus", ] +[lints] +workspace = true + [dependencies] color-eyre = "0.6" log = "0.4" @@ -37,7 +40,9 @@ uuid = { workspace = true, features = ["v4"] } tempfile = { version = "3.15" } # Terminal support xshell = "0.2" -spinoff = { version = "0.8", features = ["aesthetic"], default-features = false } +spinoff = { version = "0.8", features = [ + "aesthetic", +], default-features = false } serde = { workspace = true, features = ["derive"] } thiserror = { workspace = true } @@ -52,4 +57,3 @@ warp = { version = "0.3", default-features = false } webdriver-installation = { path = "../extras/webdriver-installation" } fantoccini = "0.21" proteus-wasm = { workspace = true, optional = true } - diff --git a/keystore-dump/Cargo.toml b/keystore-dump/Cargo.toml index 0d5b231004..2d101f2ca2 100644 --- a/keystore-dump/Cargo.toml +++ b/keystore-dump/Cargo.toml @@ -5,11 +5,13 @@ version = "4.0.0" edition = "2021" license = "GPL-3.0-only" +[lints] +workspace = true + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] color-eyre = "0.6" - [target.'cfg(not(target_family = "wasm"))'.dependencies] core-crypto-keystore = { workspace = true, features = ["serde"] } core-crypto = { path = "../crypto" } @@ -28,7 +30,11 @@ openmls_basic_credential.workspace = true openmls_x509_credential.workspace = true tls_codec.workspace = true -chrono = { version = "0.4", default-features = false, features = ["clock", "std", "serde"] } +chrono = { version = "0.4", default-features = false, features = [ + "clock", + "std", + "serde", +] } [target.'cfg(not(target_family = "wasm"))'.dependencies.proteus-wasm] workspace = true diff --git a/keystore/Cargo.toml b/keystore/Cargo.toml index c630a69575..4d63f77d9a 100644 --- a/keystore/Cargo.toml +++ b/keystore/Cargo.toml @@ -19,10 +19,17 @@ harness = false name = "write" harness = false +[lints] +workspace = true + [features] default = ["proteus-keystore"] proteus-keystore = ["dep:proteus-traits"] -ios-wal-compat = ["dep:security-framework", "dep:security-framework-sys", "dep:core-foundation"] +ios-wal-compat = [ + "dep:security-framework", + "dep:security-framework-sys", + "dep:core-foundation", +] idb-regression-test = [] log-queries = ["rusqlite/trace"] serde = ["dep:serde"] @@ -66,7 +73,7 @@ features = [ "limits", "unlock_notify", "uuid", - "functions" + "functions", ] [target.'cfg(not(target_family = "wasm"))'.dependencies.refinery] @@ -105,7 +112,10 @@ rstest = "0.24" rstest_reuse = "0.7" async-std = { workspace = true, features = ["attributes"] } futures-lite = "2.6" -core-crypto-keystore = { path = ".", features = ["idb-regression-test", "log-queries"] } +core-crypto-keystore = { path = ".", features = [ + "idb-regression-test", + "log-queries", +] } pretty_env_logger = "0.5" proteus-wasm = { workspace = true } @@ -114,7 +124,9 @@ version = "0.5" features = ["async_futures", "html_reports"] [package.metadata.wasm-pack.profile.release] -wasm-opt = ["-Os", "--enable-mutable-globals", "--enable-threads", "--detect-features"] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(wasm_bindgen_unstable_test_coverage)'] } +wasm-opt = [ + "-Os", + "--enable-mutable-globals", + "--enable-threads", + "--detect-features", +] diff --git a/keystore/src/connection/mod.rs b/keystore/src/connection/mod.rs index ab736c62ad..e6252a3812 100644 --- a/keystore/src/connection/mod.rs +++ b/keystore/src/connection/mod.rs @@ -58,7 +58,9 @@ pub trait DatabaseConnectionRequirements: Sized {} #[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))] #[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)] -pub trait DatabaseConnection: DatabaseConnectionRequirements { +pub trait DatabaseConnection<'a>: DatabaseConnectionRequirements { + type Connection: 'a; + async fn open(name: &str, key: &str) -> CryptoKeystoreResult; async fn open_in_memory(name: &str, key: &str) -> CryptoKeystoreResult; @@ -82,13 +84,6 @@ pub trait DatabaseConnection: DatabaseConnectionRequirements { Ok(()) } - #[cfg(not(target_family = "wasm"))] - async fn new_transaction(&mut self) -> CryptoKeystoreResult>; - #[cfg(target_family = "wasm")] - async fn new_transaction>( - &mut self, - tables: &[T], - ) -> CryptoKeystoreResult>; } #[derive(Debug, Clone)] @@ -126,8 +121,9 @@ pub trait FetchFromDatabase: Send + Sync { async fn count>(&self) -> CryptoKeystoreResult; } -// * SAFETY: this has mutexes and atomics protecting underlying data so this is safe to share between threads +// SAFETY: this has mutexes and atomics protecting underlying data so this is safe to share between threads unsafe impl Send for Connection {} +// SAFETY: this has mutexes and atomics protecting underlying data so this is safe to share between threads unsafe impl Sync for Connection {} impl Connection { diff --git a/keystore/src/connection/platform/generic/mod.rs b/keystore/src/connection/platform/generic/mod.rs index 0afdac64f3..d11de8954c 100644 --- a/keystore/src/connection/platform/generic/mod.rs +++ b/keystore/src/connection/platform/generic/mod.rs @@ -18,24 +18,36 @@ use std::ops::Deref; use crate::connection::{DatabaseConnection, DatabaseConnectionRequirements}; use crate::CryptoKeystoreResult; +use async_lock::{Mutex, MutexGuard}; use blocking::unblock; use rusqlite::{functions::FunctionFlags, Transaction}; refinery::embed_migrations!("src/connection/platform/generic/migrations"); -#[derive(Debug)] -pub struct SqlCipherConnection { - conn: rusqlite::Connection, - path: String, -} - pub struct TransactionWrapper<'conn> { transaction: Transaction<'conn>, } + impl TransactionWrapper<'_> { // this is async just to conform with the wasm impl pub(crate) async fn commit_tx(self) -> CryptoKeystoreResult<()> { - Ok(self.transaction.commit()?) + // It's really not ideal to do potentially-heavy IO such as committing a transaction + // within the async context, because Rust async depends on inserting cooperative yields + // in appropriate places, and blocking functions simply do not have those. This is going + // to bind up the whole async executor every time we try to commit the transaction, for + // the entire duration of the execution of the transaction. + // + // We can't even do `unblock(|| transaction.commit())` here becase `Transaction: !Send`. + // + // Hopefully either WPB-14326, WPB-14327, or WPB-15766 will open a path to a unified + // async database which can give us better performance characteristics than this. + self.transaction.commit().map_err(Into::into) + } +} + +impl<'conn> From> for TransactionWrapper<'conn> { + fn from(transaction: Transaction<'conn>) -> Self { + TransactionWrapper { transaction } } } @@ -47,26 +59,28 @@ impl<'conn> Deref for TransactionWrapper<'conn> { } } -// Safety: Both these structs are properly being locked with a RwLock and for the transaction it is created -// and dropped in a single call. -unsafe impl Send for SqlCipherConnection {} -unsafe impl Sync for SqlCipherConnection {} +// SAFETY: This is **UNSAFE**. Transactions are intentionally `!Send`, +// and we do nothing to provide guarantees which would make them safe to share between threads. +// See https://github.com/rusqlite/rusqlite/issues/697 for discussion on this. +// +// Unfortunately, everything breaks for now if we simply remove this. This is going to take +// non-trivial work to fix. See https://wearezeta.atlassian.net/browse/WPB-15767. unsafe impl Send for TransactionWrapper<'_> {} +// SAFETY: This is **UNSAFE**. See above. unsafe impl Sync for TransactionWrapper<'_> {} -impl std::ops::Deref for SqlCipherConnection { - type Target = rusqlite::Connection; - - fn deref(&self) -> &Self::Target { - &self.conn - } +#[derive(Debug)] +pub struct SqlCipherConnection { + conn: Mutex, + path: String, } -impl std::ops::DerefMut for SqlCipherConnection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.conn - } -} +// SAFETY: An `Arc` is unnecessary as `SqlCipherConnection: !Clone`, and there is a `Mutex` +// internally which ensures unique access. +unsafe impl Send for SqlCipherConnection {} +// SAFETY: An `Arc` is unnecessary as `SqlCipherConnection: !Clone`, and there is a `Mutex` +// internally which ensures unique access. +unsafe impl Sync for SqlCipherConnection {} impl SqlCipherConnection { fn init_with_key(path: &str, key: &str) -> CryptoKeystoreResult { @@ -94,6 +108,8 @@ impl SqlCipherConnection { // Disable FOREIGN KEYs - The 2 step blob writing process invalidates foreign key checks unfortunately conn.pragma_update(None, "foreign_keys", "OFF")?; + let conn = Mutex::new(conn); + let mut conn = Self { path: path.into(), conn, @@ -120,6 +136,8 @@ impl SqlCipherConnection { // Disable FOREIGN KEYs - The 2 step blob writing process invalidates foreign key checks unfortunately conn.pragma_update(None, "foreign_keys", "OFF")?; + let conn = Mutex::new(conn); + let mut conn = Self { path: "".into(), conn }; // Need to run migrations also in memory to make sure expected tables exist. @@ -128,6 +146,14 @@ impl SqlCipherConnection { Ok(conn) } + pub async fn conn(&self) -> MutexGuard { + self.conn.lock().await + } + + pub fn conn_blocking(&self) -> MutexGuard { + self.conn.lock_blocking() + } + pub async fn wipe(self) -> CryptoKeystoreResult<()> { if self.path.is_empty() { return Ok(()); @@ -141,7 +167,8 @@ impl SqlCipherConnection { } fn close(self) -> CryptoKeystoreResult<()> { - Ok(self.conn.close().map_err(|(_, e)| e)?) + let conn = self.conn.into_inner(); + conn.close().map_err(|(_, e)| e.into()) } /// To prevent iOS from killing backgrounded apps using a WAL-journaled file, @@ -181,34 +208,53 @@ impl SqlCipherConnection { pub static kSecAttrAccessible: CFStringRef; } + macro_rules! wrap_under_get_rule { + ($external_ref:expr) => { + // SAFETY: The method `CFString::wrap_under_get_rule` is required by rustc to be marked as unsafe + // because accessing any static item via FFI is intrinsically unsafe. For this reason, we can't + // just create a safe wrapper function here; rustc immediately flags it with an [E0133] because it + // needs that FFI static item to be its parameter. + // + // There isn't safety documentation anywhere in the CFString or TCFType documentation, and + // the implementation does only [basic checks], so we can assume that the main property we + // need to uphold is "the reference is not null". + // + // [E0133]: https://doc.rust-lang.org/stable/error_codes/E0133.html + // [basic checks]: https://github.com/servo/core-foundation-rs/blob/core-foundation-v0.10.0/core-foundation/src/lib.rs#L91-L95 + unsafe { CFString::wrap_under_get_rule($external_ref) } + }; + } + // Create a query that matches a: let query_params = CFDictionary::from_CFType_pairs(&[ // Class GenericPassword - (unsafe { CFString::wrap_under_get_rule(kSecClass) }, unsafe { - CFString::wrap_under_get_rule(kSecClassGenericPassword).as_CFType() - }), + ( + wrap_under_get_rule!(kSecClass), + wrap_under_get_rule!(kSecClassGenericPassword).as_CFType(), + ), // with Service = "wire.com" ( - unsafe { CFString::wrap_under_get_rule(kSecAttrService) }, + wrap_under_get_rule!(kSecAttrService), CFString::from(WIRE_SERVICE_NAME).as_CFType(), ), // Holding account name = `key` (in the following form: `keystore_salt_[sha256(file_path)]`) - ( - unsafe { CFString::wrap_under_get_rule(kSecAttrAccount) }, - CFString::from(key).as_CFType(), - ), + (wrap_under_get_rule!(kSecAttrAccount), CFString::from(key).as_CFType()), ]); // And now we ask to update the following properties: let payload_params = CFDictionary::from_CFType_pairs(&[( // Keychain Accessibility setting // See: https://developer.apple.com/documentation/security/ksecattraccessible - unsafe { CFString::wrap_under_get_rule(kSecAttrAccessible) }, + wrap_under_get_rule!(kSecAttrAccessible), // Set to AccessibleAfterFirstUnlock (i.e. is accessible after the first post-boot unlock) - unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleAfterFirstUnlock).as_CFType() }, + wrap_under_get_rule!(kSecAttrAccessibleAfterFirstUnlock).as_CFType(), )]); // Update the item in the keychain + // + // SAFETY: As before, the main source of unsafety here appears to simply be that this is an FFI function + // and nobody has constructed a safe wrapper aroud it. And sure, we can't trust the safety properties that + // external code has. But on the other hand, we can't not call this function. So the unsafe block should be fine. match unsafe { security_framework_sys::keychain_item::SecItemUpdate( query_params.as_concrete_TypeRef(), @@ -256,14 +302,14 @@ impl SqlCipherConnection { } fn run_migrations(&mut self) -> CryptoKeystoreResult<()> { - self.conn - .create_scalar_function("sha256_blob", 1, FunctionFlags::SQLITE_DETERMINISTIC, |ctx| { - let input_blob = ctx.get::>(0)?; - Ok(crate::sha256(&input_blob)) - })?; - let report = migrations::runner().run(&mut self.conn).map_err(Box::new)?; + let mut conn = self.conn_blocking(); + conn.create_scalar_function("sha256_blob", 1, FunctionFlags::SQLITE_DETERMINISTIC, |ctx| { + let input_blob = ctx.get::>(0)?; + Ok(crate::sha256(&input_blob)) + })?; + let report = migrations::runner().run(&mut *conn).map_err(Box::new)?; if let Some(version) = report.applied_migrations().iter().map(|m| m.version()).max() { - self.conn.pragma_update(None, "schema_version", version)?; + conn.pragma_update(None, "schema_version", version)?; } Ok(()) @@ -274,7 +320,9 @@ impl DatabaseConnectionRequirements for SqlCipherConnection {} #[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))] #[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)] -impl DatabaseConnection for SqlCipherConnection { +impl<'a> DatabaseConnection<'a> for SqlCipherConnection { + type Connection = MutexGuard<'a, rusqlite::Connection>; + async fn open(name: &str, key: &str) -> CryptoKeystoreResult { let name = name.to_string(); let key = key.to_string(); @@ -295,9 +343,4 @@ impl DatabaseConnection for SqlCipherConnection { self.wipe().await?; Ok(()) } - async fn new_transaction(&mut self) -> CryptoKeystoreResult> { - Ok(TransactionWrapper { - transaction: self.conn.transaction()?, - }) - } } diff --git a/keystore/src/connection/platform/wasm/migrations/keystore_v_1_0_0/connection/mod.rs b/keystore/src/connection/platform/wasm/migrations/keystore_v_1_0_0/connection/mod.rs index ef53f8a1f7..af1f5b4cbc 100644 --- a/keystore/src/connection/platform/wasm/migrations/keystore_v_1_0_0/connection/mod.rs +++ b/keystore/src/connection/platform/wasm/migrations/keystore_v_1_0_0/connection/mod.rs @@ -76,8 +76,9 @@ pub struct Connection { pub(crate) conn: Arc>, } -// * SAFETY: this has mutexes and atomics protecting underlying data so this is safe to share between threads +// SAFETY: this has mutexes and atomics protecting underlying data so this is safe to share between threads unsafe impl Send for Connection {} +// SAFETY: this has mutexes and atomics protecting underlying data so this is safe to share between threads unsafe impl Sync for Connection {} impl Connection { diff --git a/keystore/src/connection/platform/wasm/mod.rs b/keystore/src/connection/platform/wasm/mod.rs index 3730d8999c..5370007a4d 100644 --- a/keystore/src/connection/platform/wasm/mod.rs +++ b/keystore/src/connection/platform/wasm/mod.rs @@ -41,13 +41,20 @@ impl WasmConnection { pub fn storage_mut(&mut self) -> &mut WasmEncryptedStorage { &mut self.conn } + + // for compatibility with the uniffi version + pub async fn conn(&self) -> TransactionCreator { + TransactionCreator { conn: &self.conn } + } } impl DatabaseConnectionRequirements for WasmConnection {} #[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))] #[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)] -impl DatabaseConnection for WasmConnection { +impl<'a> DatabaseConnection<'a> for WasmConnection { + type Connection = &'a WasmEncryptedStorage; + async fn open(name: &str, key: &str) -> CryptoKeystoreResult { let name = name.to_string(); // ? Maybe find a cleaner way to define the schema @@ -85,10 +92,19 @@ impl DatabaseConnection for WasmConnection { Ok(()) } +} + +/// A connection reference which can create a new transaction. +/// +/// This is kind of weird but it's necessary for interop with the generic/uniffi side. +pub struct TransactionCreator<'a> { + conn: &'a WasmEncryptedStorage, +} - async fn new_transaction>( +impl TransactionCreator<'_> { + pub async fn new_transaction( &mut self, - tables: &[T], + tables: &[impl AsRef], ) -> CryptoKeystoreResult> { match &self.conn.storage { WasmStorageWrapper::Persistent(db) => Ok(WasmStorageTransaction::Persistent { diff --git a/keystore/src/entities/mls.rs b/keystore/src/entities/mls.rs index 365dcb3322..b36a8358c2 100644 --- a/keystore/src/entities/mls.rs +++ b/keystore/src/entities/mls.rs @@ -261,6 +261,7 @@ pub trait UniqueEntity: EntityBase) -> Self; async fn find_unique(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; @@ -296,11 +297,11 @@ pub trait UniqueEntity: EntityBase CryptoKeystoreResult { - Ok( - conn.query_row(&format!("SELECT COUNT(*) FROM {}", Self::COLLECTION_NAME), [], |r| { - r.get(0) - })?, - ) + let conn = conn.conn().await; + conn.query_row(&format!("SELECT COUNT(*) FROM {}", Self::COLLECTION_NAME), [], |r| { + r.get(0) + }) + .map_err(Into::into) } fn content(&self) -> &[u8]; diff --git a/keystore/src/entities/mod.rs b/keystore/src/entities/mod.rs index 2d76cba666..578c365907 100644 --- a/keystore/src/entities/mod.rs +++ b/keystore/src/entities/mod.rs @@ -132,8 +132,8 @@ impl EntityFindParams { #[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))] #[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)] -pub trait EntityBase: Send + Sized + Clone + PartialEq + Eq + std::fmt::Debug { - type ConnectionType: DatabaseConnection; +pub trait EntityBase: 'static + Send + Sized + Clone + PartialEq + Eq + std::fmt::Debug { + type ConnectionType: for<'a> DatabaseConnection<'a>; type AutoGeneratedFields: Default; /// Beware: if you change the value of this constant on any WASM entity, you'll need to do a data migration /// not only because it is used as reference to the object store names but also for the value of the aad. @@ -142,12 +142,8 @@ pub trait EntityBase: Send + Sized + Clone + PartialEq + Eq + std::fmt::Debug { fn to_missing_key_err_kind() -> MissingKeyErrorKind; fn downcast(&self) -> Option<&T> { - if T::COLLECTION_NAME == Self::COLLECTION_NAME { - // SAFETY: The above check ensures that this transmutation is safe. - Some(unsafe { std::mem::transmute::<&Self, &T>(self) }) - } else { - None - } + let as_dyn_any: &dyn std::any::Any = self; + as_dyn_any.downcast_ref() } fn to_transaction_entity(self) -> crate::transaction::dynamic_dispatch::Entity; diff --git a/keystore/src/entities/platform/generic/mls/credential.rs b/keystore/src/entities/platform/generic/mls/credential.rs index feebaf24f1..c744a80843 100644 --- a/keystore/src/entities/platform/generic/mls/credential.rs +++ b/keystore/src/entities/platform/generic/mls/credential.rs @@ -44,6 +44,7 @@ impl Entity for MlsCredential { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!( "SELECT rowid, unixepoch(created_at) FROM mls_credentials {}", @@ -90,6 +91,7 @@ impl Entity for MlsCredential { conn: &mut Self::ConnectionType, id: &StringEntityId, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; let maybe_rowid = transaction @@ -124,7 +126,9 @@ impl Entity for MlsCredential { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row("SELECT COUNT(*) FROM mls_credentials", [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_credentials", [], |r| r.get(0)) + .map_err(Into::into) } } diff --git a/keystore/src/entities/platform/generic/mls/encryption_keypair.rs b/keystore/src/entities/platform/generic/mls/encryption_keypair.rs index c08224d267..468946416c 100644 --- a/keystore/src/entities/platform/generic/mls/encryption_keypair.rs +++ b/keystore/src/entities/platform/generic/mls/encryption_keypair.rs @@ -36,6 +36,7 @@ impl Entity for MlsEncryptionKeyPair { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!("SELECT rowid FROM mls_encryption_keypairs {}", params.to_sql()); @@ -81,6 +82,7 @@ impl Entity for MlsEncryptionKeyPair { conn: &mut Self::ConnectionType, id: &StringEntityId, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; let maybe_rowid = transaction @@ -123,7 +125,9 @@ impl Entity for MlsEncryptionKeyPair { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row("SELECT COUNT(*) FROM mls_encryption_keypairs", [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_encryption_keypairs", [], |r| r.get(0)) + .map_err(Into::into) } } diff --git a/keystore/src/entities/platform/generic/mls/epoch_encryption_keypair.rs b/keystore/src/entities/platform/generic/mls/epoch_encryption_keypair.rs index 31ba878479..9a87836018 100644 --- a/keystore/src/entities/platform/generic/mls/epoch_encryption_keypair.rs +++ b/keystore/src/entities/platform/generic/mls/epoch_encryption_keypair.rs @@ -37,6 +37,7 @@ impl Entity for MlsEpochEncryptionKeyPair { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!( "SELECT rowid, id_hex FROM mls_epoch_encryption_keypairs {}", @@ -79,6 +80,7 @@ impl Entity for MlsEpochEncryptionKeyPair { conn: &mut Self::ConnectionType, id: &StringEntityId, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; let maybe_rowid = transaction @@ -111,7 +113,9 @@ impl Entity for MlsEpochEncryptionKeyPair { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row("SELECT COUNT(*) FROM mls_epoch_encryption_keypairs", [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_epoch_encryption_keypairs", [], |r| r.get(0)) + .map_err(Into::into) } } diff --git a/keystore/src/entities/platform/generic/mls/group.rs b/keystore/src/entities/platform/generic/mls/group.rs index 1300086439..67f945ca00 100644 --- a/keystore/src/entities/platform/generic/mls/group.rs +++ b/keystore/src/entities/platform/generic/mls/group.rs @@ -30,6 +30,7 @@ impl Entity for PersistedMlsGroup { self.id.as_slice() } async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!("SELECT rowid, id_hex FROM mls_groups {}", params.to_sql()); @@ -74,6 +75,7 @@ impl Entity for PersistedMlsGroup { id: &StringEntityId, ) -> crate::CryptoKeystoreResult> { use rusqlite::OptionalExtension as _; + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let mut rowid: Option = transaction .query_row( @@ -119,7 +121,9 @@ impl Entity for PersistedMlsGroup { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row("SELECT COUNT(*) FROM mls_groups", [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_groups", [], |r| r.get(0)) + .map_err(Into::into) } } @@ -200,6 +204,7 @@ impl PersistedMlsGroupExt for PersistedMlsGroup { async fn child_groups(&self, conn: &mut ::ConnectionType) -> CryptoKeystoreResult> { let id = self.id_raw(); + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let mut query = transaction.prepare_cached("SELECT rowid FROM mls_groups WHERE parent_id = ?")?; let mut rows = query.query_map([id], |r| r.get(0))?; diff --git a/keystore/src/entities/platform/generic/mls/hpke_private_key.rs b/keystore/src/entities/platform/generic/mls/hpke_private_key.rs index 390f1669b0..0ecb23e6a4 100644 --- a/keystore/src/entities/platform/generic/mls/hpke_private_key.rs +++ b/keystore/src/entities/platform/generic/mls/hpke_private_key.rs @@ -37,6 +37,7 @@ impl Entity for MlsHpkePrivateKey { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!("SELECT rowid FROM mls_hpke_private_keys {}", params.to_sql()); @@ -72,6 +73,7 @@ impl Entity for MlsHpkePrivateKey { conn: &mut Self::ConnectionType, id: &StringEntityId, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; let maybe_rowid = transaction @@ -104,7 +106,9 @@ impl Entity for MlsHpkePrivateKey { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row("SELECT COUNT(*) FROM mls_hpke_private_keys", [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_hpke_private_keys", [], |r| r.get(0)) + .map_err(Into::into) } } diff --git a/keystore/src/entities/platform/generic/mls/keypackage.rs b/keystore/src/entities/platform/generic/mls/keypackage.rs index 9182830189..b1c3f58809 100644 --- a/keystore/src/entities/platform/generic/mls/keypackage.rs +++ b/keystore/src/entities/platform/generic/mls/keypackage.rs @@ -37,6 +37,7 @@ impl Entity for MlsKeyPackage { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!( "SELECT rowid, keypackage_ref_hex FROM mls_keypackages {}", @@ -81,6 +82,7 @@ impl Entity for MlsKeyPackage { conn: &mut Self::ConnectionType, id: &StringEntityId, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; let mut row_id = transaction @@ -118,8 +120,9 @@ impl Entity for MlsKeyPackage { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - let count: usize = conn.query_row("SELECT COUNT(*) FROM mls_keypackages", [], |r| r.get(0))?; - Ok(count) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_keypackages", [], |r| r.get(0)) + .map_err(Into::into) } } diff --git a/keystore/src/entities/platform/generic/mls/pending_group.rs b/keystore/src/entities/platform/generic/mls/pending_group.rs index 846bec4cb1..d0988111c1 100644 --- a/keystore/src/entities/platform/generic/mls/pending_group.rs +++ b/keystore/src/entities/platform/generic/mls/pending_group.rs @@ -38,6 +38,7 @@ impl Entity for PersistedMlsPendingGroup { use rusqlite::OptionalExtension as _; use std::io::Read as _; + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let rowid: Option = transaction .query_row( @@ -96,6 +97,7 @@ impl Entity for PersistedMlsPendingGroup { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!("SELECT rowid FROM mls_pending_groups {}", params.to_sql()); @@ -154,6 +156,8 @@ impl Entity for PersistedMlsPendingGroup { conn: &mut Self::ConnectionType, _ids: &[StringEntityId], ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; + // Plot twist: we always select ALL the persisted groups. Unsure if we want to make it a real API with selection let mut stmt = conn.prepare_cached("SELECT rowid FROM mls_pending_groups ORDER BY rowid ASC")?; let rowids: Vec = stmt @@ -220,7 +224,9 @@ impl Entity for PersistedMlsPendingGroup { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row("SELECT COUNT(*) FROM mls_pending_groups", [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_pending_groups", [], |r| r.get(0)) + .map_err(Into::into) } } diff --git a/keystore/src/entities/platform/generic/mls/pending_message.rs b/keystore/src/entities/platform/generic/mls/pending_message.rs index b0e4264515..ae69f67a84 100644 --- a/keystore/src/entities/platform/generic/mls/pending_message.rs +++ b/keystore/src/entities/platform/generic/mls/pending_message.rs @@ -39,6 +39,7 @@ impl Entity for MlsPendingMessage { use rusqlite::OptionalExtension as _; use std::io::Read as _; + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let rowid: Option = transaction .query_row( @@ -79,6 +80,7 @@ impl Entity for MlsPendingMessage { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!("SELECT rowid FROM mls_pending_messages {}", params.to_sql()); @@ -123,7 +125,9 @@ impl Entity for MlsPendingMessage { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row("SELECT COUNT(*) FROM mls_pending_messages", [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_pending_messages", [], |r| r.get(0)) + .map_err(Into::into) } } diff --git a/keystore/src/entities/platform/generic/mls/psk_bundle.rs b/keystore/src/entities/platform/generic/mls/psk_bundle.rs index 5b678cdcaa..2aaccbe613 100644 --- a/keystore/src/entities/platform/generic/mls/psk_bundle.rs +++ b/keystore/src/entities/platform/generic/mls/psk_bundle.rs @@ -36,6 +36,7 @@ impl Entity for MlsPskBundle { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!("SELECT rowid FROM mls_psk_bundles {}", params.to_sql()); @@ -71,6 +72,7 @@ impl Entity for MlsPskBundle { conn: &mut Self::ConnectionType, id: &StringEntityId, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; let maybe_rowid = transaction @@ -98,7 +100,9 @@ impl Entity for MlsPskBundle { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row("SELECT COUNT(*) FROM mls_psk_bundles", [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_psk_bundles", [], |r| r.get(0)) + .map_err(Into::into) } } diff --git a/keystore/src/entities/platform/generic/mls/signature_keypair.rs b/keystore/src/entities/platform/generic/mls/signature_keypair.rs index 38e11a17ab..16097903d9 100644 --- a/keystore/src/entities/platform/generic/mls/signature_keypair.rs +++ b/keystore/src/entities/platform/generic/mls/signature_keypair.rs @@ -31,6 +31,7 @@ impl Entity for MlsSignatureKeyPair { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!( "SELECT rowid, signature_scheme FROM mls_signature_keypairs {}", @@ -96,6 +97,7 @@ impl Entity for MlsSignatureKeyPair { conn: &mut Self::ConnectionType, id: &StringEntityId, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; let maybe_rowid = transaction @@ -155,7 +157,9 @@ impl Entity for MlsSignatureKeyPair { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { - Ok(conn.query_row("SELECT COUNT(*) FROM mls_signature_keypairs", [], |r| r.get(0))?) + let conn = conn.conn().await; + conn.query_row("SELECT COUNT(*) FROM mls_signature_keypairs", [], |r| r.get(0)) + .map_err(Into::into) } } diff --git a/keystore/src/entities/platform/generic/proteus/identity.rs b/keystore/src/entities/platform/generic/proteus/identity.rs index 619a0a19f5..8ec400f1e1 100644 --- a/keystore/src/entities/platform/generic/proteus/identity.rs +++ b/keystore/src/entities/platform/generic/proteus/identity.rs @@ -46,6 +46,7 @@ impl Entity for ProteusIdentity { conn: &mut Self::ConnectionType, _id: &StringEntityId, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let mut row_id: Option = transaction @@ -91,6 +92,7 @@ impl Entity for ProteusIdentity { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { + let conn = conn.conn().await; let count = conn.query_row("SELECT COUNT(*) FROM proteus_identities", [], |r| r.get(0))?; // This should always be less or equal 1 debug_assert!(count <= 1); diff --git a/keystore/src/entities/platform/generic/proteus/prekey.rs b/keystore/src/entities/platform/generic/proteus/prekey.rs index 47ef7271fe..8e3d3b6f7f 100644 --- a/keystore/src/entities/platform/generic/proteus/prekey.rs +++ b/keystore/src/entities/platform/generic/proteus/prekey.rs @@ -32,6 +32,7 @@ impl Entity for ProteusPrekey { conn: &mut Self::ConnectionType, params: EntityFindParams, ) -> crate::CryptoKeystoreResult> { + let mut conn = conn.conn().await; let transaction = conn.transaction()?; let query: String = format!("SELECT rowid, id FROM proteus_prekeys {}", params.to_sql()); @@ -61,6 +62,7 @@ impl Entity for ProteusPrekey { ) -> crate::CryptoKeystoreResult> { let id = ProteusPrekey::id_from_slice(id.as_slice()); + let mut conn = conn.conn().await; let transaction = conn.transaction()?; use rusqlite::OptionalExtension as _; @@ -86,6 +88,7 @@ impl Entity for ProteusPrekey { } async fn count(conn: &mut Self::ConnectionType) -> crate::CryptoKeystoreResult { + let conn = conn.conn().await; Ok(conn.query_row("SELECT COUNT(*) FROM proteus_prekeys", [], |r| r.get(0))?) } } diff --git a/keystore/src/transaction/mod.rs b/keystore/src/transaction/mod.rs index b734b37745..3793640e0c 100644 --- a/keystore/src/transaction/mod.rs +++ b/keystore/src/transaction/mod.rs @@ -6,7 +6,7 @@ use crate::entities::proteus::*; use crate::entities::{ConsumerData, EntityBase, EntityFindParams, EntityTransactionExt, UniqueEntity}; use crate::transaction::dynamic_dispatch::EntityId; use crate::{ - connection::{Connection, DatabaseConnection, FetchFromDatabase, KeystoreDatabaseConnection}, + connection::{Connection, FetchFromDatabase, KeystoreDatabaseConnection}, CryptoKeystoreError, CryptoKeystoreResult, }; use async_lock::{RwLock, SemaphoreGuardArc}; @@ -43,11 +43,12 @@ impl KeystoreTransaction { mut entity: E, ) -> CryptoKeystoreResult { entity.pre_save().await?; - let mut conn = self.cache.borrow_conn().await?; + let conn = self.cache.borrow_conn().await?; + let mut conn = conn.conn().await; #[cfg(target_family = "wasm")] let transaction = conn.new_transaction(&[E::COLLECTION_NAME]).await?; #[cfg(not(target_family = "wasm"))] - let transaction = conn.new_transaction().await?; + let transaction = conn.transaction()?.into(); entity.save(&transaction).await?; transaction.commit_tx().await?; Ok(entity) @@ -60,11 +61,12 @@ impl KeystoreTransaction { &self, id: S, ) -> CryptoKeystoreResult<()> { - let mut conn = self.cache.borrow_conn().await?; + let conn = self.cache.borrow_conn().await?; + let mut conn = conn.conn().await; #[cfg(target_family = "wasm")] let transaction = conn.new_transaction(&[E::COLLECTION_NAME]).await?; #[cfg(not(target_family = "wasm"))] - let transaction = conn.new_transaction().await?; + let transaction = conn.transaction()?.into(); E::delete(&transaction, id.as_ref().into()).await?; transaction.commit_tx().await?; let mut deleted_list = self.deleted.write().await; @@ -87,11 +89,12 @@ impl KeystoreTransaction { } pub(crate) async fn cred_delete_by_credential(&self, cred: Vec) -> CryptoKeystoreResult<()> { - let mut conn = self.cache.borrow_conn().await?; + let conn = self.cache.borrow_conn().await?; + let mut conn = conn.conn().await; #[cfg(target_family = "wasm")] let transaction = conn.new_transaction(&[MlsCredential::COLLECTION_NAME]).await?; #[cfg(not(target_family = "wasm"))] - let transaction = conn.new_transaction().await?; + let transaction = conn.transaction()?.into(); MlsCredential::delete_by_credential(&transaction, cred.clone()).await?; transaction.commit_tx().await?; let mut deleted_list = self.deleted_credentials.write().await; @@ -272,7 +275,8 @@ macro_rules! commit_transaction { let ( $( $( $records, )* )* ) = cached_collections; - let mut conn = $db.borrow_conn().await?; + let conn = $db.borrow_conn().await?; + let mut conn = conn.conn().await; let deleted_ids = $keystore_transaction.deleted.read().await; let mut tables = Vec::new(); @@ -294,7 +298,7 @@ macro_rules! commit_transaction { #[cfg(target_family = "wasm")] let tx = conn.new_transaction(&tables).await?; #[cfg(not(target_family = "wasm"))] - let tx = conn.new_transaction().await?; + let tx = conn.transaction()?.into(); $( $( if !$records.is_empty() { diff --git a/mls-provider/Cargo.toml b/mls-provider/Cargo.toml index 8276b239c8..96932432cc 100644 --- a/mls-provider/Cargo.toml +++ b/mls-provider/Cargo.toml @@ -11,6 +11,9 @@ publish = false name = "mls_crypto_provider" crate-type = ["lib", "cdylib"] +[lints] +workspace = true + [features] default = [] raw-rand-access = [] # TESTING ONLY @@ -64,6 +67,3 @@ async-std = { workspace = true, features = ["attributes"] } cfg-if.workspace = true hex-literal = "0.4" mls-crypto-provider = { workspace = true, features = ["raw-rand-access"] } - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(wasm_bindgen_unstable_test_coverage)'] }