Skip to content

Commit cf96a3b

Browse files
authored
feat(crypto-js): Implement key verification
feat(crypto-js): Implement key verification
2 parents 83d5e56 + 9d2e0fe commit cf96a3b

File tree

16 files changed

+2797
-63
lines changed

16 files changed

+2797
-63
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindings/matrix-sdk-crypto-js/Cargo.toml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@ wasm-opt = ['-Oz']
2121
crate-type = ["cdylib"]
2222

2323
[features]
24-
default = ["tracing"]
25-
qrcode = ["matrix-sdk-crypto/qrcode"]
24+
default = ["tracing", "qrcode"]
25+
qrcode = ["matrix-sdk-crypto/qrcode", "dep:matrix-sdk-qrcode"]
2626
tracing = []
2727

2828
[dependencies]
2929
matrix-sdk-common = { version = "0.5.0", path = "../../crates/matrix-sdk-common" }
3030
matrix-sdk-crypto = { version = "0.5.0", path = "../../crates/matrix-sdk-crypto" }
3131
matrix-sdk-indexeddb = { version = "0.1.0", path = "../../crates/matrix-sdk-indexeddb" }
32+
matrix-sdk-qrcode = { version = "0.3.0", path = "../../crates/matrix-sdk-qrcode", optional = true }
3233
ruma = { version = "0.7.0", features = ["client-api-c", "js", "rand", "unstable-msc2676", "unstable-msc2677"] }
34+
vodozemac = { version = "0.3.0", features = ["js"] }
3335
wasm-bindgen = "0.2.80"
3436
wasm-bindgen-futures = "0.4.30"
3537
js-sys = "0.3.49"
@@ -39,8 +41,4 @@ http = "0.2.6"
3941
anyhow = "1.0.58"
4042
tracing = { version = "0.1.35", default-features = false, features = ["attributes"] }
4143
tracing-subscriber = { version = "0.3.14", default-features = false, features = ["registry", "std"] }
42-
zeroize = "1.3.0"
43-
44-
[dependencies.vodozemac]
45-
version = "0.3.0"
46-
features = ["js"]
44+
zeroize = "1.3.0"

