matrix_sdk_crypto/types/events/
to_device.rs1use std::{collections::BTreeMap, fmt::Debug};
16
17use ruma::{
18 events::{
19 key::verification::{
20 accept::ToDeviceKeyVerificationAcceptEvent, cancel::ToDeviceKeyVerificationCancelEvent,
21 done::ToDeviceKeyVerificationDoneEvent, key::ToDeviceKeyVerificationKeyEvent,
22 mac::ToDeviceKeyVerificationMacEvent, ready::ToDeviceKeyVerificationReadyEvent,
23 request::ToDeviceKeyVerificationRequestEvent, start::ToDeviceKeyVerificationStartEvent,
24 },
25 secret::request::{SecretName, ToDeviceSecretRequestEvent},
26 ToDeviceEventContent, ToDeviceEventType,
27 },
28 serde::{JsonCastable, Raw},
29 OwnedUserId, UserId,
30};
31use serde::{Deserialize, Serialize};
32use serde_json::{
33 value::{to_raw_value, RawValue},
34 Value,
35};
36use zeroize::Zeroize;
37
38use super::{
39 dummy::DummyEvent,
40 forwarded_room_key::{ForwardedRoomKeyContent, ForwardedRoomKeyEvent},
41 room::encrypted::EncryptedToDeviceEvent,
42 room_key::RoomKeyEvent,
43 room_key_request::RoomKeyRequestEvent,
44 room_key_withheld::RoomKeyWithheldEvent,
45 secret_send::SecretSendEvent,
46 EventType,
47};
48use crate::types::events::from_str;
49
50#[derive(Debug)]
52pub enum ToDeviceEvents {
53 Custom(ToDeviceCustomEvent),
55 Dummy(DummyEvent),
57
58 KeyVerificationAccept(ToDeviceKeyVerificationAcceptEvent),
60 KeyVerificationCancel(ToDeviceKeyVerificationCancelEvent),
62 KeyVerificationKey(ToDeviceKeyVerificationKeyEvent),
64 KeyVerificationMac(ToDeviceKeyVerificationMacEvent),
66 KeyVerificationDone(ToDeviceKeyVerificationDoneEvent),
68 KeyVerificationStart(ToDeviceKeyVerificationStartEvent),
70 KeyVerificationReady(ToDeviceKeyVerificationReadyEvent),
72 KeyVerificationRequest(ToDeviceKeyVerificationRequestEvent),
74
75 RoomEncrypted(EncryptedToDeviceEvent),
77 RoomKey(RoomKeyEvent),
79 RoomKeyRequest(RoomKeyRequestEvent),
81 ForwardedRoomKey(Box<ForwardedRoomKeyEvent>),
83 SecretSend(SecretSendEvent),
85 SecretRequest(ToDeviceSecretRequestEvent),
87 RoomKeyWithheld(RoomKeyWithheldEvent),
89}
90
91impl ToDeviceEvents {
92 pub fn sender(&self) -> &UserId {
94 match self {
95 ToDeviceEvents::Custom(e) => &e.sender,
96 ToDeviceEvents::Dummy(e) => &e.sender,
97
98 ToDeviceEvents::KeyVerificationAccept(e) => &e.sender,
99 ToDeviceEvents::KeyVerificationCancel(e) => &e.sender,
100 ToDeviceEvents::KeyVerificationKey(e) => &e.sender,
101 ToDeviceEvents::KeyVerificationMac(e) => &e.sender,
102 ToDeviceEvents::KeyVerificationDone(e) => &e.sender,
103 ToDeviceEvents::KeyVerificationStart(e) => &e.sender,
104 ToDeviceEvents::KeyVerificationReady(e) => &e.sender,
105 ToDeviceEvents::KeyVerificationRequest(e) => &e.sender,
106
107 ToDeviceEvents::RoomEncrypted(e) => &e.sender,
108 ToDeviceEvents::RoomKey(e) => &e.sender,
109 ToDeviceEvents::RoomKeyRequest(e) => &e.sender,
110 ToDeviceEvents::ForwardedRoomKey(e) => &e.sender,
111
112 ToDeviceEvents::SecretSend(e) => &e.sender,
113 ToDeviceEvents::SecretRequest(e) => &e.sender,
114 ToDeviceEvents::RoomKeyWithheld(e) => &e.sender,
115 }
116 }
117
118 pub fn event_type(&self) -> ToDeviceEventType {
120 match self {
121 ToDeviceEvents::Custom(e) => ToDeviceEventType::from(e.event_type.to_owned()),
122 ToDeviceEvents::Dummy(_) => ToDeviceEventType::Dummy,
123
124 ToDeviceEvents::KeyVerificationAccept(e) => e.content.event_type(),
125 ToDeviceEvents::KeyVerificationCancel(e) => e.content.event_type(),
126 ToDeviceEvents::KeyVerificationKey(e) => e.content.event_type(),
127 ToDeviceEvents::KeyVerificationMac(e) => e.content.event_type(),
128 ToDeviceEvents::KeyVerificationDone(e) => e.content.event_type(),
129 ToDeviceEvents::KeyVerificationStart(e) => e.content.event_type(),
130 ToDeviceEvents::KeyVerificationReady(e) => e.content.event_type(),
131 ToDeviceEvents::KeyVerificationRequest(e) => e.content.event_type(),
132
133 ToDeviceEvents::RoomEncrypted(_) => ToDeviceEventType::RoomEncrypted,
134 ToDeviceEvents::RoomKey(_) => ToDeviceEventType::RoomKey,
135 ToDeviceEvents::RoomKeyRequest(_) => ToDeviceEventType::RoomKeyRequest,
136 ToDeviceEvents::ForwardedRoomKey(_) => ToDeviceEventType::ForwardedRoomKey,
137
138 ToDeviceEvents::SecretSend(_) => ToDeviceEventType::SecretSend,
139 ToDeviceEvents::SecretRequest(e) => e.content.event_type(),
140 ToDeviceEvents::RoomKeyWithheld(e) => {
142 ToDeviceEventType::from(e.content.event_type().to_owned())
143 }
144 }
145 }
146
147 pub(crate) fn serialize_zeroized(self) -> Result<Raw<ToDeviceEvents>, serde_json::Error> {
177 let serialized = match self {
178 ToDeviceEvents::Custom(_)
179 | ToDeviceEvents::Dummy(_)
180 | ToDeviceEvents::KeyVerificationAccept(_)
181 | ToDeviceEvents::KeyVerificationCancel(_)
182 | ToDeviceEvents::KeyVerificationKey(_)
183 | ToDeviceEvents::KeyVerificationMac(_)
184 | ToDeviceEvents::KeyVerificationDone(_)
185 | ToDeviceEvents::KeyVerificationStart(_)
186 | ToDeviceEvents::KeyVerificationReady(_)
187 | ToDeviceEvents::KeyVerificationRequest(_)
188 | ToDeviceEvents::RoomEncrypted(_)
189 | ToDeviceEvents::RoomKeyRequest(_)
190 | ToDeviceEvents::RoomKeyWithheld(_)
191 | ToDeviceEvents::SecretRequest(_) => Raw::from_json(to_raw_value(&self)?),
192 ToDeviceEvents::RoomKey(e) => {
193 let event_type = e.content.event_type();
194 let content = e.content.serialize_zeroized()?;
195
196 #[derive(Serialize)]
197 struct Helper<'a, C> {
198 sender: &'a UserId,
199 content: &'a Raw<C>,
200 #[serde(rename = "type")]
201 event_type: &'a str,
202 }
203
204 let helper = Helper { sender: &e.sender, content: &content, event_type };
205
206 let raw_value = to_raw_value(&helper)?;
207
208 Raw::from_json(raw_value)
209 }
210 ToDeviceEvents::ForwardedRoomKey(mut e) => {
211 match &mut e.content {
212 ForwardedRoomKeyContent::MegolmV1AesSha2(c) => c.session_key.zeroize(),
213 #[cfg(feature = "experimental-algorithms")]
214 ForwardedRoomKeyContent::MegolmV2AesSha2(c) => c.session_key.zeroize(),
215 ForwardedRoomKeyContent::Unknown(_) => (),
216 }
217
218 Raw::from_json(to_raw_value(&e)?)
219 }
220 ToDeviceEvents::SecretSend(mut e) => {
221 if let Some(SecretName::RecoveryKey) = e.content.secret_name {
222 } else {
227 e.content.secret.zeroize();
228 }
229 Raw::from_json(to_raw_value(&e)?)
230 }
231 };
232
233 Ok(serialized)
234 }
235}
236
237impl JsonCastable<ToDeviceEvents> for ruma::events::AnyToDeviceEvent {}
238
239impl JsonCastable<ruma::events::AnyToDeviceEvent> for ToDeviceEvents {}
240
241#[derive(Clone, Debug, Deserialize, Serialize)]
243pub struct ToDeviceCustomEvent {
244 pub sender: OwnedUserId,
246 pub content: BTreeMap<String, Value>,
248 #[serde(rename = "type")]
250 pub event_type: String,
251 #[serde(flatten)]
253 other: BTreeMap<String, Value>,
254}
255
256#[derive(Debug)]
258pub struct ToDeviceEvent<C>
259where
260 C: EventType + Debug + Sized + Serialize,
261{
262 pub sender: OwnedUserId,
264 pub content: C,
266 pub(crate) other: BTreeMap<String, Value>,
268}
269
270impl<C: EventType + Debug + Sized + Serialize> ToDeviceEvent<C> {
271 pub fn new(sender: OwnedUserId, content: C) -> ToDeviceEvent<C> {
273 ToDeviceEvent { sender, content, other: Default::default() }
274 }
275}
276
277impl<C> Serialize for ToDeviceEvent<C>
278where
279 C: EventType + Debug + Sized + Serialize,
280{
281 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
282 where
283 S: serde::Serializer,
284 {
285 #[derive(Serialize)]
286 struct Helper<'a, C> {
287 sender: &'a UserId,
288 content: &'a C,
289 #[serde(rename = "type")]
290 event_type: &'a str,
291 #[serde(flatten)]
292 other: &'a BTreeMap<String, Value>,
293 }
294
295 let event_type = self.content.event_type();
296
297 let helper =
298 Helper { sender: &self.sender, content: &self.content, event_type, other: &self.other };
299
300 helper.serialize(serializer)
301 }
302}
303
304impl<'de, C> Deserialize<'de> for ToDeviceEvent<C>
305where
306 C: EventType + Debug + Sized + Deserialize<'de> + Serialize,
307{
308 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
309 where
310 D: serde::Deserializer<'de>,
311 {
312 #[derive(Deserialize)]
313 struct Helper<C> {
314 sender: OwnedUserId,
315 content: C,
316 #[allow(dead_code)]
318 #[serde(rename = "type")]
319 event_type: String,
320 #[serde(flatten)]
321 other: BTreeMap<String, Value>,
322 }
323
324 let helper: Helper<C> = Helper::deserialize(deserializer)?;
325
326 if helper.event_type == helper.content.event_type() {
327 Ok(Self { sender: helper.sender, content: helper.content, other: helper.other })
328 } else {
329 Err(serde::de::Error::custom(format!(
330 "Mismatched event type, got {}, expected {}",
331 helper.event_type,
332 helper.content.event_type()
333 )))
334 }
335 }
336}
337
338impl<'de> Deserialize<'de> for ToDeviceEvents {
339 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
340 where
341 D: serde::Deserializer<'de>,
342 {
343 #[derive(Debug, Deserialize)]
344 struct Helper<'a> {
345 #[serde(rename = "type")]
346 event_type: &'a str,
347 }
348
349 let json = Box::<RawValue>::deserialize(deserializer)?;
350 let helper: Helper<'_> =
351 serde_json::from_str(json.get()).map_err(serde::de::Error::custom)?;
352
353 let json = json.get();
354
355 Ok(match helper.event_type {
356 "m.dummy" => ToDeviceEvents::Dummy(from_str(json)?),
357
358 "m.key.verification.accept" => ToDeviceEvents::KeyVerificationAccept(from_str(json)?),
359 "m.key.verification.cancel" => ToDeviceEvents::KeyVerificationCancel(from_str(json)?),
360 "m.key.verification.done" => ToDeviceEvents::KeyVerificationDone(from_str(json)?),
361 "m.key.verification.key" => ToDeviceEvents::KeyVerificationKey(from_str(json)?),
362 "m.key.verification.mac" => ToDeviceEvents::KeyVerificationMac(from_str(json)?),
363 "m.key.verification.start" => ToDeviceEvents::KeyVerificationStart(from_str(json)?),
364 "m.key.verification.ready" => ToDeviceEvents::KeyVerificationReady(from_str(json)?),
365 "m.key.verification.request" => ToDeviceEvents::KeyVerificationRequest(from_str(json)?),
366
367 "m.room.encrypted" => ToDeviceEvents::RoomEncrypted(from_str(json)?),
368 "m.room_key" => ToDeviceEvents::RoomKey(from_str(json)?),
369 "m.forwarded_room_key" => ToDeviceEvents::ForwardedRoomKey(from_str(json)?),
370 "m.room_key_request" => ToDeviceEvents::RoomKeyRequest(from_str(json)?),
371 "m.room_key.withheld" => ToDeviceEvents::RoomKeyWithheld(from_str(json)?),
372
373 "m.secret.send" => ToDeviceEvents::SecretSend(from_str(json)?),
374 "m.secret.request" => ToDeviceEvents::SecretRequest(from_str(json)?),
375
376 _ => ToDeviceEvents::Custom(from_str(json)?),
377 })
378 }
379}
380
381impl Serialize for ToDeviceEvents {
382 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
383 where
384 S: serde::Serializer,
385 {
386 match self {
387 ToDeviceEvents::Custom(e) => e.serialize(serializer),
388 ToDeviceEvents::Dummy(e) => e.serialize(serializer),
389
390 ToDeviceEvents::KeyVerificationAccept(e) => e.serialize(serializer),
391 ToDeviceEvents::KeyVerificationCancel(e) => e.serialize(serializer),
392 ToDeviceEvents::KeyVerificationKey(e) => e.serialize(serializer),
393 ToDeviceEvents::KeyVerificationMac(e) => e.serialize(serializer),
394 ToDeviceEvents::KeyVerificationDone(e) => e.serialize(serializer),
395 ToDeviceEvents::KeyVerificationStart(e) => e.serialize(serializer),
396 ToDeviceEvents::KeyVerificationReady(e) => e.serialize(serializer),
397 ToDeviceEvents::KeyVerificationRequest(e) => e.serialize(serializer),
398
399 ToDeviceEvents::RoomEncrypted(e) => e.serialize(serializer),
400 ToDeviceEvents::RoomKey(e) => e.serialize(serializer),
401 ToDeviceEvents::RoomKeyRequest(e) => e.serialize(serializer),
402 ToDeviceEvents::ForwardedRoomKey(e) => e.serialize(serializer),
403
404 ToDeviceEvents::SecretSend(e) => e.serialize(serializer),
405 ToDeviceEvents::SecretRequest(e) => e.serialize(serializer),
406 ToDeviceEvents::RoomKeyWithheld(e) => e.serialize(serializer),
407 }
408 }
409}
410
411#[cfg(test)]
412mod tests {
413 use assert_matches::assert_matches;
414 use serde_json::{json, Value};
415 use similar_asserts::assert_eq;
416
417 use super::ToDeviceEvents;
418
419 fn custom_event() -> Value {
420 json!({
421 "sender": "@alice:example.org",
422 "content": {
423 "custom_key": "custom_value",
424 },
425 "m.custom.top": "something custom in the top",
426 "type": "m.custom.event",
427 })
428 }
429
430 fn key_verification_event() -> Value {
431 json!({
432 "sender": "@alice:example.org",
433 "content": {
434 "from_device": "AliceDevice2",
435 "methods": [
436 "m.sas.v1"
437 ],
438 "timestamp": 1559598944869u64,
439 "transaction_id": "S0meUniqueAndOpaqueString"
440 },
441 "type": "m.key.verification.request"
442 })
443 }
444
445 fn dummy_event() -> Value {
446 json!({
447 "sender": "@alice:example.org",
448 "content": {},
449 "type": "m.dummy"
450 })
451 }
452
453 fn secret_request_event() -> Value {
454 json!({
455 "sender": "@alice:example.org",
456 "content": {
457 "name": "org.example.some.secret",
458 "action": "request",
459 "requesting_device_id": "ABCDEFG",
460 "request_id": "randomly_generated_id_9573"
461 },
462 "type": "m.secret.request"
463 })
464 }
465
466 fn forwarded_room_key_event() -> Value {
467 json!({
468 "sender": "@alice:example.org",
469 "content": {
470 "algorithm": "m.megolm.v1.aes-sha2",
471 "forwarding_curve25519_key_chain": [
472 "hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw"
473 ],
474 "room_id": "!Cuyf34gef24t:localhost",
475 "sender_claimed_ed25519_key": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y",
476 "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
477 "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ",
478 "session_key": "AQAAAAq2JpkMceK5f6JrZPJWwzQTn59zliuIv0F7apVLXDcZCCT\
479 3LqBjD21sULYEO5YTKdpMVhi9i6ZSZhdvZvp//tzRpDT7wpWVWI\
480 00Y3EPEjmpm/HfZ4MMAKpk+tzJVuuvfAcHBZgpnxBGzYOc/DAqa\
481 pK7Tk3t3QJ1UMSD94HfAqlb1JF5QBPwoh0fOvD8pJdanB8zxz05\
482 tKFdR73/vo2Q/zE3"
483 },
484 "type": "m.forwarded_room_key"
485 })
486 }
487
488 fn room_key_request_event() -> Value {
489 json!({
490 "sender": "@alice:example.org",
491 "content": {
492 "action": "request",
493 "body": {
494 "algorithm": "m.megolm.v1.aes-sha2",
495 "room_id": "!Cuyf34gef24t:localhost",
496 "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
497 "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ"
498 },
499 "request_id": "1495474790150.19",
500 "requesting_device_id": "RJYKSTBOIE"
501 },
502 "type": "m.room_key_request"
503 })
504 }
505
506 #[test]
507 fn deserialization() -> Result<(), serde_json::Error> {
508 macro_rules! assert_serialization_roundtrip {
509 ( $( $json:path => $to_device_events:ident ),* $(,)? ) => {
510 $(
511 let json = $json();
512 let event: ToDeviceEvents = serde_json::from_value(json.clone())?;
513
514 assert_matches!(event, ToDeviceEvents::$to_device_events(_));
515 let serialized = serde_json::to_value(event)?;
516 assert_eq!(json, serialized);
517 )*
518 }
519 }
520
521 assert_serialization_roundtrip!(
522 crate::types::events::room_key::tests::json => RoomKey,
524
525 forwarded_room_key_event => ForwardedRoomKey,
527
528 room_key_request_event => RoomKeyRequest,
530
531 crate::types::events::secret_send::tests::json => SecretSend,
533
534 secret_request_event => SecretRequest,
536
537 custom_event => Custom,
539
540 key_verification_event => KeyVerificationRequest,
542
543 dummy_event => Dummy,
545
546 crate::types::events::room::encrypted::tests::to_device_json => RoomEncrypted,
548 );
549
550 Ok(())
551 }
552
553 #[test]
554 fn zeroized_deserialization() -> Result<(), serde_json::Error> {
555 use ruma::events::AnyToDeviceEvent;
556
557 macro_rules! assert_serialization_roundtrip {
558 ( $( $json:path => $to_device_events:ident ),* $(,)? ) => {
559 $(
560 let json = $json();
561 let event: ToDeviceEvents = serde_json::from_value(json.clone())?;
562 let zeroized = event.serialize_zeroized()?;
563
564 let ruma_event: AnyToDeviceEvent = zeroized.deserialize_as()?;
565
566 assert_matches!(ruma_event, AnyToDeviceEvent::$to_device_events(_));
567 )*
568 }
569 }
570
571 assert_serialization_roundtrip!(
572 crate::types::events::room_key::tests::json => RoomKey,
574
575 forwarded_room_key_event => ForwardedRoomKey,
577
578 room_key_request_event => RoomKeyRequest,
580
581 crate::types::events::secret_send::tests::json => SecretSend,
583
584 secret_request_event => SecretRequest,
586
587 key_verification_event => KeyVerificationRequest,
589
590 dummy_event => Dummy,
592
593 crate::types::events::room::encrypted::tests::to_device_json => RoomEncrypted,
595 );
596
597 Ok(())
598 }
599}