From 1ecf90bb425fd36cf3385940e1c98cad762afeb9 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 30 May 2022 17:46:00 +0200 Subject: [PATCH] feat(crypto-nodejs): Implement `OlmMachine.receive_sync_changes`. --- crates/matrix-sdk-crypto-nodejs/Cargo.toml | 1 + crates/matrix-sdk-crypto-nodejs/src/errors.rs | 7 +++ .../src/identifiers.rs | 18 ++------ crates/matrix-sdk-crypto-nodejs/src/lib.rs | 3 +- .../matrix-sdk-crypto-nodejs/src/machine.rs | 45 ++++++++++++++++++- .../src/sync_events.rs | 41 +++++++++++++++++ 6 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 crates/matrix-sdk-crypto-nodejs/src/sync_events.rs diff --git a/crates/matrix-sdk-crypto-nodejs/Cargo.toml b/crates/matrix-sdk-crypto-nodejs/Cargo.toml index b8b6a94ce..b5c0525c0 100644 --- a/crates/matrix-sdk-crypto-nodejs/Cargo.toml +++ b/crates/matrix-sdk-crypto-nodejs/Cargo.toml @@ -29,6 +29,7 @@ ruma = { version = "0.6.2", features = ["client-api-c", "rand", "unstable-msc267 vodozemac = { git = "https://github.com/matrix-org/vodozemac/", rev = "d0e744287a14319c2a9148fef3747548c740fc36" } napi = { git = "https://github.com/Hywan/napi-rs", branch = "feat-tonapivalue-u16", default-features = false, features = ["napi4", "tokio_rt"] } napi-derive = "2.4.1" +serde_json = "1.0.79" [build-dependencies] napi-build = "2.0.0" \ No newline at end of file diff --git a/crates/matrix-sdk-crypto-nodejs/src/errors.rs b/crates/matrix-sdk-crypto-nodejs/src/errors.rs index 3b35a55ce..7eb96bdbc 100644 --- a/crates/matrix-sdk-crypto-nodejs/src/errors.rs +++ b/crates/matrix-sdk-crypto-nodejs/src/errors.rs @@ -16,3 +16,10 @@ impl From for napi::Error { value.0 } } + +pub fn into_err(error: E) -> napi::Error +where + E: std::error::Error, +{ + Error::from(error).into() +} diff --git a/crates/matrix-sdk-crypto-nodejs/src/identifiers.rs b/crates/matrix-sdk-crypto-nodejs/src/identifiers.rs index 47c8ec448..f5bcea54f 100644 --- a/crates/matrix-sdk-crypto-nodejs/src/identifiers.rs +++ b/crates/matrix-sdk-crypto-nodejs/src/identifiers.rs @@ -3,7 +3,7 @@ use napi_derive::*; -use crate::errors::*; +use crate::into_err; /// A Matrix [user ID]. /// @@ -25,11 +25,7 @@ impl UserId { /// Parse/validate and create a new `UserId`. #[napi(constructor)] pub fn new(id: String) -> Result { - Ok(Self::new_with( - ruma::UserId::parse(id.as_str()) - .map_err(Error::from) - .map_err(Into::::into)?, - )) + Ok(Self::new_with(ruma::UserId::parse(id.as_str()).map_err(into_err)?)) } /// Returns the user's localpart. @@ -114,9 +110,7 @@ impl RoomId { /// Parse/validate and create a new `RoomId`. #[napi(constructor)] pub fn new(id: String) -> Result { - Ok(Self::new_with( - ruma::RoomId::parse(id).map_err(Error::from).map_err(Into::::into)?, - )) + Ok(Self::new_with(ruma::RoomId::parse(id).map_err(into_err)?)) } /// Returns the user's localpart. @@ -156,11 +150,7 @@ impl ServerName { /// Parse/validate and create a new `ServerName`. #[napi(constructor)] pub fn new(name: String) -> Result { - Ok(Self { - inner: ruma::ServerName::parse(name) - .map_err(Error::from) - .map_err(Into::::into)?, - }) + Ok(Self { inner: ruma::ServerName::parse(name).map_err(into_err)? }) } /// Returns the host of the server name. diff --git a/crates/matrix-sdk-crypto-nodejs/src/lib.rs b/crates/matrix-sdk-crypto-nodejs/src/lib.rs index ad3f0a361..753fede74 100644 --- a/crates/matrix-sdk-crypto-nodejs/src/lib.rs +++ b/crates/matrix-sdk-crypto-nodejs/src/lib.rs @@ -20,5 +20,6 @@ mod errors; pub mod events; pub mod identifiers; pub mod machine; +pub mod sync_events; -pub use crate::errors::Error; +use crate::errors::into_err; diff --git a/crates/matrix-sdk-crypto-nodejs/src/machine.rs b/crates/matrix-sdk-crypto-nodejs/src/machine.rs index 7668a7880..dd7f28c1d 100644 --- a/crates/matrix-sdk-crypto-nodejs/src/machine.rs +++ b/crates/matrix-sdk-crypto-nodejs/src/machine.rs @@ -1,8 +1,11 @@ //! The crypto specific Olm objects. -use napi_derive::*; +use std::collections::{BTreeMap, HashMap}; -use crate::identifiers; +use napi_derive::*; +use ruma::{DeviceKeyAlgorithm, UInt}; + +use crate::{identifiers, into_err, sync_events}; /// State machine implementation of the Olm/Megolm encryption protocol /// used for Matrix end to end encryption. @@ -51,6 +54,44 @@ impl OlmMachine { self.inner.identity_keys().into() } + #[napi] + pub async fn receive_sync_changes( + &self, + to_device_events: String, + changed_devices: &sync_events::DeviceLists, + one_time_key_counts: HashMap, + unused_fallback_keys: Vec, + ) -> Result { + let to_device_events = serde_json::from_str(to_device_events.as_ref()).map_err(into_err)?; + let changed_devices = changed_devices.inner.clone(); + let one_time_key_counts = one_time_key_counts + .iter() + .filter_map(|(key, value)| { + Some((DeviceKeyAlgorithm::from(key.as_str()), UInt::new(*value as u64)?)) + }) + .collect::>(); + let unused_fallback_keys = Some( + unused_fallback_keys + .into_iter() + .map(|key| DeviceKeyAlgorithm::from(key.as_str())) + .collect::>(), + ); + + Ok(serde_json::to_string( + &self + .inner + .receive_sync_changes( + to_device_events, + &changed_devices, + &one_time_key_counts, + unused_fallback_keys.as_deref(), + ) + .await + .map_err(into_err)?, + ) + .map_err(into_err)?) + } + #[napi] pub async fn update_tracked_users(&self, users: Vec<&identifiers::UserId>) { let users: Vec = diff --git a/crates/matrix-sdk-crypto-nodejs/src/sync_events.rs b/crates/matrix-sdk-crypto-nodejs/src/sync_events.rs new file mode 100644 index 000000000..c44433a4e --- /dev/null +++ b/crates/matrix-sdk-crypto-nodejs/src/sync_events.rs @@ -0,0 +1,41 @@ +//! `GET /_matrix/client/*/sync`. + +use napi_derive::*; + +use crate::identifiers; + +/// Information on E2E device updates. +#[napi] +pub struct DeviceLists { + pub(crate) inner: ruma::api::client::sync::sync_events::v3::DeviceLists, +} + +#[napi] +impl DeviceLists { + /// Create an empty `DeviceLists`. + #[napi(constructor)] + pub fn new(changed: Vec<&identifiers::UserId>, left: Vec<&identifiers::UserId>) -> Self { + let mut inner = ruma::api::client::sync::sync_events::v3::DeviceLists::default(); + + inner.changed = changed.into_iter().map(|user| user.inner.clone()).collect(); + inner.left = left.into_iter().map(|user| user.inner.clone()).collect(); + + Self { inner } + } + + /// Returns true if there are no device list updates. + #[napi] + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + #[napi] + pub fn changed(&self) -> Vec { + self.inner.changed.iter().map(|user| identifiers::UserId::new_with(user.clone())).collect() + } + + #[napi] + pub fn left(&self) -> Vec { + self.inner.left.iter().map(|user| identifiers::UserId::new_with(user.clone())).collect() + } +}