Skip to content

Commit

Permalink
Add bindings for dehydrated devices (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
uhoreg authored Mar 22, 2024
1 parent fa8ebb8 commit 0634134
Show file tree
Hide file tree
Showing 9 changed files with 370 additions and 25 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# UNRELEASED

- Add `OlmMachine.dehydratedDevices()` and `DehydratedDevices` class to
support dehydrated devices.
([#104](https://github.com/matrix-org/matrix-rust-sdk-crypto-wasm/pull/104))

- Fix a problem when using matrix-sdk-crypto-wasm in a webapp running
in the webpack dev server; when rebuilding, the server would throw an
error.
Expand Down
42 changes: 25 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

117 changes: 117 additions & 0 deletions src/dehydrated_devices.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//! Dehydrated devices
//!
//! WASM wrapper for `matrix_sdk_crypto::dehydrated_devices`.
use js_sys::{Array, JsString, Uint8Array};
use matrix_sdk_crypto::dehydrated_devices;
use wasm_bindgen::prelude::*;

use crate::{identifiers::DeviceId, requests::PutDehydratedDeviceRequest, store::RoomKeyInfo};

#[wasm_bindgen]
#[derive(Debug)]
/// Struct collecting methods to create and rehydrate dehydrated devices.
pub struct DehydratedDevices {
inner: dehydrated_devices::DehydratedDevices,
}

impl From<dehydrated_devices::DehydratedDevices> for DehydratedDevices {
fn from(value: dehydrated_devices::DehydratedDevices) -> Self {
Self { inner: value }
}
}

#[wasm_bindgen]
impl DehydratedDevices {
/// Create a new [`DehydratedDevice`] which can be uploaded to the server.
#[wasm_bindgen]
pub async fn create(&self) -> Result<DehydratedDevice, JsError> {
Ok(self.inner.create().await?.into())
}

/// Rehydrate a dehydrated device.
#[wasm_bindgen]
pub async fn rehydrate(
&self,
pickle_key: &Uint8Array,
device_id: &DeviceId,
device_data: &str,
) -> Result<RehydratedDevice, JsError> {
let pickle_key: [u8; 32] =
pickle_key.to_vec().try_into().map_err(|_| JsError::new("Wrong key length"))?;
Ok(self
.inner
.rehydrate(&pickle_key, &device_id.inner, serde_json::from_str(device_data)?)
.await?
.into())
}
}

#[wasm_bindgen]
#[derive(Debug)]
/// A rehydrated device
///
/// This device can receive to-device events to get room keys that were send to
/// it.
pub struct RehydratedDevice {
inner: dehydrated_devices::RehydratedDevice,
}

impl From<dehydrated_devices::RehydratedDevice> for RehydratedDevice {
fn from(value: dehydrated_devices::RehydratedDevice) -> Self {
Self { inner: value }
}
}

#[wasm_bindgen]
impl RehydratedDevice {
#[wasm_bindgen(js_name = "receiveEvents")]
/// Receive the to-device events that sent to the dehydrated device
///
/// The rehydrated device will decrypt the events and pass the room keys
/// into the `OlmMachine`.
///
/// `to_device_events` is a JSON-encoded result of the `events` array from
/// `/dehydrated_device/{device_id}/events`.
///
/// Returns an array of `RoomKeyInfo`, indicating the room keys that were
/// received.
pub async fn receive_events(&self, to_device_events: &str) -> Result<Array, JsError> {
let to_device_events = serde_json::from_str(to_device_events)?;

let room_key_info = self.inner.receive_events(to_device_events).await?;
Ok(room_key_info.into_iter().map(RoomKeyInfo::from).map(JsValue::from).collect())
}
}

#[wasm_bindgen]
#[derive(Debug)]
/// A dehydrated device that can be uploaded to the server
pub struct DehydratedDevice {
inner: dehydrated_devices::DehydratedDevice,
}

impl From<dehydrated_devices::DehydratedDevice> for DehydratedDevice {
fn from(value: dehydrated_devices::DehydratedDevice) -> Self {
Self { inner: value }
}
}

#[wasm_bindgen]
impl DehydratedDevice {
#[wasm_bindgen(js_name = "keysForUpload")]
/// Create the request to upload the dehydrated device
pub async fn keys_for_upload(
&self,
initial_device_display_name: JsString,
pickle_key: Uint8Array,
) -> Result<PutDehydratedDeviceRequest, JsError> {
let pickle_key: [u8; 32] =
pickle_key.to_vec().try_into().map_err(|_| JsError::new("Wrong key length"))?;
Ok(self
.inner
.keys_for_upload(initial_device_display_name.into(), &pickle_key)
.await?
.try_into()?)
}
}
6 changes: 6 additions & 0 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ impl Device {
Ok(requests::SignatureUploadRequest::try_from(&device.verify().await?)?)
})
}

/// Whether or not the device is a dehydrated device.
#[wasm_bindgen(getter, js_name = "isDehydrated")]
pub fn is_dehydrated(&self) -> bool {
self.inner.is_dehydrated()
}
}

/// The local trust state of a device.
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

pub mod attachment;
pub mod backup;
pub mod dehydrated_devices;
pub mod device;
pub mod encryption;
pub mod error;
Expand Down
2 changes: 2 additions & 0 deletions src/libolm_migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,11 @@ async fn migrate_base_data_to_store(
// device keys to the server (it does it every time the stack is started). For safety,
// let's assume it hasn't happened yet.
shared: false,
dehydrated: false,
// Assume we have 50 keys on the server, until we get a sync that says fewer.
uploaded_signed_key_count: 50,
creation_local_time: MilliSecondsSinceUnixEpoch::now(),
fallback_key_creation_timestamp: None,
})?;

let backup_decryption_key = data
Expand Down
7 changes: 7 additions & 0 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use wasm_bindgen_futures::{spawn_local, JsFuture};

use crate::{
backup::{BackupDecryptionKey, BackupKeys, RoomKeyCounts},
dehydrated_devices::DehydratedDevices,
device, encryption,
error::MegolmDecryptionError,
future::{future_to_promise, future_to_promise_with_custom_error},
Expand Down Expand Up @@ -1445,6 +1446,12 @@ impl OlmMachine {
Ok(())
}

/// Manage dehydrated devices
#[wasm_bindgen(js_name = "dehydratedDevices")]
pub fn dehydrated_devices(&self) -> DehydratedDevices {
self.inner.dehydrated_devices().into()
}

/// Shut down the `OlmMachine`.
///
/// The `OlmMachine` cannot be used after this method has been called.
Expand Down
Loading

0 comments on commit 0634134

Please sign in to comment.