feat(crypto) Implement OlmMachine.receive_sync_changes & friends.

This commit is contained in:
Ivan Enderlin
2022-05-10 15:44:49 +02:00
parent 3318789a8b
commit 3aa46fa746
7 changed files with 214 additions and 69 deletions
@@ -0,0 +1,56 @@
//! Types for [Matrix](https://matrix.org/) identifiers for devices,
//! events, keys, rooms, servers, users and URIs.
use wasm_bindgen::prelude::*;
/// A Matrix [user ID].
///
/// [user ID]: https://spec.matrix.org/v1.2/appendices/#user-identifiers
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct UserId {
pub(crate) inner: ruma::OwnedUserId,
}
#[wasm_bindgen]
impl UserId {
/// Parse/validate and create a new `UserId`.
#[wasm_bindgen(constructor)]
pub fn new(id: &str) -> Result<UserId, String> {
Ok(Self { inner: ruma::UserId::parse(id).map_err(|e| e.to_string())? })
}
/// Returns the user's localpart.
pub fn localpart(&self) -> String {
self.inner.localpart().to_owned()
}
/// Whether this user ID is a historical one.
///
/// A historical user ID is one that doesn't conform to the latest
/// specification of the user ID grammar but is still accepted
/// because it was previously allowed.
#[wasm_bindgen(getter, js_name = "isHistorical")]
pub fn is_historical(&self) -> bool {
self.inner.is_historical()
}
}
/// A Matrix key ID.
///
/// Device identifiers in Matrix are completely opaque character
/// sequences. This type is provided simply for its semantic value.
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct DeviceId {
pub(crate) inner: ruma::OwnedDeviceId,
}
#[wasm_bindgen]
impl DeviceId {
/// Create a new `DeviceId`.
#[wasm_bindgen(constructor)]
pub fn new(id: &str) -> DeviceId {
Self { inner: id.into() }
}
}
@@ -0,0 +1,85 @@
use std::{collections::BTreeMap, sync::Arc};
use js_sys::{Array, Map, Promise, Set};
use ruma::{DeviceKeyAlgorithm, UInt};
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::future_to_promise;
use crate::js::{identifiers, sync_events};
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: String);
}
#[wasm_bindgen]
#[derive(Debug)]
pub struct OlmMachine {
inner: Arc<crate::OlmMachine>,
}
#[cfg_attr(feature = "js", wasm_bindgen)]
impl OlmMachine {
#[wasm_bindgen(constructor)]
pub fn new(user_id: &identifiers::UserId, device_id: &identifiers::DeviceId) -> Promise {
let user_id = user_id.inner.clone();
let device_id = device_id.inner.clone();
future_to_promise(async move {
Ok(JsValue::from(OlmMachine {
inner: Arc::new(crate::OlmMachine::new(user_id.as_ref(), device_id.as_ref()).await),
}))
})
}
pub fn receive_sync_changes(
&self,
to_device_events: &str,
changed_devices: &sync_events::DeviceLists,
one_time_key_counts: &Map,
unused_fallback_keys: &Set,
) -> Promise {
let to_device_events = serde_json::from_str(to_device_events).unwrap();
let changed_devices = changed_devices.inner.clone();
let one_time_key_counts: BTreeMap<DeviceKeyAlgorithm, UInt> = one_time_key_counts
.entries()
.into_iter()
.filter_map(|js_value| {
let pair = Array::from(&js_value.ok()?);
let (key, value) = (
DeviceKeyAlgorithm::from(pair.at(0).as_string()?),
UInt::new(pair.at(1).as_f64()? as u64)?,
);
Some((key, value))
})
.collect();
let unused_fallback_keys: Option<Vec<DeviceKeyAlgorithm>> = Some(
unused_fallback_keys
.values()
.into_iter()
.filter_map(|js_value| Some(DeviceKeyAlgorithm::from(js_value.ok()?.as_string()?)))
.collect(),
);
let me = self.inner.clone();
future_to_promise(async move {
Ok(JsValue::from(
serde_json::to_string(
&me.receive_sync_changes(
to_device_events,
&changed_devices,
&one_time_key_counts,
unused_fallback_keys.as_deref(),
)
.await
.unwrap(),
)
.unwrap(),
))
})
}
}
+3 -38
View File
@@ -1,40 +1,5 @@
//! Additional API that can be useful from JavaScript.
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct UserId {
pub(crate) inner: ruma::OwnedUserId,
}
#[wasm_bindgen]
impl UserId {
#[wasm_bindgen(constructor)]
pub fn new(id: &str) -> Result<UserId, String> {
Ok(Self { inner: ruma::UserId::parse(id).map_err(|e| e.to_string())? })
}
pub fn localpart(&self) -> String {
self.inner.localpart().to_owned()
}
#[wasm_bindgen(getter, js_name = "isHistorical")]
pub fn is_historical(&self) -> bool {
self.inner.is_historical()
}
}
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct DeviceId {
pub(crate) inner: ruma::OwnedDeviceId,
}
#[wasm_bindgen]
impl DeviceId {
#[wasm_bindgen(constructor)]
pub fn new(id: &str) -> DeviceId {
Self { inner: id.into() }
}
}
pub mod identifiers;
pub mod machine;
pub mod sync_events;
@@ -0,0 +1,50 @@
//! `GET /_matrix/client/*/sync`
use js_sys::Array;
use wasm_bindgen::prelude::*;
use crate::js::identifiers;
/// Information on E2E device updates.
#[wasm_bindgen]
#[derive(Debug)]
pub struct DeviceLists {
pub(crate) inner: ruma::api::client::sync::sync_events::v3::DeviceLists,
}
#[wasm_bindgen]
impl DeviceLists {
/// Create an empty `DeviceLists`.
#[wasm_bindgen(constructor)]
pub fn new() -> DeviceLists {
Self { inner: Default::default() }
}
/// Returns true if there are no device list updates.
#[wasm_bindgen(js_name = "isEmpty")]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
/// List of users who have updated their device identity keys or who now
/// share an encrypted room with the client since the previous sync
pub fn changed(&self) -> Array {
self.inner
.changed
.iter()
.map(|user| identifiers::UserId { inner: user.clone() })
.map(JsValue::from)
.collect()
}
/// List of users who no longer share encrypted rooms since the previous
/// sync response.
pub fn left(&self) -> Array {
self.inner
.left
.iter()
.map(|user| identifiers::UserId { inner: user.clone() })
.map(JsValue::from)
.collect()
}
}
-25
View File
@@ -47,14 +47,10 @@ use ruma::{
};
use serde_json::Value;
use tracing::{debug, error, info, trace, warn};
#[cfg(feature = "js")]
use wasm_bindgen::prelude::*;
use zeroize::Zeroize;
#[cfg(feature = "backups_v1")]
use crate::backups::BackupMachine;
#[cfg(feature = "js")]
use crate::js;
use crate::{
error::{EventError, MegolmError, MegolmResult, OlmError, OlmResult},
gossiping::GossipMachine,
@@ -76,7 +72,6 @@ use crate::{
/// State machine implementation of the Olm/Megolm encryption protocol used for
/// Matrix end to end encryption.
#[cfg_attr(feature = "js", wasm_bindgen)]
#[derive(Clone)]
pub struct OlmMachine {
/// The unique user id that owns this account.
@@ -1520,26 +1515,6 @@ impl OlmMachine {
}
}
#[cfg_attr(feature = "js", wasm_bindgen)]
impl OlmMachine {
#[wasm_bindgen(constructor)]
pub async fn js_new(user_id: js::UserId, device_id: js::DeviceId) -> js_sys::Promise {
js_sys::Promise::new(&mut |resolve, reject| {
let user_id = user_id.inner.clone();
let device_id = device_id.inner.clone();
wasm_bindgen_futures::spawn_local(async move {
let result = Self::new(user_id.as_ref(), device_id.as_ref()).await;
resolve
.call1(&wasm_bindgen::JsValue::UNDEFINED, &wasm_bindgen::JsValue::from(result))
.unwrap_throw();
})
})
}
//pub async fn new(user_id: &UserId, device_id: &DeviceId) -> Self {
}
#[cfg(any(feature = "testing", test))]
pub(crate) mod testing {
#![allow(dead_code)]
+1 -1
View File
@@ -1,2 +1,2 @@
build:
wasm-pack build --target nodejs ../../crates/matrix-sdk-crypto --features js
wasm-pack build --release --target nodejs ../../crates/matrix-sdk-crypto --features js
+19 -5
View File
@@ -1,14 +1,28 @@
const { UserId, DeviceId, OlmMachine } = require('../../crates/matrix-sdk-crypto/pkg');
const { UserId, DeviceId, OlmMachine, ToDevice, DeviceLists } = require('../../crates/matrix-sdk-crypto/pkg');
async function run_example() {
const user_id = new UserId('@alice:example.org');
console.log(user_id);
const device_id = new DeviceId("DEVICE_ID");
console.log(device_id);
const device_id = new DeviceId('DEVICE_ID');
const olm_machine = await new OlmMachine(user_id, device_id);
console.log(olm_machine);
const to_device_events = '{}';
const changed_devices = new DeviceLists();
const one_time_key_counts = new Map();
one_time_key_counts.set('foo', 42);
one_time_key_counts.set('bar', 153);
const unused_fallback_keys = new Set();
unused_fallback_keys.add('baz');
unused_fallback_keys.add('qux');
const decrypted_to_device = await olm_machine.receive_sync_changes(
to_device_events,
changed_devices,
one_time_key_counts,
unused_fallback_keys,
);
console.log(JSON.parse(decrypted_to_device));
}
run_example();