Skip to content

Commit c1107be

Browse files
committed
Expose bindings to manage dehydrated devices
1 parent 0cf6e95 commit c1107be

File tree

3 files changed

+194
-0
lines changed

3 files changed

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

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)