1use 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 EventContent, ToDeviceEventType,
27 },
28 serde::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
237#[derive(Clone, Debug, Deserialize, Serialize)]
239pub struct ToDeviceCustomEvent {
240 pub sender: OwnedUserId,
242 pub content: BTreeMap<String, Value>,
244 #[serde(rename = "type")]
246 pub event_type: String,
247 #[serde(flatten)]
249 other: BTreeMap<String, Value>,
250}
251
252#[derive(Debug)]
254pub struct ToDeviceEvent<C>
255where
256 C: EventType + Debug + Sized + Serialize,
257{
258 pub sender: OwnedUserId,
260 pub content: C,
262 pub(crate) other: BTreeMap<String, Value>,
264}
265
266impl<C: EventType + Debug + Sized + Serialize> ToDeviceEvent<C> {
267 pub fn new(sender: OwnedUserId, content: C) -> ToDeviceEvent<C> {
269 ToDeviceEvent { sender, content, other: Default::default() }
270 }
271}
272
273impl<C> Serialize for ToDeviceEvent<C>
274where
275 C: EventType + Debug + Sized + Serialize,
276{
277 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
278 where
279 S: serde::Serializer,
280 {
281 #[derive(Serialize)]
282 struct Helper<'a, C> {
283 sender: &'a UserId,
284 content: &'a C,
285 #[serde(rename = "type")]
286 event_type: &'a str,
287 #[serde(flatten)]
288 other: &'a BTreeMap<String, Value>,
289 }
290
291 let event_type = self.content.event_type();
292
293 let helper =
294 Helper { sender: &self.sender, content: &self.content, event_type, other: &self.other };
295
296 helper.serialize(serializer)
297 }
298}
299
300impl<'de, C> Deserialize<'de> for ToDeviceEvent<C>
301where
302 C: EventType + Debug + Sized + Deserialize<'de> + Serialize,
303{
304 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
305 where
306 D: serde::Deserializer<'de>,
307 {
308 #[derive(Deserialize)]
309 struct Helper<C> {
310 sender: OwnedUserId,
311 content: C,
312 #[allow(dead_code)]
314 #[serde(rename = "type")]
315 event_type: String,
316 #[serde(flatten)]
317 other: BTreeMap<String, Value>,
318 }
319
320 let helper: Helper<C> = Helper::deserialize(deserializer)?;
321
322 if helper.event_type == helper.content.event_type() {
323 Ok(Self { sender: helper.sender, content: helper.content, other: helper.other })
324 } else {
325 Err(serde::de::Error::custom(format!(
326 "Mismatched event type, got {}, expected {}",
327 helper.event_type,
328 helper.content.event_type()
329 )))
330 }
331 }
332}
333
334impl<'de> Deserialize<'de> for ToDeviceEvents {
335 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
336 where
337 D: serde::Deserializer<'de>,
338 {
339 #[derive(Debug, Deserialize)]
340 struct Helper<'a> {
341 #[serde(rename = "type")]
342 event_type: &'a str,
343 }
344
345 let json = Box::<RawValue>::deserialize(deserializer)?;
346 let helper: Helper<'_> =
347 serde_json::from_str(json.get()).map_err(serde::de::Error::custom)?;
348
349 let json = json.get();
350
351 Ok(match helper.event_type {
352 "m.dummy" => ToDeviceEvents::Dummy(from_str(json)?),
353
354 "m.key.verification.accept" => ToDeviceEvents::KeyVerificationAccept(from_str(json)?),
355 "m.key.verification.cancel" => ToDeviceEvents::KeyVerificationCancel(from_str(json)?),
356 "m.key.verification.done" => ToDeviceEvents::KeyVerificationDone(from_str(json)?),
357 "m.key.verification.key" => ToDeviceEvents::KeyVerificationKey(from_str(json)?),
358 "m.key.verification.mac" => ToDeviceEvents::KeyVerificationMac(from_str(json)?),
359 "m.key.verification.start" => ToDeviceEvents::KeyVerificationStart(from_str(json)?),
360 "m.key.verification.ready" => ToDeviceEvents::KeyVerificationReady(from_str(json)?),
361 "m.key.verification.request" => ToDeviceEvents::KeyVerificationRequest(from_str(json)?),
362
363 "m.room.encrypted" => ToDeviceEvents::RoomEncrypted(from_str(json)?),
364 "m.room_key" => ToDeviceEvents::RoomKey(from_str(json)?),
365 "m.forwarded_room_key" => ToDeviceEvents::ForwardedRoomKey(from_str(json)?),
366 "m.room_key_request" => ToDeviceEvents::RoomKeyRequest(from_str(json)?),
367 "m.room_key.withheld" => ToDeviceEvents::RoomKeyWithheld(from_str(json)?),
368
369 "m.secret.send" => ToDeviceEvents::SecretSend(from_str(json)?),
370 "m.secret.request" => ToDeviceEvents::SecretRequest(from_str(json)?),
371
372 _ => ToDeviceEvents::Custom(from_str(json)?),
373 })
374 }
375}
376
377impl Serialize for ToDeviceEvents {
378 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
379 where
380 S: serde::Serializer,
381 {
382 match self {
383 ToDeviceEvents::Custom(e) => e.serialize(serializer),
384 ToDeviceEvents::Dummy(e) => e.serialize(serializer),
385
386 ToDeviceEvents::KeyVerificationAccept(e) => e.serialize(serializer),
387 ToDeviceEvents::KeyVerificationCancel(e) => e.serialize(serializer),
388 ToDeviceEvents::KeyVerificationKey(e) => e.serialize(serializer),
389 ToDeviceEvents::KeyVerificationMac(e) => e.serialize(serializer),
390 ToDeviceEvents::KeyVerificationDone(e) => e.serialize(serializer),
391 ToDeviceEvents::KeyVerificationStart(e) => e.serialize(serializer),
392 ToDeviceEvents::KeyVerificationReady(e) => e.serialize(serializer),
393 ToDeviceEvents::KeyVerificationRequest(e) => e.serialize(serializer),
394
395 ToDeviceEvents::RoomEncrypted(e) => e.serialize(serializer),
396 ToDeviceEvents::RoomKey(e) => e.serialize(serializer),
397 ToDeviceEvents::RoomKeyRequest(e) => e.serialize(serializer),
398 ToDeviceEvents::ForwardedRoomKey(e) => e.serialize(serializer),
399
400 ToDeviceEvents::SecretSend(e) => e.serialize(serializer),
401 ToDeviceEvents::SecretRequest(e) => e.serialize(serializer),
402 ToDeviceEvents::RoomKeyWithheld(e) => e.serialize(serializer),
403 }
404 }
405}
406
407#[cfg(test)]
408mod tests {
409 use assert_matches::assert_matches;
410 use serde_json::{json, Value};
411 use similar_asserts::assert_eq;
412
413 use super::ToDeviceEvents;
414
415 fn custom_event() -> Value {
416 json!({
417 "sender": "@alice:example.org",
418 "content": {
419 "custom_key": "custom_value",
420 },
421 "m.custom.top": "something custom in the top",
422 "type": "m.custom.event",
423 })
424 }
425
426 fn key_verification_event() -> Value {
427 json!({
428 "sender": "@alice:example.org",
429 "content": {
430 "from_device": "AliceDevice2",
431 "methods": [
432 "m.sas.v1"
433 ],
434 "timestamp": 1559598944869u64,
435 "transaction_id": "S0meUniqueAndOpaqueString"
436 },
437 "type": "m.key.verification.request"
438 })
439 }
440
441 fn dummy_event() -> Value {
442 json!({
443 "sender": "@alice:example.org",
444 "content": {},
445 "type": "m.dummy"
446 })
447 }
448
449 fn secret_request_event() -> Value {
450 json!({
451 "sender": "@alice:example.org",
452 "content": {
453 "name": "org.example.some.secret",
454 "action": "request",
455 "requesting_device_id": "ABCDEFG",
456 "request_id": "randomly_generated_id_9573"
457 },
458 "type": "m.secret.request"
459 })
460 }
461
462 fn forwarded_room_key_event() -> Value {
463 json!({
464 "sender": "@alice:example.org",
465 "content": {
466 "algorithm": "m.megolm.v1.aes-sha2",
467 "forwarding_curve25519_key_chain": [
468 "hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw"
469 ],
470 "room_id": "!Cuyf34gef24t:localhost",
471 "sender_claimed_ed25519_key": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y",
472 "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
473 "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ",
474 "session_key": "AQAAAAq2JpkMceK5f6JrZPJWwzQTn59zliuIv0F7apVLXDcZCCT\
475 3LqBjD21sULYEO5YTKdpMVhi9i6ZSZhdvZvp//tzRpDT7wpWVWI\
476 00Y3EPEjmpm/HfZ4MMAKpk+tzJVuuvfAcHBZgpnxBGzYOc/DAqa\
477 pK7Tk3t3QJ1UMSD94HfAqlb1JF5QBPwoh0fOvD8pJdanB8zxz05\
478 tKFdR73/vo2Q/zE3"
479 },
480 "type": "m.forwarded_room_key"
481 })
482 }
483
484 fn room_key_request_event() -> Value {
485 json!({
486 "sender": "@alice:example.org",
487 "content": {
488 "action": "request",
489 "body": {
490 "algorithm": "m.megolm.v1.aes-sha2",
491 "room_id": "!Cuyf34gef24t:localhost",
492 "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
493 "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ"
494 },
495 "request_id": "1495474790150.19",
496 "requesting_device_id": "RJYKSTBOIE"
497 },
498 "type": "m.room_key_request"
499 })
500 }
501
502 #[test]
503 fn deserialization() -> Result<(), serde_json::Error> {
504 macro_rules! assert_serialization_roundtrip {
505 ( $( $json:path => $to_device_events:ident ),* $(,)? ) => {
506 $(
507 let json = $json();
508 let event: ToDeviceEvents = serde_json::from_value(json.clone())?;
509
510 assert_matches!(event, ToDeviceEvents::$to_device_events(_));
511 let serialized = serde_json::to_value(event)?;
512 assert_eq!(json, serialized);
513 )*
514 }
515 }
516
517 assert_serialization_roundtrip!(
518 crate::types::events::room_key::tests::json => RoomKey,
520
521 forwarded_room_key_event => ForwardedRoomKey,
523
524 room_key_request_event => RoomKeyRequest,
526
527 crate::types::events::secret_send::tests::json => SecretSend,
529
530 secret_request_event => SecretRequest,
532
533 custom_event => Custom,
535
536 key_verification_event => KeyVerificationRequest,
538
539 dummy_event => Dummy,
541
542 crate::types::events::room::encrypted::tests::to_device_json => RoomEncrypted,
544 );
545
546 Ok(())
547 }
548
549 #[test]
550 fn zeroized_deserialization() -> Result<(), serde_json::Error> {
551 use ruma::events::AnyToDeviceEvent;
552
553 macro_rules! assert_serialization_roundtrip {
554 ( $( $json:path => $to_device_events:ident ),* $(,)? ) => {
555 $(
556 let json = $json();
557 let event: ToDeviceEvents = serde_json::from_value(json.clone())?;
558 let zeroized = event.serialize_zeroized()?;
559
560 let ruma_event: AnyToDeviceEvent = zeroized.deserialize_as()?;
561
562 assert_matches!(ruma_event, AnyToDeviceEvent::$to_device_events(_));
563 )*
564 }
565 }
566
567 assert_serialization_roundtrip!(
568 crate::types::events::room_key::tests::json => RoomKey,
570
571 forwarded_room_key_event => ForwardedRoomKey,
573
574 room_key_request_event => RoomKeyRequest,
576
577 crate::types::events::secret_send::tests::json => SecretSend,
579
580 secret_request_event => SecretRequest,
582
583 key_verification_event => KeyVerificationRequest,
585
586 dummy_event => Dummy,
588
589 crate::types::events::room::encrypted::tests::to_device_json => RoomEncrypted,
591 );
592
593 Ok(())
594 }
595}