bindings/matrix-sdk-crypto-js/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
"pkg/matrix_sdk_crypto.d.ts"
2727
],
2828
"devDependencies": {
29-
"wasm-pack": "^0.10.2",
29+
"cross-env": "^7.0.3",
30+
"fake-indexeddb": "^4.0",
3031
"jest": "^28.1.0",
3132
"typedoc": "^0.22.17",
32-
"cross-env": "^7.0.3",
33-
"yargs-parser": "~21.0.1",
34-
"fake-indexeddb": "^4.0"
33+
"wasm-pack": "^0.10.2",
34+
"yargs-parser": "~21.0.1"
3535
},
3636
"engines": {
3737
"node": ">= 10"
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
//! Types for a `Device`.
2+
3+
use js_sys::{Array, Map, Promise};
4+
use wasm_bindgen::prelude::*;
5+
6+
use crate::{
7+
future::future_to_promise,
8+
identifiers::{self, DeviceId, UserId},
9+
types, verification, vodozemac,
10+
};
11+
12+
/// A device represents a E2EE capable client of an user.
13+
#[wasm_bindgen]
14+
#[derive(Debug)]
15+
pub struct Device {
16+
pub(crate) inner: matrix_sdk_crypto::Device,
17+
}
18+
19+
impl From<matrix_sdk_crypto::Device> for Device {
20+
fn from(inner: matrix_sdk_crypto::Device) -> Self {
21+
Self { inner }
22+
}
23+
}
24+
25+
#[wasm_bindgen]
26+
impl Device {
27+
/// Request an interactive verification with this device.
28+
#[wasm_bindgen(js_name = "requestVerification")]
29+
pub fn request_verification(&self, methods: Option<Array>) -> Result<Promise, JsError> {
30+
let methods = methods
31+
.map(|array| {
32+
array
33+
.iter()
34+
.map(|method| {
35+
verification::VerificationMethod::try_from(method).map(Into::into)
36+
})
37+
.collect::<Result<_, _>>()
38+
})
39+
.transpose()?;
40+
let me = self.inner.clone();
41+
42+
Ok(future_to_promise(async move {
43+
let tuple = Array::new();
44+
let (verification_request, outgoing_verification_request) = match methods {
45+
Some(methods) => me.request_verification_with_methods(methods).await,
46+
None => me.request_verification().await,
47+
};
48+
49+
tuple.set(0, verification::VerificationRequest::from(verification_request).into());
50+
tuple.set(
51+
1,
52+
verification::OutgoingVerificationRequest::from(outgoing_verification_request)
53+
.try_into()?,
54+
);
55+
56+
Ok(tuple)
57+
}))
58+
}
59+
60+
/// Is this device considered to be verified.
61+
///
62+
/// This method returns true if either the `is_locally_trusted`
63+
/// method returns `true` or if the `is_cross_signing_trusted`
64+
/// method returns `true`.
65+
#[wasm_bindgen(js_name = "isVerified")]
66+
pub fn is_verified(&self) -> bool {
67+
self.inner.is_verified()
68+
}
69+
70+
/// Is this device considered to be verified using cross signing.
71+
#[wasm_bindgen(js_name = "isCrossSigningTrusted")]
72+
pub fn is_cross_signing_trusted(&self) -> bool {
73+
self.inner.is_cross_signing_trusted()
74+
}
75+
76+
/// Set the local trust state of the device to the given state.
77+
///
78+
/// This won’t affect any cross signing trust state, this only
79+
/// sets a flag marking to have the given trust state.
80+
///
81+
/// `trust_state` represents the new trust state that should be
82+
/// set for the device.
83+
#[wasm_bindgen(js_name = "setLocalTrust")]
84+
pub fn set_local_trust(&self, local_state: LocalTrust) -> Promise {
85+
let me = self.inner.clone();
86+
87+
future_to_promise(async move {
88+
me.set_local_trust(local_state.into()).await?;
89+
90+
Ok(JsValue::NULL)
91+
})
92+
}
93+
94+
/// The user ID of the device owner.
95+
#[wasm_bindgen(getter, js_name = "userId")]
96+
pub fn user_id(&self) -> UserId {
97+
self.inner.user_id().to_owned().into()
98+
}
99+
100+
/// The unique ID of the device.
101+
#[wasm_bindgen(getter, js_name = "deviceId")]
102+
pub fn device_id(&self) -> DeviceId {
103+
self.inner.device_id().to_owned().into()
104+
}
105+
106+
/// Get the human readable name of the device.
107+
#[wasm_bindgen(getter, js_name = "displayName")]
108+
pub fn display_name(&self) -> Option<String> {
109+
self.inner.display_name().map(ToOwned::to_owned)
110+
}
111+
112+
/// Get the key of the given key algorithm belonging to this device.
113+
#[wasm_bindgen(js_name = "getKey")]
114+
pub fn get_key(
115+
&self,
116+
algorithm: identifiers::DeviceKeyAlgorithmName,
117+
) -> Result<Option<vodozemac::DeviceKey>, JsError> {
118+
Ok(self.inner.get_key(algorithm.try_into()?).cloned().map(Into::into))
119+
}
120+
121+
/// Get the Curve25519 key of the given device.
122+
#[wasm_bindgen(getter, js_name = "curve25519Key")]
123+
pub fn curve25519_key(&self) -> Option<vodozemac::Curve25519PublicKey> {
124+
self.inner.curve25519_key().map(Into::into)
125+
}
126+
127+
/// Get the Ed25519 key of the given device.
128+
#[wasm_bindgen(getter, js_name = "ed25519Key")]
129+
pub fn ed25519_key(&self) -> Option<vodozemac::Ed25519PublicKey> {
130+
self.inner.ed25519_key().map(Into::into)
131+
}
132+
133+
/// Get a map containing all the device keys.
134+
#[wasm_bindgen(getter)]
135+
pub fn keys(&self) -> Map {
136+
let map = Map::new();
137+
138+
for (device_key_id, device_key) in self.inner.keys() {
139+
map.set(
140+
&identifiers::DeviceKeyId::from(device_key_id.clone()).into(),
141+
&vodozemac::DeviceKey::from(device_key.clone()).into(),
142+
);
143+
}
144+
145+
map
146+
}
147+
148+
/// Get a map containing all the device signatures.
149+
#[wasm_bindgen(getter)]
150+
pub fn signatures(&self) -> types::Signatures {
151+
self.inner.signatures().clone().into()
152+
}
153+
154+
/// Get the trust state of the device.
155+
#[wasm_bindgen(getter, js_name = "localTrustState")]
156+
pub fn local_trust_state(&self) -> LocalTrust {
157+
self.inner.local_trust_state().into()
158+
}
159+
160+
/// Is the device locally marked as trusted?
161+
#[wasm_bindgen(js_name = "isLocallyTrusted")]
162+
pub fn is_locally_trusted(&self) -> bool {
163+
self.inner.is_locally_trusted()
164+
}
165+
166+
/// Is the device locally marked as blacklisted?
167+
///
168+
/// Blacklisted devices won’t receive any group sessions.
169+
#[wasm_bindgen(js_name = "isBlacklisted")]
170+
pub fn is_blacklisted(&self) -> bool {
171+
self.inner.is_blacklisted()
172+
}
173+
174+
/// Is the device deleted?
175+
#[wasm_bindgen(js_name = "isDeleted")]
176+
pub fn is_deleted(&self) -> bool {
177+
self.inner.is_deleted()
178+
}
179+
}
180+
181+
/// The local trust state of a device.
182+
#[wasm_bindgen]
183+
#[derive(Debug)]
184+
pub enum LocalTrust {
185+
/// The device has been verified and is trusted.
186+
Verified,
187+
188+
/// The device been blacklisted from communicating.
189+
BlackListed,
190+
191+
/// The trust state of the device is being ignored.
192+
Ignored,
193+
194+
/// The trust state is unset.
195+
Unset,
196+
}
197+
198+
impl From<matrix_sdk_crypto::LocalTrust> for LocalTrust {
199+
fn from(value: matrix_sdk_crypto::LocalTrust) -> Self {
200+
use matrix_sdk_crypto::LocalTrust::*;
201+
202+
match value {
203+
Verified => Self::Verified,
204+
BlackListed => Self::BlackListed,
205+
Ignored => Self::Ignored,
206+
Unset => Self::Unset,
207+
}
208+
}
209+
}
210+
211+
impl From<LocalTrust> for matrix_sdk_crypto::LocalTrust {
212+
fn from(value: LocalTrust) -> Self {
213+
use LocalTrust::*;
214+
215+
match value {
216+
Verified => Self::Verified,
217+
BlackListed => Self::BlackListed,
218+
Ignored => Self::Ignored,
219+
Unset => Self::Unset,
220+
}
221+
}
222+
}
223+
224+
/// A read only view over all devices belonging to a user.
225+
#[wasm_bindgen]
226+
#[derive(Debug)]
227+
pub struct UserDevices {
228+
pub(crate) inner: matrix_sdk_crypto::UserDevices,
229+
}
230+
231+
impl From<matrix_sdk_crypto::UserDevices> for UserDevices {
232+
fn from(inner: matrix_sdk_crypto::UserDevices) -> Self {
233+
Self { inner }
234+
}
235+
}
236+
237+
#[wasm_bindgen]
238+
impl UserDevices {
239+
/// Get the specific device with the given device ID.
240+
pub fn get(&self, device_id: &DeviceId) -> Option<Device> {
241+
self.inner.get(&device_id.inner).map(Into::into)
242+
}
243+
244+
/// Returns true if there is at least one devices of this user
245+
/// that is considered to be verified, false otherwise.
246+
///
247+
/// This won't consider your own device as verified, as your own
248+
/// device is always implicitly verified.
249+
#[wasm_bindgen(js_name = "isAnyVerified")]
250+
pub fn is_any_verified(&self) -> bool {
251+
self.inner.is_any_verified()
252+
}
253+
254+
/// Array over all the device IDs of the user devices.
255+
pub fn keys(&self) -> Array {
256+
self.inner.keys().map(ToOwned::to_owned).map(DeviceId::from).map(JsValue::from).collect()
257+
}
258+
259+
/// Iterator over all the devices of the user devices.
260+
pub fn devices(&self) -> Array {
261+
self.inner.devices().map(Device::from).map(JsValue::from).collect()
262+
}
263+
}

bindings/matrix-sdk-crypto-js/src/identifiers.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl DeviceKeyId {
135135
#[wasm_bindgen]
136136
#[derive(Debug)]
137137
pub struct DeviceKeyAlgorithm {
138-
inner: ruma::DeviceKeyAlgorithm,
138+
pub(crate) inner: ruma::DeviceKeyAlgorithm,
139139
}
140140

141141
impl From<ruma::DeviceKeyAlgorithm> for DeviceKeyAlgorithm {
@@ -180,6 +180,25 @@ pub enum DeviceKeyAlgorithmName {
180180
Unknown,
181181
}
182182

183+
impl TryFrom<DeviceKeyAlgorithmName> for ruma::DeviceKeyAlgorithm {
184+
type Error = JsError;
185+
186+
fn try_from(value: DeviceKeyAlgorithmName) -> Result<Self, Self::Error> {
187+
use DeviceKeyAlgorithmName::*;
188+
189+
Ok(match value {
190+
Ed25519 => Self::Ed25519,
191+
Curve25519 => Self::Curve25519,
192+
SignedCurve25519 => Self::SignedCurve25519,
193+
Unknown => {
194+
return Err(JsError::new(
195+
"The `DeviceKeyAlgorithmName.Unknown` variant cannot be converted",
196+
))
197+
}
198+
})
199+
}
200+
}
201+
183202
impl From<ruma::DeviceKeyAlgorithm> for DeviceKeyAlgorithmName {
184203
fn from(value: ruma::DeviceKeyAlgorithm) -> Self {
185204
use ruma::DeviceKeyAlgorithm::*;

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#![allow(clippy::drop_non_drop)] // triggered by wasm_bindgen code
1919

2020
pub mod attachment;
21+
pub mod device;
2122
pub mod encryption;
2223
pub mod events;
2324
mod future;
@@ -26,9 +27,11 @@ pub mod machine;
2627
pub mod olm;
2728
pub mod requests;
2829
pub mod responses;
30+
pub mod store;
2931
pub mod sync_events;
3032
mod tracing;
3133
pub mod types;
34+
pub mod verification;
3235
pub mod vodozemac;
3336

3437
use js_sys::{Object, Reflect};

0 commit comments

Comments
 (0)