diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 054659a12..2036e60c2 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -28,12 +28,16 @@ jobs: - matrix-sdk-base - matrix-sdk-common - matrix-sdk-crypto + - indexeddb-no-crypto + - indexeddb-with-crypto include: - name: matrix-sdk (no-default, wasm-flags) cmd: matrix-sdk-no-default - name: matrix-sdk / indexeddb_stores cmd: matrix-sdk-indexeddb-stores + - name: matrix-sdk / indexeddb_stores / no crypto + cmd: matrix-sdk-indexeddb-stores-no-crypto - name: matrix-sdk / wasm-example cmd: matrix-sdk-command-bot @@ -50,11 +54,22 @@ jobs: profile: minimal override: true + - name: Install WasmPack + uses: jetli/wasm-pack-action@v0.3.0 + with: + version: 'latest' + - name: Load cache uses: Swatinem/rust-cache@v1 - - name: check + - name: Rust Check uses: actions-rs/cargo@v1 with: command: run args: -p xtask -- ci wasm ${{ matrix.cmd || matrix.name }} + + - name: Wasm-Pack test + uses: actions-rs/cargo@v1 + with: + command: run + args: -p xtask -- ci wasm-pack ${{ matrix.cmd || matrix.name }} diff --git a/crates/matrix-sdk-base/Cargo.toml b/crates/matrix-sdk-base/Cargo.toml index 76ea1c261..8244ab496 100644 --- a/crates/matrix-sdk-base/Cargo.toml +++ b/crates/matrix-sdk-base/Cargo.toml @@ -57,3 +57,6 @@ tokio = { version = "1.17.0", default-features = false, features = [ "rt-multi-thread", "macros", ] } + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test = "0.3.30" diff --git a/crates/matrix-sdk-common/src/util.rs b/crates/matrix-sdk-common/src/util.rs index 7670836e6..c9e1dc142 100644 --- a/crates/matrix-sdk-common/src/util.rs +++ b/crates/matrix-sdk-common/src/util.rs @@ -1,4 +1,4 @@ -use instant::SystemTime; +use instant::{Duration, SystemTime}; use ruma::{MilliSecondsSinceUnixEpoch, SecondsSinceUnixEpoch}; /// Platform agnostic helper function to create MilliSecondsSinceUnixEpoch @@ -12,8 +12,17 @@ pub fn milli_seconds_since_unix_epoch() -> MilliSecondsSinceUnixEpoch { /// Platform agnostic helper function to create SecondsSinceUnixEpoch pub fn seconds_since_unix_epoch() -> SecondsSinceUnixEpoch { + modified_seconds_since_unix_epoch(|e| e) +} + +/// Platform agnostic helper function to create SecondsSinceUnixEpoch with +/// modifications +pub fn modified_seconds_since_unix_epoch Duration>( + f: F, +) -> SecondsSinceUnixEpoch { let duration = - SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).expect("now is always higher"); + f(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).expect("now is always higher")); + let millis = duration.as_secs().try_into().expect("can't convert seconds since UNIXEPOCH"); SecondsSinceUnixEpoch(millis) } diff --git a/crates/matrix-sdk-crypto/Cargo.toml b/crates/matrix-sdk-crypto/Cargo.toml index 264c52e96..5bf1062d5 100644 --- a/crates/matrix-sdk-crypto/Cargo.toml +++ b/crates/matrix-sdk-crypto/Cargo.toml @@ -75,6 +75,9 @@ http = "0.2.6" indoc = "1.0.4" matches = "0.1.9" matrix-sdk-test = { version = "0.4.0", path = "../matrix-sdk-test" } -proptest = "1.0.0" +proptest = { version = "1.0.0", default-features = false, features = ["std"] } # required for async_test macro -tokio = { version = "1.17.0", default-features = false, features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.7.0", default-features = false, features = ["macros", "rt-multi-thread"] } + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test = "0.3.24" diff --git a/crates/matrix-sdk-crypto/src/machine.rs b/crates/matrix-sdk-crypto/src/machine.rs index df852ca3d..8ceda3c3e 100644 --- a/crates/matrix-sdk-crypto/src/machine.rs +++ b/crates/matrix-sdk-crypto/src/machine.rs @@ -741,11 +741,7 @@ impl OlmMachine { /// /// # Arguments /// - /// * `sender_key` - The sender (curve25519) key of the event sender. - /// - /// * `signing_key` - The signing (ed25519) key of the event sender. - /// - /// * `event` - The decrypted to-device event. + /// * `decrypted` - The decrypted event and some associated metadata. async fn handle_decrypted_to_device_event( &self, decrypted: &OlmDecryptionInfo, diff --git a/crates/matrix-sdk-crypto/src/olm/account.rs b/crates/matrix-sdk-crypto/src/olm/account.rs index fb9fa5157..dd79d594b 100644 --- a/crates/matrix-sdk-crypto/src/olm/account.rs +++ b/crates/matrix-sdk-crypto/src/olm/account.rs @@ -90,8 +90,13 @@ impl SessionType { } } +/// A struct witnessing a successful decryption of an Olm-encrypted to-device +/// event. +/// +/// Contains the decrypted event plaintext along with some associated metadata, +/// such as the identity (Curve25519) key of the to-device event sender. #[derive(Debug, Clone)] -pub struct OlmDecryptionInfo { +pub(crate) struct OlmDecryptionInfo { pub sender: OwnedUserId, pub session: SessionType, pub message_hash: OlmMessageHash, @@ -213,7 +218,7 @@ impl Account { } } - pub async fn decrypt_to_device_event( + pub(crate) async fn decrypt_to_device_event( &self, event: &ToDeviceRoomEncryptedEvent, ) -> OlmResult { @@ -1005,7 +1010,7 @@ impl ReadOnlyAccount { /// session failed. /// /// # Arguments - /// * `their_identity_key` - The other account's identitiy/curve25519 key. + /// * `their_identity_key` - The other account's identity/curve25519 key. /// /// * `message` - A pre-key Olm message that was sent to us by the other /// account. diff --git a/crates/matrix-sdk-crypto/src/olm/group_sessions/outbound.rs b/crates/matrix-sdk-crypto/src/olm/group_sessions/outbound.rs index d27af2831..a7c36539d 100644 --- a/crates/matrix-sdk-crypto/src/olm/group_sessions/outbound.rs +++ b/crates/matrix-sdk-crypto/src/olm/group_sessions/outbound.rs @@ -608,7 +608,7 @@ mod tests { use std::time::Duration; use atomic::Ordering; - use matrix_sdk_common::instant::SystemTime; + use matrix_sdk_common::util::modified_seconds_since_unix_epoch; use matrix_sdk_test::async_test; use ruma::{ device_id, @@ -616,7 +616,7 @@ mod tests { encryption::RoomEncryptionEventContent, history_visibility::HistoryVisibility, message::RoomMessageEventContent, }, - room_id, uint, user_id, EventEncryptionAlgorithm, SecondsSinceUnixEpoch, + room_id, uint, user_id, EventEncryptionAlgorithm, }; use super::{EncryptionSettings, ROTATION_MESSAGES, ROTATION_PERIOD}; @@ -672,8 +672,8 @@ mod tests { assert!(!session.expired()); // FIXME: this might break on macosx and windows - let time = SystemTime::now() - Duration::from_secs(60 * 60); - session.creation_time = SecondsSinceUnixEpoch::from_system_time(time).unwrap(); + session.creation_time = + modified_seconds_since_unix_epoch(|e| e - Duration::from_secs(60 * 60)); assert!(session.expired()); let settings = EncryptionSettings { rotation_period_msgs: 0, ..Default::default() }; diff --git a/crates/matrix-sdk-indexeddb/Cargo.toml b/crates/matrix-sdk-indexeddb/Cargo.toml index 1251a8f90..e5fb1fced 100644 --- a/crates/matrix-sdk-indexeddb/Cargo.toml +++ b/crates/matrix-sdk-indexeddb/Cargo.toml @@ -37,5 +37,6 @@ matrix-sdk-common = { path = "../matrix-sdk-common" } matrix-sdk-base = { path = "../matrix-sdk-base", features = ["testing"] } matrix-sdk-crypto = { path = "../matrix-sdk-crypto", features = ["testing"] } matrix-sdk-test = { path = "../matrix-sdk-test" } +matrix-sdk-common = { path = "../matrix-sdk-common" } uuid = "1.0.0" wasm-bindgen-test = "0.3.30" diff --git a/crates/matrix-sdk-indexeddb/src/cryptostore.rs b/crates/matrix-sdk-indexeddb/src/cryptostore.rs index b1d9b4979..dc34da5b9 100644 --- a/crates/matrix-sdk-indexeddb/src/cryptostore.rs +++ b/crates/matrix-sdk-indexeddb/src/cryptostore.rs @@ -65,6 +65,11 @@ mod KEYS { pub const STORE_CIPHER: &str = "store_cipher"; pub const ACCOUNT: &str = "account"; pub const PRIVATE_IDENTITY: &str = "private_identity"; + + // BACKUP v1 + pub const BACKUP_KEYS: &str = "backup_keys"; + pub const BACKUP_KEY_V1: &str = "backup_key_v1"; + pub const RECOVERY_KEY_V1: &str = "recovery_key_v1"; } /// An in-memory only store that will forget all the E2EE key once it's dropped. @@ -159,6 +164,8 @@ impl IndexeddbStore { db.create_object_store(KEYS::OUTGOING_SECRET_REQUESTS)?; db.create_object_store(KEYS::UNSENT_SECRET_REQUESTS)?; db.create_object_store(KEYS::SECRET_REQUESTS_BY_INFO)?; + + db.create_object_store(KEYS::BACKUP_KEYS)?; } Ok(()) })); @@ -270,6 +277,7 @@ impl IndexeddbStore { async fn save_changes(&self, changes: Changes) -> Result<()> { let mut stores: Vec<&str> = [ (changes.account.is_some() || changes.private_identity.is_some(), KEYS::CORE), + (changes.recovery_key.is_some() || changes.backup_version.is_some(), KEYS::BACKUP_KEYS), (!changes.sessions.is_empty(), KEYS::SESSION), ( !changes.devices.new.is_empty() @@ -311,6 +319,9 @@ impl IndexeddbStore { let private_identity_pickle = if let Some(i) = changes.private_identity { Some(i.pickle().await?) } else { None }; + let recovery_key_pickle = changes.recovery_key; + let backup_version = changes.backup_version; + if let Some(a) = &account_pickle { tx.object_store(KEYS::CORE)? .put_key_val(&JsValue::from_str(KEYS::ACCOUNT), &self.serialize_value(&a)?)?; @@ -323,6 +334,18 @@ impl IndexeddbStore { )?; } + if let Some(a) = &recovery_key_pickle { + tx.object_store(KEYS::BACKUP_KEYS)?.put_key_val( + &JsValue::from_str(KEYS::RECOVERY_KEY_V1), + &self.serialize_value(&a)?, + )?; + } + + if let Some(a) = &backup_version { + tx.object_store(KEYS::BACKUP_KEYS)? + .put_key_val(&JsValue::from_str(KEYS::BACKUP_KEY_V1), &self.serialize_value(&a)?)?; + } + if !changes.sessions.is_empty() { let sessions = tx.object_store(KEYS::SESSION)?; @@ -834,6 +857,31 @@ impl IndexeddbStore { tx.await.into_result().map_err(|e| e.into()) } + + async fn load_backup_keys(&self) -> Result { + let key = { + let tx = self + .inner + .transaction_on_one_with_mode(KEYS::BACKUP_KEYS, IdbTransactionMode::Readonly)?; + let store = tx.object_store(KEYS::BACKUP_KEYS)?; + + let backup_version = store + .get(&JsValue::from_str(KEYS::BACKUP_KEY_V1))? + .await? + .map(|i| self.deserialize_value(i)) + .transpose()?; + + let recovery_key = store + .get(&JsValue::from_str(KEYS::RECOVERY_KEY_V1))? + .await? + .map(|i| self.deserialize_value(i)) + .transpose()?; + + BackupKeys { backup_version, recovery_key } + }; + + Ok(key) + } } #[async_trait(?Send)] @@ -924,9 +972,8 @@ impl CryptoStore for IndexeddbStore { self.users_for_key_query() } - #[allow(clippy::todo)] async fn load_backup_keys(&self) -> Result { - todo!() + self.load_backup_keys().await.map_err(|e| e.into()) } async fn update_tracked_user( diff --git a/crates/matrix-sdk-indexeddb/src/state_store.rs b/crates/matrix-sdk-indexeddb/src/state_store.rs index c1f85c952..744cb39c1 100644 --- a/crates/matrix-sdk-indexeddb/src/state_store.rs +++ b/crates/matrix-sdk-indexeddb/src/state_store.rs @@ -1394,6 +1394,8 @@ mod encrypted_tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + use std::sync::Arc; + use matrix_sdk_base::statestore_integration_tests; use uuid::Uuid; @@ -1401,9 +1403,9 @@ mod encrypted_tests { async fn get_store() -> Result { let db_name = - format!("test-state-encrypted-{}", Uuid::new_v4().to_hyphenated().to_string()); + format!("test-state-encrypted-{}", Uuid::new_v4().as_hyphenated().to_string()); let key = StoreCipher::new()?; - Ok(IndexeddbStore::open_helper(db_name, Some(key)).await?) + Ok(IndexeddbStore::open_helper(db_name, Some(Arc::new(key))).await?) } statestore_integration_tests! { integration } diff --git a/crates/matrix-sdk-sled/Cargo.toml b/crates/matrix-sdk-sled/Cargo.toml index d71bc0db1..bdbe9539d 100644 --- a/crates/matrix-sdk-sled/Cargo.toml +++ b/crates/matrix-sdk-sled/Cargo.toml @@ -27,7 +27,7 @@ anyhow = "1.0.57" dashmap = "5.2.0" [dev-dependencies] -lazy_static = "1.4.0" +once_cell = "1.10.0" tempfile = "3.3.0" matrix-sdk-test = { version = "0.4.0", path = "../matrix-sdk-test" } matrix-sdk-crypto = { path = "../matrix-sdk-crypto", features = ["testing"] } diff --git a/crates/matrix-sdk-sled/src/cryptostore.rs b/crates/matrix-sdk-sled/src/cryptostore.rs index 2232ef972..0372fb91b 100644 --- a/crates/matrix-sdk-sled/src/cryptostore.rs +++ b/crates/matrix-sdk-sled/src/cryptostore.rs @@ -1040,15 +1040,13 @@ impl CryptoStore for SledStore { #[cfg(test)] mod tests { - use lazy_static::lazy_static; use matrix_sdk_crypto::cryptostore_integration_tests; + use once_cell::sync::Lazy; use tempfile::{tempdir, TempDir}; use super::SledStore; - lazy_static! { - /// This is an example for using doc comment attributes - static ref TMP_DIR: TempDir = tempdir().unwrap(); - } + + static TMP_DIR: Lazy = Lazy::new(|| tempdir().unwrap()); async fn get_store(name: String, passphrase: Option<&str>) -> SledStore { let tmpdir_path = TMP_DIR.path().join(name); diff --git a/crates/matrix-sdk-test/Cargo.toml b/crates/matrix-sdk-test/Cargo.toml index ce64fda48..c5bba1d1e 100644 --- a/crates/matrix-sdk-test/Cargo.toml +++ b/crates/matrix-sdk-test/Cargo.toml @@ -16,8 +16,8 @@ appservice = [] [dependencies] http = "0.2.6" -lazy_static = "1.4.0" matrix-sdk-test-macros = { version = "0.1.0", path = "../matrix-sdk-test-macros" } +once_cell = "1.10.0" ruma = { git = "https://github.com/ruma/ruma", rev = "4014e6959", features = ["client-api-c"] } serde = "1.0.136" serde_json = "1.0.79" diff --git a/crates/matrix-sdk-test/src/test_json/events.rs b/crates/matrix-sdk-test/src/test_json/events.rs index 2e3ec4e50..ae5e36d68 100644 --- a/crates/matrix-sdk-test/src/test_json/events.rs +++ b/crates/matrix-sdk-test/src/test_json/events.rs @@ -1,8 +1,8 @@ -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use serde_json::{json, Value as JsonValue}; -lazy_static! { - pub static ref ALIAS: JsonValue = json!({ +pub static ALIAS: Lazy = Lazy::new(|| { + json!({ "content": { "alias": "#tutorial:localhost" }, @@ -14,11 +14,11 @@ lazy_static! { "unsigned": { "age": 703422 } - }); -} + }) +}); -lazy_static! { - pub static ref ALIASES: JsonValue = json!({ +pub static ALIASES: Lazy = Lazy::new(|| { + json!({ "content": { "aliases": [ "#tutorial:localhost" @@ -32,11 +32,11 @@ lazy_static! { "unsigned": { "age": 703422 } - }); -} + }) +}); -lazy_static! { - pub static ref CREATE: JsonValue = json!({ +pub static CREATE: Lazy = Lazy::new(|| { + json!({ "content": { "creator": "@example:localhost", "m.federate": true, @@ -50,21 +50,21 @@ lazy_static! { "unsigned": { "age": 139298 } - }); -} + }) +}); -lazy_static! { - pub static ref FULLY_READ: JsonValue = json!({ +pub static FULLY_READ: Lazy = Lazy::new(|| { + json!({ "content": { "event_id": "$someplace:example.org" }, "room_id": "!somewhere:example.org", "type": "m.fully_read" - }); -} + }) +}); -lazy_static! { - pub static ref HISTORY_VISIBILITY: JsonValue = json!({ +pub static HISTORY_VISIBILITY: Lazy = Lazy::new(|| { + json!({ "content": { "history_visibility": "world_readable" }, @@ -76,11 +76,11 @@ lazy_static! { "unsigned": { "age": 1392989 } - }); -} + }) +}); -lazy_static! { - pub static ref JOIN_RULES: JsonValue = json!({ +pub static JOIN_RULES: Lazy = Lazy::new(|| { + json!({ "content": { "join_rule": "public" }, @@ -92,11 +92,11 @@ lazy_static! { "unsigned": { "age": 1392989 } - }); -} + }) +}); -lazy_static! { - pub static ref ROOM_MESSAGES: JsonValue = json!({ +pub static ROOM_MESSAGES: Lazy = Lazy::new(|| { + json!({ "chunk": [ { "age": 1042, @@ -140,11 +140,11 @@ lazy_static! { ], "end": "t47409-4357353_219380_26003_2265", "start": "t47429-4392820_219380_26003_2265" - }); -} + }) +}); -lazy_static! { - pub static ref SYNC_ROOM_MESSAGES_BATCH_1: JsonValue = json!({ +pub static SYNC_ROOM_MESSAGES_BATCH_1: Lazy = Lazy::new(|| { + json!({ "chunk": [ { "age": 1042, @@ -188,11 +188,11 @@ lazy_static! { ], "end": "t47409-4357353_219380_26003_2269", "start": "t392-516_47314_0_7_1_1_1_11444_1" - }); -} + }) +}); -lazy_static! { - pub static ref SYNC_ROOM_MESSAGES_BATCH_2: JsonValue = json!({ +pub static SYNC_ROOM_MESSAGES_BATCH_2: Lazy = Lazy::new(|| { + json!({ "chunk": [ { "age": 1042, @@ -236,11 +236,11 @@ lazy_static! { ], "end": "t47409-4357353_219380_26003_2270", "start": "t47409-4357353_219380_26003_2269" - }); -} + }) +}); -lazy_static! { - pub static ref KEYS_QUERY: JsonValue = json!({ +pub static KEYS_QUERY: Lazy = Lazy::new(|| { + json!({ "device_keys": { "@alice:example.org": { "JLAFKJWSCS": { @@ -266,29 +266,29 @@ lazy_static! { } }, "failures": {} - }); -} + }) +}); -lazy_static! { - pub static ref KEYS_UPLOAD: JsonValue = json!({ +pub static KEYS_UPLOAD: Lazy = Lazy::new(|| { + json!({ "one_time_key_counts": { "curve25519": 10, "signed_curve25519": 20 } - }); -} + }) +}); -lazy_static! { - pub static ref LOGIN: JsonValue = json!({ +pub static LOGIN: Lazy = Lazy::new(|| { + json!({ "access_token": "abc123", "device_id": "GHTYAJCE", "home_server": "matrix.org", "user_id": "@cheeky_monkey:matrix.org" - }); -} + }) +}); -lazy_static! { - pub static ref LOGIN_WITH_DISCOVERY: JsonValue = json!({ +pub static LOGIN_WITH_DISCOVERY: Lazy = Lazy::new(|| { + json!({ "access_token": "abc123", "device_id": "GHTYAJCE", "home_server": "matrix.org", @@ -301,18 +301,18 @@ lazy_static! { "base_url": "https://id.example.org" } } - }); -} + }) +}); -lazy_static! { - pub static ref LOGIN_RESPONSE_ERR: JsonValue = json!({ +pub static LOGIN_RESPONSE_ERR: Lazy = Lazy::new(|| { + json!({ "errcode": "M_FORBIDDEN", "error": "Invalid password" - }); -} + }) +}); -lazy_static! { - pub static ref LOGIN_TYPES: JsonValue = json!({ +pub static LOGIN_TYPES: Lazy = Lazy::new(|| { + json!({ "flows": [ { "type": "m.login.password" @@ -324,21 +324,19 @@ lazy_static! { "type": "m.login.token" } ] - }); -} + }) +}); -lazy_static! { - pub static ref LOGOUT: JsonValue = json!({}); -} +pub static LOGOUT: Lazy = Lazy::new(|| json!({})); -lazy_static! { - pub static ref EVENT_ID: JsonValue = json!({ +pub static EVENT_ID: Lazy = Lazy::new(|| { + json!({ "event_id": "$h29iv0s8:example.com" - }); -} + }) +}); -lazy_static! { - pub static ref ENCRYPTION: JsonValue = json!({ +pub static ENCRYPTION: Lazy = Lazy::new(|| { + json!({ "content": { "algorithm": "m.megolm.v1.aes-sha2", "rotation_period_ms": 604800000, @@ -353,12 +351,12 @@ lazy_static! { "unsigned": { "age": 1234 } - }); -} + }) +}); // TODO: Move `prev_content` into `unsigned` once ruma supports it -lazy_static! { - pub static ref MEMBER: JsonValue = json!({ +pub static MEMBER: Lazy = Lazy::new(|| { + json!({ "content": { "avatar_url": null, "displayname": "example", @@ -379,11 +377,11 @@ lazy_static! { "age": 297036, "replaces_state": "$151800111315tsynI:localhost" } - }); -} + }) +}); -lazy_static! { - pub static ref MEMBER_INVITE: JsonValue = json!({ +pub static MEMBER_INVITE: Lazy = Lazy::new(|| { + json!({ "content": { "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF", "displayname": "example", @@ -417,12 +415,12 @@ lazy_static! { } ] } - }); -} + }) +}); // TODO: Move `prev_content` into `unsigned` once ruma supports it -lazy_static! { - pub static ref MEMBER_NAME_CHANGE: JsonValue = json!({ +pub static MEMBER_NAME_CHANGE: Lazy = Lazy::new(|| { + json!({ "content": { "avatar_url": null, "displayname": "changed", @@ -443,11 +441,11 @@ lazy_static! { "age": 297032, "replaces_state": "$151800140517rfvjc:localhost" } - }); -} + }) +}); -lazy_static! { - pub static ref MEMBER_STRIPPED: JsonValue = json!({ +pub static MEMBER_STRIPPED: Lazy = Lazy::new(|| { + json!({ "content": { "avatar_url": null, "displayname": "example", @@ -456,11 +454,11 @@ lazy_static! { "sender": "@example:localhost", "state_key": "@example:localhost", "type": "m.room.member", - }); -} + }) +}); -lazy_static! { - pub static ref MESSAGE_EDIT: JsonValue = json!({ +pub static MESSAGE_EDIT: Lazy = Lazy::new(|| { + json!({ "content": { "body": " * edited message", "m.new_content": { @@ -480,11 +478,11 @@ lazy_static! { "unsigned": { "age": 85 } - }); -} + }) +}); -lazy_static! { - pub static ref MESSAGE_EMOTE: JsonValue = json!({ +pub static MESSAGE_EMOTE: Lazy = Lazy::new(|| { + json!({ "content": { "body": "is dancing", "format": "org.matrix.custom.html", "formatted_body": "is dancing", @@ -497,11 +495,11 @@ lazy_static! { "unsigned": { "age": 598971 } - }); -} + }) +}); -lazy_static! { - pub static ref MESSAGE_NOTICE: JsonValue = json!({ +pub static MESSAGE_NOTICE: Lazy = Lazy::new(|| { + json!({ "origin_server_ts": 153356516, "sender": "@_neb_github:matrix.org", "event_id": "$153356516319138IHRIC:matrix.org", @@ -516,11 +514,11 @@ lazy_static! { }, "type": "m.room.message", "room_id": "!YHhmBTmGBHGQOlGpaZ:matrix.org" - }); -} + }) +}); -lazy_static! { - pub static ref MESSAGE_TEXT: JsonValue = json!({ +pub static MESSAGE_TEXT: Lazy = Lazy::new(|| { + json!({ "content": { "body": "is dancing", "format": "org.matrix.custom.html", "formatted_body": "is dancing", @@ -533,11 +531,11 @@ lazy_static! { "unsigned": { "age": 598971 } - }); -} + }) +}); -lazy_static! { - pub static ref NAME: JsonValue = json!({ +pub static NAME: Lazy = Lazy::new(|| { + json!({ "content": { "name": "room name" }, @@ -549,22 +547,22 @@ lazy_static! { "unsigned": { "age": 703422 } - }); -} + }) +}); -lazy_static! { - pub static ref NAME_STRIPPED: JsonValue = json!({ +pub static NAME_STRIPPED: Lazy = Lazy::new(|| { + json!({ "content": { "name": "room name" }, "sender": "@example:localhost", "state_key": "", "type": "m.room.name", - }); -} + }) +}); -lazy_static! { - pub static ref POWER_LEVELS: JsonValue = json!({ +pub static POWER_LEVELS: Lazy = Lazy::new(|| { + json!({ "content": { "ban": 50, "events": { @@ -594,12 +592,11 @@ lazy_static! { "unsigned": { "age": 703422 } - } - ); -} + }) +}); -lazy_static! { - pub static ref PRESENCE: JsonValue = json!({ +pub static PRESENCE: Lazy = Lazy::new(|| { + json!({ "content": { "avatar_url": "mxc://localhost/wefuiwegh8742w", "currently_active": false, @@ -609,11 +606,11 @@ lazy_static! { }, "sender": "@example:localhost", "type": "m.presence" - }); -} + }) +}); -lazy_static! { - pub static ref PUBLIC_ROOMS: JsonValue = json!({ +pub static PUBLIC_ROOMS: Lazy = Lazy::new(|| { + json!({ "chunk": [ { "aliases": [ @@ -631,11 +628,11 @@ lazy_static! { "next_batch": "p190q", "prev_batch": "p1902", "total_room_count_estimate": 115 - }); -} + }) +}); -lazy_static! { - pub static ref PUSH_RULES: JsonValue = json!({ +pub static PUSH_RULES: Lazy = Lazy::new(|| { + json!({ "content": { "global": { "content": [ @@ -830,11 +827,11 @@ lazy_static! { } }, "type": "m.push_rules" - }); -} + }) +}); -lazy_static! { - pub static ref REGISTRATION_RESPONSE_ERR: JsonValue = json!({ +pub static REGISTRATION_RESPONSE_ERR: Lazy = Lazy::new(|| { + json!({ "errcode": "M_FORBIDDEN", "error": "Invalid password", "completed": ["example.type.foo"], @@ -852,11 +849,11 @@ lazy_static! { } }, "session": "xxxxxx" - }); -} + }) +}); -lazy_static! { - pub static ref REACTION: JsonValue = json!({ +pub static REACTION: Lazy = Lazy::new(|| { + json!({ "content": { "m.relates_to": { "event_id": "$MDitXXXXXXuBlpP7S6c6XXXXXXXC2HqZ3peV1NrV4PKA", @@ -871,11 +868,11 @@ lazy_static! { "unsigned": { "age": 85 } - }); -} + }) +}); -lazy_static! { - pub static ref READ_RECEIPT: JsonValue = json!({ +pub static READ_RECEIPT: Lazy = Lazy::new(|| { + json!({ "content": { "$example": { "m.read": { @@ -887,11 +884,11 @@ lazy_static! { }, "room_id": "!test:localhost", "type": "m.receipt" - }); -} + }) +}); -lazy_static! { - pub static ref READ_RECEIPT_OTHER: JsonValue = json!({ +pub static READ_RECEIPT_OTHER: Lazy = Lazy::new(|| { + json!({ "content": { "$other": { "m.read": { @@ -903,21 +900,21 @@ lazy_static! { }, "room_id": "!test:localhost", "type": "m.receipt" - }); -} + }) +}); -lazy_static! { - pub static ref REDACTED_INVALID: JsonValue = json!({ +pub static REDACTED_INVALID: Lazy = Lazy::new(|| { + json!({ "content": {}, "event_id": "$15275046980maRLj:localhost", "origin_server_ts": 1527504698, "sender": "@example:localhost", "type": "m.room.message" - }); -} + }) +}); -lazy_static! { - pub static ref REDACTED_STATE: JsonValue = json!({ +pub static REDACTED_STATE: Lazy = Lazy::new(|| { + json!({ "content": {}, "event_id": "$example_id:example.org", "origin_server_ts": 153232493, @@ -937,11 +934,11 @@ lazy_static! { }, "redacted_by": "$redaction_example_id:example.org" } - }); -} + }) +}); -lazy_static! { - pub static ref REDACTED: JsonValue = json!({ +pub static REDACTED: Lazy = Lazy::new(|| { + json!({ "content": {}, "event_id": "$15275046980maRLj:localhost", "origin_server_ts": 1527504698, @@ -962,11 +959,11 @@ lazy_static! { }, "redacted_by": "$15275047031IXQRi:localhost" } - }); -} + }) +}); -lazy_static! { - pub static ref REDACTION: JsonValue = json!({ +pub static REDACTION: Lazy = Lazy::new(|| { + json!({ "content": { "reason": "😀" }, @@ -975,11 +972,11 @@ lazy_static! { "sender": "@example:localhost", "type": "m.room.redaction", "redacts": "$151957878228ssqrj:localhost" - }); -} + }) +}); -lazy_static! { - pub static ref ROOM_AVATAR: JsonValue = json!({ +pub static ROOM_AVATAR: Lazy = Lazy::new(|| { + json!({ "content": { "info": { "h": 398, @@ -998,17 +995,17 @@ lazy_static! { "unsigned": { "age": 1234 } - }); -} + }) +}); -lazy_static! { - pub static ref ROOM_ID: JsonValue = json!({ +pub static ROOM_ID: Lazy = Lazy::new(|| { + json!({ "room_id": "!testroom:example.org" - }); -} + }) +}); -lazy_static! { - pub static ref TAG: JsonValue = json!({ +pub static TAG: Lazy = Lazy::new(|| { + json!({ "content": { "tags": { "u.work": { @@ -1017,12 +1014,12 @@ lazy_static! { } }, "type": "m.tag" - }); -} + }) +}); // TODO: Move `prev_content` into `unsigned` once ruma supports it -lazy_static! { - pub static ref TOPIC: JsonValue = json!({ +pub static TOPIC: Lazy = Lazy::new(|| { + json!({ "content": { "topic": "😀" }, @@ -1039,11 +1036,11 @@ lazy_static! { "prev_sender": "@example:localhost", "replaces_state": "$151957069225EVYKm:localhost" } - }); -} + }) +}); -lazy_static! { - pub static ref TYPING: JsonValue = json!({ +pub static TYPING: Lazy = Lazy::new(|| { + json!({ "content": { "user_ids": [ "@alice:matrix.org", @@ -1052,5 +1049,5 @@ lazy_static! { }, "room_id": "!jEsUZKDJdhlrceRyVU:example.org", "type": "m.typing" - }); -} + }) +}); diff --git a/crates/matrix-sdk-test/src/test_json/members.rs b/crates/matrix-sdk-test/src/test_json/members.rs index 401ec034f..94bc7df7e 100644 --- a/crates/matrix-sdk-test/src/test_json/members.rs +++ b/crates/matrix-sdk-test/src/test_json/members.rs @@ -1,8 +1,8 @@ -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use serde_json::{json, Value as JsonValue}; -lazy_static! { - pub static ref MEMBERS: JsonValue = json!({ +pub static MEMBERS: Lazy = Lazy::new(|| { + json!({ "chunk": [ { "content": { @@ -21,5 +21,5 @@ lazy_static! { } } ] - }); -} + }) +}); diff --git a/crates/matrix-sdk-test/src/test_json/mod.rs b/crates/matrix-sdk-test/src/test_json/mod.rs index d41ca88d0..78f440b2e 100644 --- a/crates/matrix-sdk-test/src/test_json/mod.rs +++ b/crates/matrix-sdk-test/src/test_json/mod.rs @@ -4,7 +4,7 @@ //! truth. When running `cargo publish` no external folders are allowed so all //! the test data needs to be contained within this crate. -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use serde_json::{json, Value as JsonValue}; pub mod events; @@ -25,8 +25,8 @@ pub use sync::{ VOIP_SYNC, }; -lazy_static! { - pub static ref DEVICES: JsonValue = json!({ +pub static DEVICES: Lazy = Lazy::new(|| { + json!({ "devices": [ { "device_id": "BNYQQWUMXO", @@ -43,19 +43,19 @@ lazy_static! { "user_id": "@example:localhost" } ] - }); -} + }) +}); -lazy_static! { - pub static ref WELL_KNOWN: JsonValue = json!({ +pub static WELL_KNOWN: Lazy = Lazy::new(|| { + json!({ "m.homeserver": { "base_url": "HOMESERVER_URL" } - }); -} + }) +}); -lazy_static! { - pub static ref VERSIONS: JsonValue = json!({ +pub static VERSIONS: Lazy = Lazy::new(|| { + json!({ "versions": [ "r0.0.1", "r0.1.0", @@ -69,11 +69,11 @@ lazy_static! { "org.matrix.label_based_filtering":true, "org.matrix.e2e_cross_signing":true } - }); -} + }) +}); -lazy_static! { - pub static ref WHOAMI: JsonValue = json!({ +pub static WHOAMI: Lazy = Lazy::new(|| { + json!({ "user_id": "@joe:example.org" - }); -} + }) +}); diff --git a/crates/matrix-sdk-test/src/test_json/sync.rs b/crates/matrix-sdk-test/src/test_json/sync.rs index 6434da623..842f6ac01 100644 --- a/crates/matrix-sdk-test/src/test_json/sync.rs +++ b/crates/matrix-sdk-test/src/test_json/sync.rs @@ -1,8 +1,8 @@ -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use serde_json::{json, Value as JsonValue}; -lazy_static! { - pub static ref SYNC: JsonValue = json!({ +pub static SYNC: Lazy = Lazy::new(|| { + json!({ "device_one_time_keys_count": {}, "next_batch": "s526_47314_0_7_1_1_1_11444_1", "device_lists": { @@ -283,11 +283,11 @@ lazy_static! { } ] } - }); -} + }) +}); -lazy_static! { - pub static ref DEFAULT_SYNC_SUMMARY: JsonValue = json!({ +pub static DEFAULT_SYNC_SUMMARY: Lazy = Lazy::new(|| { + json!({ "device_one_time_keys_count": {}, "next_batch": "s526_47314_0_7_1_1_1_11444_1", "device_lists": { @@ -541,11 +541,11 @@ lazy_static! { } ] } - }); -} + }) +}); -lazy_static! { - pub static ref MORE_SYNC: JsonValue = json!({ +pub static MORE_SYNC: Lazy = Lazy::new(|| { + json!({ "device_one_time_keys_count": {}, "next_batch": "s526_47314_0_7_1_1_1_11444_2", "device_lists": { @@ -714,11 +714,11 @@ lazy_static! { "presence": { "events": [] } - }); -} + }) +}); -lazy_static! { - pub static ref MORE_SYNC_2: JsonValue = json!({ +pub static MORE_SYNC_2: Lazy = Lazy::new(|| { + json!({ "next_batch": "s526_47314_0_7_1_1_1_11444_3", "rooms": { "join": { @@ -838,11 +838,11 @@ lazy_static! { } }, }, - }); -} + }) +}); -lazy_static! { - pub static ref INVITE_SYNC: JsonValue = json!({ +pub static INVITE_SYNC: Lazy = Lazy::new(|| { + json!({ "device_one_time_keys_count": {}, "next_batch": "s526_47314_0_7_1_1_1_11444_2", "device_lists": { @@ -897,11 +897,11 @@ lazy_static! { } ] } - }); -} + }) +}); -lazy_static! { - pub static ref LEAVE_SYNC: JsonValue = json!({ +pub static LEAVE_SYNC: Lazy = Lazy::new(|| { + json!({ "device_one_time_keys_count": {}, "next_batch": "s526_47314_0_7_1_1_1_11444_1", "device_lists": { @@ -1180,11 +1180,11 @@ lazy_static! { } ] } - }); -} + }) +}); -lazy_static! { - pub static ref LEAVE_SYNC_EVENT: JsonValue = json!({ +pub static LEAVE_SYNC_EVENT: Lazy = Lazy::new(|| { + json!({ "account_data": { "events": [] }, @@ -1247,11 +1247,11 @@ lazy_static! { "signed_curve25519": 50 }, "next_batch": "s1380317562_757269739_1655566_503953763_334052043_1209862_55290918_65705002_101146" - }); -} + }) +}); -lazy_static! { - pub static ref VOIP_SYNC: JsonValue = json!({ +pub static VOIP_SYNC: Lazy = Lazy::new(|| { + json!({ "device_one_time_keys_count": {}, "next_batch": "s526_47314_0_7_1_1_1_11444_1", "device_lists": { @@ -1367,5 +1367,5 @@ lazy_static! { "presence": { "events": [] } - }); -} + }) +}); diff --git a/crates/matrix-sdk/Cargo.toml b/crates/matrix-sdk/Cargo.toml index 2b861c7eb..6209da4b6 100644 --- a/crates/matrix-sdk/Cargo.toml +++ b/crates/matrix-sdk/Cargo.toml @@ -132,10 +132,10 @@ features = ["fs", "rt"] anyhow = "1.0.57" dirs = "4.0.0" futures = { version = "0.3.21", default-features = false, features = ["executor"] } -lazy_static = "1.4.0" matches = "0.1.9" matrix-sdk-test = { version = "0.4.0", path = "../matrix-sdk-test" } mockito = "0.31.0" +once_cell = "1.10.0" serde_json = "1.0.79" tempfile = "3.3.0" tracing-subscriber = { version = "0.3.11", features = ["env-filter"] } @@ -147,6 +147,7 @@ default-features = false features = ["rt-multi-thread", "macros"] [target.'cfg(target_arch = "wasm32")'.dev-dependencies] +getrandom = { version = "0.2.6", default-features = false, features = ["js"] } wasm-bindgen-test = "0.3.30" [[example]] diff --git a/xtask/src/ci.rs b/xtask/src/ci.rs index 82a188746..6d7a93d06 100644 --- a/xtask/src/ci.rs +++ b/xtask/src/ci.rs @@ -36,6 +36,11 @@ enum CiCommand { #[clap(subcommand)] cmd: Option, }, + /// Run wasm-pack tests + WasmPack { + #[clap(subcommand)] + cmd: Option, + }, /// Run tests for the different crypto crate features TestCrypto, } @@ -61,7 +66,10 @@ enum WasmFeatureSet { MatrixSdkBase, MatrixSdkCommon, MatrixSdkCrypto, + MatrixSdkIndexeddbStoresNoCrypto, MatrixSdkIndexeddbStores, + IndexeddbNoCrypto, + IndexeddbWithCrypto, MatrixSdkCommandBot, } @@ -79,6 +87,7 @@ impl CiArgs { CiCommand::TestFeatures { cmd } => run_feature_tests(cmd), CiCommand::TestAppservice => run_appservice_tests(), CiCommand::Wasm { cmd } => run_wasm_checks(cmd), + CiCommand::WasmPack { cmd } => run_wasm_pack_tests(cmd), CiCommand::TestCrypto => run_crypto_tests(), }, None => { @@ -192,17 +201,27 @@ fn run_wasm_checks(cmd: Option) -> Result<()> { (WasmFeatureSet::MatrixQrcode, "-p matrix-qrcode"), ( WasmFeatureSet::MatrixSdkNoDefault, - "-p matrix-sdk \ - --no-default-features \ - --features qrcode,encryption,indexeddb-state-store,indexeddb-crypto-store,rustls-tls", + "-p matrix-sdk --no-default-features --features rustls-tls", ), (WasmFeatureSet::MatrixSdkBase, "-p matrix-sdk-base"), (WasmFeatureSet::MatrixSdkCommon, "-p matrix-sdk-common"), (WasmFeatureSet::MatrixSdkCrypto, "-p matrix-sdk-crypto"), + ( + WasmFeatureSet::MatrixSdkIndexeddbStoresNoCrypto, + "-p matrix-sdk --no-default-features --features indexeddb-state-store,rustls-tls", + ), ( WasmFeatureSet::MatrixSdkIndexeddbStores, "-p matrix-sdk --no-default-features --features indexeddb-state-store,indexeddb-crypto-store,encryption,rustls-tls", ), + ( + WasmFeatureSet::IndexeddbNoCrypto, + "-p matrix-sdk-indexeddb --no-default-features ", + ), + ( + WasmFeatureSet::IndexeddbWithCrypto, + "-p matrix-sdk-indexeddb --no-default-features --features encryption", + ), ]); let run = |arg_set: &str| { @@ -241,6 +260,71 @@ fn run_wasm_checks(cmd: Option) -> Result<()> { Ok(()) } +fn run_wasm_pack_tests(cmd: Option) -> Result<()> { + let args = BTreeMap::from([ + (WasmFeatureSet::MatrixQrcode, ("matrix-qrcode", "")), + ( + WasmFeatureSet::MatrixSdkNoDefault, ("matrix-sdk", "--no-default-features --features rustls-tls --lib") + ), + (WasmFeatureSet::MatrixSdkBase, ("matrix-sdk-base", "")), + (WasmFeatureSet::MatrixSdkCommon, ("matrix-sdk-common", "")), + (WasmFeatureSet::MatrixSdkCrypto, ("matrix-sdk-crypto", "")), + ( + WasmFeatureSet::MatrixSdkIndexeddbStoresNoCrypto, ( + "matrix-sdk", "--no-default-features --features indexeddb-state-store,rustls-tls --lib", + ) + ), + ( + WasmFeatureSet::MatrixSdkIndexeddbStores, ( + "matrix-sdk", "--no-default-features --features indexeddb-state-store,indexeddb-crypto-store,encryption,rustls-tls --lib", + ) + ), + ( + WasmFeatureSet::IndexeddbNoCrypto, ( + "matrix-sdk-indexeddb", "--no-default-features", + ) + ), + ( + WasmFeatureSet::IndexeddbWithCrypto, ( + "matrix-sdk-indexeddb", "--no-default-features --features encryption", + ) + ), + ]); + + let run = |(folder, arg_set): (&str, &str)| { + let _p = pushd(format!("crates/{}", folder)); + cmd!("pwd").run()?; // print dir so we know what might have failed + cmd!("wasm-pack test --node -- ").args(arg_set.split_whitespace()).run()?; + cmd!("wasm-pack test --firefox --headless --").args(arg_set.split_whitespace()).run() + }; + + let test_command_bot = || { + let _p = pushd("crates/matrix-sdk/examples/wasm_command_bot"); + cmd!("wasm-pack test --node").run()?; + cmd!("wasm-pack test --firefox --headless").run() + }; + + match cmd { + Some(cmd) => match cmd { + WasmFeatureSet::MatrixSdkCommandBot => { + test_command_bot()?; + } + _ => { + run(args[&cmd])?; + } + }, + None => { + for &arg_set in args.values() { + run(arg_set)?; + } + + test_command_bot()?; + } + } + + Ok(()) +} + fn workspace_root() -> Result { #[derive(Deserialize)] struct Metadata {