Skip to content

Commit 38cdc6a

Browse files
committed
Expose bindings to manage dehydrated devices
1 parent 1089128 commit 38cdc6a

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
use std::{mem::ManuallyDrop, sync::Arc};
2+
3+
use matrix_sdk_crypto::dehydrated_devices::{
4+
DehydratedDevice as InnerDehydratedDevice, DehydratedDevices as InnerDehydratedDevices,
5+
RehydratedDevice as InnerRehydratedDevice,
6+
};
7+
use ruma::{api::client::dehydrated_device, events::AnyToDeviceEvent, serde::Raw, OwnedDeviceId};
8+
use serde_json::json;
9+
use tokio::runtime::Handle;
10+
use zeroize::Zeroize;
11+
12+
#[derive(Debug, thiserror::Error, uniffi::Error)]
13+
#[uniffi(flat_error)]
14+
pub enum DehydrationError {
15+
#[error(transparent)]
16+
Pickle(#[from] matrix_sdk_crypto::vodozemac::LibolmPickleError),
17+
#[error(transparent)]
18+
MissingSigningKey(#[from] matrix_sdk_crypto::SignatureError),
19+
#[error(transparent)]
20+
Json(#[from] serde_json::Error),
21+
#[error("The pickle key has an invalid length, expected 32 bytes, got {0}")]
22+
PickleKeyLength(usize),
23+
}
24+
25+
impl From<matrix_sdk_crypto::dehydrated_devices::DehydrationError> for DehydrationError {
26+
fn from(value: matrix_sdk_crypto::dehydrated_devices::DehydrationError) -> Self {
27+
match value {
28+
matrix_sdk_crypto::dehydrated_devices::DehydrationError::Json(e) => Self::Json(e),
29+
matrix_sdk_crypto::dehydrated_devices::DehydrationError::Pickle(e) => Self::Pickle(e),
30+
matrix_sdk_crypto::dehydrated_devices::DehydrationError::MissingSigningKey(e) => {
31+
Self::MissingSigningKey(e)
32+
}
33+
}
34+
}
35+
}
36+
37+
#[derive(uniffi::Object)]
38+
pub struct DehydratedDevices {
39+
pub(crate) runtime: Handle,
40+
pub(crate) inner: ManuallyDrop<InnerDehydratedDevices>,
41+
}
42+
43+
impl Drop for DehydratedDevices {
44+
fn drop(&mut self) {
45+
// See the drop implementation for the `crate::OlmMachine` for an explanation.
46+
let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
47+
let _guard = self.runtime.enter();
48+
drop(inner);
49+
}
50+
}
51+
52+
#[uniffi::export]
53+
impl DehydratedDevices {
54+
pub fn create(&self) -> Arc<DehydratedDevice> {
55+
DehydratedDevice {
56+
inner: ManuallyDrop::new(self.inner.create()),
57+
runtime: self.runtime.to_owned(),
58+
}
59+
.into()
60+
}
61+
62+
pub fn rehydrate(
63+
&self,
64+
pickle_key: Vec<u8>,
65+
device_id: String,
66+
device_data: String,
67+
) -> Result<Arc<RehydratedDevice>, DehydrationError> {
68+
let device_data: Raw<_> = serde_json::from_str(&device_data)?;
69+
let device_id: OwnedDeviceId = device_id.into();
70+
71+
let mut key = get_pickle_key(&pickle_key)?;
72+
73+
let ret = RehydratedDevice {
74+
runtime: self.runtime.to_owned(),
75+
inner: ManuallyDrop::new(self.runtime.block_on(self.inner.rehydrate(
76+
&key,
77+
&device_id,
78+
device_data,
79+
))?),
80+
}
81+
.into();
82+
83+
key.zeroize();
84+
85+
Ok(ret)
86+
}
87+
}
88+
89+
#[derive(uniffi::Object)]
90+
pub struct RehydratedDevice {
91+
inner: ManuallyDrop<InnerRehydratedDevice>,
92+
runtime: Handle,
93+
}
94+
95+
impl Drop for RehydratedDevice {
96+
fn drop(&mut self) {
97+
// See the drop implementation for the `crate::OlmMachine` for an explanation.
98+
let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
99+
let _guard = self.runtime.enter();
100+
drop(inner);
101+
}
102+
}
103+
104+
#[uniffi::export]
105+
impl RehydratedDevice {
106+
pub fn receive_events(&self, events: String) -> Result<(), crate::CryptoStoreError> {
107+
let events: Vec<Raw<AnyToDeviceEvent>> = serde_json::from_str(&events)?;
108+
self.runtime.block_on(self.inner.receive_events(events))?;
109+
110+
Ok(())
111+
}
112+
}
113+
114+
#[derive(uniffi::Object)]
115+
pub struct DehydratedDevice {
116+
pub(crate) runtime: Handle,
117+
pub(crate) inner: ManuallyDrop<InnerDehydratedDevice>,
118+
}
119+
120+
impl Drop for DehydratedDevice {
121+
fn drop(&mut self) {
122+
// See the drop implementation for the `crate::OlmMachine` for an explanation.
123+
let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
124+
let _guard = self.runtime.enter();
125+
drop(inner);
126+
}
127+
}
128+
129+
#[uniffi::export]
130+
impl DehydratedDevice {
131+
pub fn keys_for_upload(
132+
&self,
133+
device_display_name: String,
134+
pickle_key: Vec<u8>,
135+
) -> Result<UploadDehydratedDeviceRequest, DehydrationError> {
136+
let mut key = get_pickle_key(&pickle_key)?;
137+
138+
let request =
139+
self.runtime.block_on(self.inner.keys_for_upload(device_display_name, &key))?;
140+
141+
key.zeroize();
142+
143+
Ok(request.into())
144+
}
145+
}
146+
147+
#[derive(Debug, uniffi::Record)]
148+
pub struct UploadDehydratedDeviceRequest {
149+
/// The serialized JSON body of the request.
150+
body: String,
151+
}
152+
153+
impl From<dehydrated_device::put_dehydrated_device::unstable::Request>
154+
for UploadDehydratedDeviceRequest
155+
{
156+
fn from(value: dehydrated_device::put_dehydrated_device::unstable::Request) -> Self {
157+
let body = json!({
158+
"device_id": value.device_id,
159+
"device_data": value.device_data,
160+
"initial_device_display_name": value.initial_device_display_name,
161+
"device_keys": value.device_keys,
162+
"one_time_keys": value.one_time_keys,
163+
"fallback_keys": value.fallback_keys,
164+
});
165+
166+
let body = serde_json::to_string(&body)
167+
.expect("We should be able to serialize the PUT dehydrated devices request body");
168+
169+
Self { body }
170+
}
171+
}
172+
173+
fn get_pickle_key(pickle_key: &[u8]) -> Result<Box<[u8; 32]>, DehydrationError> {
174+
let pickle_key_length = pickle_key.len();
175+
176+
if pickle_key_length == 32 {
177+
let mut key = Box::new([0u8; 32]);
178+
key.copy_from_slice(pickle_key);
179+
180+
Ok(key)
181+
} else {
182+
Err(DehydrationError::PickleKeyLength(pickle_key_length))
183+
}
184+
}

bindings/matrix-sdk-crypto-ffi/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#![allow(unused_qualifications)]
88

99
mod backup_recovery_key;
10+
mod dehydrated_devices;
1011
mod device;
1112
mod error;
1213
mod logger;

bindings/matrix-sdk-crypto-ffi/src/machine.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use tokio::runtime::Runtime;
4848
use zeroize::Zeroize;
4949

5050
use crate::{
51+
dehydrated_devices::DehydratedDevices,
5152
error::{CryptoStoreError, DecryptionError, SecretImportError, SignatureError},
5253
parse_user_id,
5354
responses::{response_from_string, OwnedResponse},
@@ -1427,6 +1428,15 @@ impl OlmMachine {
14271428
.block_on(self.inner.backup_machine().verify_backup(backup_info, false))?
14281429
.into())
14291430
}
1431+
1432+
/// Manage dehydrated devices.
1433+
pub fn dehydrated_devices(&self) -> Arc<DehydratedDevices> {
1434+
DehydratedDevices {
1435+
inner: ManuallyDrop::new(self.inner.dehydrated_devices()),
1436+
runtime: self.runtime.handle().to_owned(),
1437+
}
1438+
.into()
1439+
}
14301440
}
14311441

14321442
impl OlmMachine {

0 commit comments

Comments
 (0)