matrix_sdk_crypto/types/events/
olm_v1.rs

1// Copyright 2022 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Module containing specialized event types that were decrypted using the Olm
16//! protocol
17
18use std::fmt::Debug;
19
20use ruma::{OwnedUserId, UserId};
21use serde::{Deserialize, Serialize};
22use serde_json::value::RawValue;
23use vodozemac::Ed25519PublicKey;
24
25use super::{
26    dummy::DummyEventContent,
27    forwarded_room_key::ForwardedRoomKeyContent,
28    room_key::RoomKeyContent,
29    room_key_request::{self, SupportedKeyInfo},
30    secret_send::SecretSendContent,
31    EventType,
32};
33use crate::types::{
34    deserialize_ed25519_key,
35    events::{from_str, room_key_bundle::RoomKeyBundleContent},
36    serialize_ed25519_key, DeviceKeys,
37};
38
39/// An `m.dummy` event that was decrypted using the
40/// `m.olm.v1.curve25519-aes-sha2` algorithm
41pub type DecryptedDummyEvent = DecryptedOlmV1Event<DummyEventContent>;
42
43/// An `m.room_key` event that was decrypted using the
44/// `m.olm.v1.curve25519-aes-sha2` algorithm
45pub type DecryptedRoomKeyEvent = DecryptedOlmV1Event<RoomKeyContent>;
46
47/// An `m.forwarded_room_key` event that was decrypted using the
48/// `m.olm.v1.curve25519-aes-sha2` algorithm
49pub type DecryptedForwardedRoomKeyEvent = DecryptedOlmV1Event<ForwardedRoomKeyContent>;
50
51impl DecryptedForwardedRoomKeyEvent {
52    /// Get the unique info about the room key that is contained in this
53    /// forwarded room key event.
54    ///
55    /// Returns `None` if we do not understand the algorithm that was used to
56    /// encrypt the event.
57    pub fn room_key_info(&self) -> Option<SupportedKeyInfo> {
58        match &self.content {
59            ForwardedRoomKeyContent::MegolmV1AesSha2(c) => Some(
60                room_key_request::MegolmV1AesSha2Content {
61                    room_id: c.room_id.to_owned(),
62                    sender_key: c.claimed_sender_key,
63                    session_id: c.session_id.to_owned(),
64                }
65                .into(),
66            ),
67            #[cfg(feature = "experimental-algorithms")]
68            ForwardedRoomKeyContent::MegolmV2AesSha2(c) => Some(
69                room_key_request::MegolmV2AesSha2Content {
70                    room_id: c.room_id.to_owned(),
71                    session_id: c.session_id.to_owned(),
72                }
73                .into(),
74            ),
75            ForwardedRoomKeyContent::Unknown(_) => None,
76        }
77    }
78}
79
80/// An `m.secret.send` event that was decrypted using the
81/// `m.olm.v1.curve25519-aes-sha2` algorithm
82pub type DecryptedSecretSendEvent = DecryptedOlmV1Event<SecretSendContent>;
83
84/// An `io.element.msc4268.room_key_bundle` to-device event which has
85/// been decrypted using using the `m.olm.v1.curve25519-aes-sha2` algorithm
86pub type DecryptedRoomKeyBundleEvent = DecryptedOlmV1Event<RoomKeyBundleContent>;
87
88/// An enum over the various events that were decrypted using the
89/// `m.olm.v1.curve25519-aes-sha2` algorithm.
90#[derive(Debug)]
91pub enum AnyDecryptedOlmEvent {
92    /// The `m.room_key` decrypted to-device event.
93    RoomKey(DecryptedRoomKeyEvent),
94    /// The `m.forwarded_room_key` decrypted to-device event.
95    ForwardedRoomKey(DecryptedForwardedRoomKeyEvent),
96    /// The `m.secret.send` decrypted to-device event.
97    SecretSend(DecryptedSecretSendEvent),
98    /// The `m.dummy` decrypted to-device event.
99    Dummy(DecryptedDummyEvent),
100    /// The `io.element.msc4268.room_key_bundle` decrypted to-device event.
101    RoomKeyBundle(DecryptedRoomKeyBundleEvent),
102    /// A decrypted to-device event of an unknown or custom type.
103    Custom(Box<ToDeviceCustomEvent>),
104}
105
106impl AnyDecryptedOlmEvent {
107    /// The sender of the event, as set by the sender of the event.
108    pub fn sender(&self) -> &UserId {
109        match self {
110            AnyDecryptedOlmEvent::RoomKey(e) => &e.sender,
111            AnyDecryptedOlmEvent::ForwardedRoomKey(e) => &e.sender,
112            AnyDecryptedOlmEvent::SecretSend(e) => &e.sender,
113            AnyDecryptedOlmEvent::Custom(e) => &e.sender,
114            AnyDecryptedOlmEvent::RoomKeyBundle(e) => &e.sender,
115            AnyDecryptedOlmEvent::Dummy(e) => &e.sender,
116        }
117    }
118
119    /// The intended recipient of the event, as set by the sender of the event.
120    pub fn recipient(&self) -> &UserId {
121        match self {
122            AnyDecryptedOlmEvent::RoomKey(e) => &e.recipient,
123            AnyDecryptedOlmEvent::ForwardedRoomKey(e) => &e.recipient,
124            AnyDecryptedOlmEvent::SecretSend(e) => &e.recipient,
125            AnyDecryptedOlmEvent::Custom(e) => &e.recipient,
126            AnyDecryptedOlmEvent::RoomKeyBundle(e) => &e.recipient,
127            AnyDecryptedOlmEvent::Dummy(e) => &e.recipient,
128        }
129    }
130
131    /// The sender's signing keys of the encrypted event.
132    pub fn keys(&self) -> &OlmV1Keys {
133        match self {
134            AnyDecryptedOlmEvent::RoomKey(e) => &e.keys,
135            AnyDecryptedOlmEvent::ForwardedRoomKey(e) => &e.keys,
136            AnyDecryptedOlmEvent::SecretSend(e) => &e.keys,
137            AnyDecryptedOlmEvent::Custom(e) => &e.keys,
138            AnyDecryptedOlmEvent::RoomKeyBundle(e) => &e.keys,
139            AnyDecryptedOlmEvent::Dummy(e) => &e.keys,
140        }
141    }
142
143    /// The recipient's signing keys of the encrypted event.
144    pub fn recipient_keys(&self) -> &OlmV1Keys {
145        match self {
146            AnyDecryptedOlmEvent::RoomKey(e) => &e.recipient_keys,
147            AnyDecryptedOlmEvent::ForwardedRoomKey(e) => &e.recipient_keys,
148            AnyDecryptedOlmEvent::SecretSend(e) => &e.recipient_keys,
149            AnyDecryptedOlmEvent::Custom(e) => &e.recipient_keys,
150            AnyDecryptedOlmEvent::RoomKeyBundle(e) => &e.recipient_keys,
151            AnyDecryptedOlmEvent::Dummy(e) => &e.recipient_keys,
152        }
153    }
154
155    /// The event type of the encrypted event.
156    pub fn event_type(&self) -> &str {
157        match self {
158            AnyDecryptedOlmEvent::Custom(e) => &e.event_type,
159            AnyDecryptedOlmEvent::RoomKey(e) => e.content.event_type(),
160            AnyDecryptedOlmEvent::ForwardedRoomKey(e) => e.content.event_type(),
161            AnyDecryptedOlmEvent::SecretSend(e) => e.content.event_type(),
162            AnyDecryptedOlmEvent::RoomKeyBundle(e) => e.content.event_type(),
163            AnyDecryptedOlmEvent::Dummy(e) => e.content.event_type(),
164        }
165    }
166
167    /// The sender's device keys, if supplied in the message as per MSC4147
168    pub fn sender_device_keys(&self) -> Option<&DeviceKeys> {
169        match self {
170            AnyDecryptedOlmEvent::Custom(e) => e.sender_device_keys.as_ref(),
171            AnyDecryptedOlmEvent::RoomKey(e) => e.sender_device_keys.as_ref(),
172            AnyDecryptedOlmEvent::ForwardedRoomKey(e) => e.sender_device_keys.as_ref(),
173            AnyDecryptedOlmEvent::SecretSend(e) => e.sender_device_keys.as_ref(),
174            AnyDecryptedOlmEvent::RoomKeyBundle(e) => e.sender_device_keys.as_ref(),
175            AnyDecryptedOlmEvent::Dummy(e) => e.sender_device_keys.as_ref(),
176        }
177    }
178}
179
180/// An `m.olm.v1.curve25519-aes-sha2` decrypted to-device event.
181///
182/// **Note**: This event will reserialize events lossily; unknown fields will be
183/// lost during deserialization.
184#[derive(Clone, Debug, Deserialize)]
185pub struct DecryptedOlmV1Event<C>
186where
187    C: EventType + Debug + Sized + Serialize,
188{
189    /// The sender of the event, as set by the sender of the event.
190    pub sender: OwnedUserId,
191    /// The intended recipient of the event, as set by the sender of the event.
192    pub recipient: OwnedUserId,
193    /// The sender's signing keys of the encrypted event.
194    pub keys: OlmV1Keys,
195    /// The recipient's signing keys of the encrypted event.
196    pub recipient_keys: OlmV1Keys,
197    /// The device keys if supplied as per MSC4147
198    #[serde(alias = "org.matrix.msc4147.device_keys")]
199    pub sender_device_keys: Option<DeviceKeys>,
200    /// The type of the event.
201    pub content: C,
202}
203
204impl<C: EventType + Debug + Sized + Serialize> Serialize for DecryptedOlmV1Event<C> {
205    /// A customized [`Serialize`] implementation that ensures that the
206    /// `event_type` field is present in the serialized JSON.
207    ///
208    /// The `event_type` in the [`DecryptedOlmV1Event`] is omitted because the
209    /// event type is expressed in the generic type `C`. To properly serialize
210    /// the [`DecryptedOlmV1Event`] we'll must extract the event type from `C`
211    /// and reintroduce it into the JSON field.
212    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
213    where
214        S: serde::Serializer,
215    {
216        #[derive(Serialize)]
217        struct DecryptedEventSerializationHelper<'a, C: EventType + Debug + Sized + Serialize> {
218            sender: &'a UserId,
219            recipient: &'a UserId,
220            keys: &'a OlmV1Keys,
221            recipient_keys: &'a OlmV1Keys,
222            #[serde(skip_serializing_if = "Option::is_none")]
223            sender_device_keys: Option<&'a DeviceKeys>,
224            content: &'a C,
225            #[serde(rename = "type")]
226            event_type: &'a str,
227        }
228
229        let event_type = self.content.event_type();
230
231        let DecryptedOlmV1Event {
232            sender,
233            recipient,
234            keys,
235            recipient_keys,
236            sender_device_keys,
237            content,
238        } = &self;
239
240        let event = DecryptedEventSerializationHelper {
241            sender,
242            recipient,
243            keys,
244            recipient_keys,
245            sender_device_keys: sender_device_keys.as_ref(),
246            content,
247            event_type,
248        };
249
250        event.serialize(serializer)
251    }
252}
253
254impl<C: EventType + Debug + Sized + Serialize> DecryptedOlmV1Event<C> {
255    #[cfg(test)]
256    /// Test helper to create a new [`DecryptedOlmV1Event`] with the given
257    /// content.
258    ///
259    /// This should never be done in real code as we need to deserialize
260    /// decrypted events.
261    pub fn new(
262        sender: &UserId,
263        recipient: &UserId,
264        key: Ed25519PublicKey,
265        device_keys: Option<DeviceKeys>,
266        content: C,
267    ) -> Self {
268        Self {
269            sender: sender.to_owned(),
270            recipient: recipient.to_owned(),
271            keys: OlmV1Keys { ed25519: key },
272            recipient_keys: OlmV1Keys { ed25519: key },
273            sender_device_keys: device_keys,
274            content,
275        }
276    }
277}
278
279/// A decrypted to-device event with an unknown type and content.
280#[derive(Clone, Debug, Deserialize, Serialize)]
281pub struct ToDeviceCustomEvent {
282    /// The sender of the encrypted to-device event.
283    pub sender: OwnedUserId,
284    /// The recipient of the encrypted to-device event.
285    pub recipient: OwnedUserId,
286    /// The sender's signing keys of the encrypted event.
287    pub keys: OlmV1Keys,
288    /// The recipient's signing keys of the encrypted event.
289    pub recipient_keys: OlmV1Keys,
290    /// The device keys if supplied as per MSC4147
291    #[serde(alias = "org.matrix.msc4147.device_keys")]
292    pub sender_device_keys: Option<DeviceKeys>,
293    /// The type of the event.
294    #[serde(rename = "type")]
295    pub event_type: String,
296}
297
298/// Public keys used for an m.olm.v1.curve25519-aes-sha2 event.
299#[derive(Clone, Debug, Deserialize, Serialize)]
300pub struct OlmV1Keys {
301    /// The Ed25519 public key of the `m.olm.v1.curve25519-aes-sha2` keys.
302    #[serde(
303        deserialize_with = "deserialize_ed25519_key",
304        serialize_with = "serialize_ed25519_key"
305    )]
306    pub ed25519: Ed25519PublicKey,
307}
308
309impl<'de> Deserialize<'de> for AnyDecryptedOlmEvent {
310    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
311    where
312        D: serde::Deserializer<'de>,
313    {
314        #[derive(Debug, Deserialize)]
315        struct Helper<'a> {
316            #[serde(rename = "type")]
317            event_type: &'a str,
318        }
319
320        let json = Box::<RawValue>::deserialize(deserializer)?;
321        let helper: Helper<'_> =
322            serde_json::from_str(json.get()).map_err(serde::de::Error::custom)?;
323
324        let json = json.get();
325
326        Ok(match helper.event_type {
327            "m.room_key" => AnyDecryptedOlmEvent::RoomKey(from_str(json)?),
328            "m.forwarded_room_key" => AnyDecryptedOlmEvent::ForwardedRoomKey(from_str(json)?),
329            "m.secret.send" => AnyDecryptedOlmEvent::SecretSend(from_str(json)?),
330            "m.dummy" => AnyDecryptedOlmEvent::Dummy(from_str(json)?),
331            RoomKeyBundleContent::EVENT_TYPE => {
332                AnyDecryptedOlmEvent::RoomKeyBundle(from_str(json)?)
333            }
334            _ => AnyDecryptedOlmEvent::Custom(from_str(json)?),
335        })
336    }
337}
338
339#[cfg(test)]
340mod tests {
341    use std::collections::BTreeMap;
342
343    use assert_matches::assert_matches;
344    use insta::{assert_json_snapshot, with_settings};
345    use ruma::{device_id, owned_user_id, KeyId};
346    use serde_json::{json, Value};
347    use similar_asserts::assert_eq;
348    use vodozemac::{Curve25519PublicKey, Ed25519PublicKey, Ed25519Signature};
349
350    use super::AnyDecryptedOlmEvent;
351    use crate::types::{
352        events::olm_v1::DecryptedRoomKeyEvent, DeviceKey, DeviceKeys, EventEncryptionAlgorithm,
353        Signatures,
354    };
355
356    const ED25519_KEY: &str = "aOfOnlaeMb5GW1TxkZ8pXnblkGMgAvps+lAukrdYaZk";
357
358    fn dummy_event() -> Value {
359        json!({
360            "sender": "@alice:example.org",
361            "sender_device": "DEVICEID",
362            "keys": {
363                "ed25519": ED25519_KEY,
364            },
365            "recipient": "@bob:example.org",
366            "recipient_keys": {
367                "ed25519": ED25519_KEY,
368            },
369            "content": {},
370            "type": "m.dummy"
371        })
372    }
373
374    fn room_key_event() -> Value {
375        json!({
376            "sender": "@alice:example.org",
377            "keys": {
378                "ed25519": ED25519_KEY,
379            },
380            "recipient": "@bob:example.org",
381            "recipient_keys": {
382                "ed25519": ED25519_KEY,
383            },
384            "content": {
385                "algorithm": "m.megolm.v1.aes-sha2",
386                "room_id": "!Cuyf34gef24t:localhost",
387                "session_id": "ZFD6+OmV7fVCsJ7Gap8UnORH8EnmiAkes8FAvQuCw/I",
388                "session_key": "AgAAAADNp1EbxXYOGmJtyX4AkD1bvJvAUyPkbIaKxtnGKjv\
389                                SQ3E/4mnuqdM4vsmNzpO1EeWzz1rDkUpYhYE9kP7sJhgLXi\
390                                jVv80fMPHfGc49hPdu8A+xnwD4SQiYdFmSWJOIqsxeo/fiH\
391                                tino//CDQENtcKuEt0I9s0+Kk4YSH310Szse2RQ+vjple31\
392                                QrCexmqfFJzkR/BJ5ogJHrPBQL0LgsPyglIbMTLg7qygIaY\
393                                U5Fe2QdKMH7nTZPNIRHh1RaMfHVETAUJBax88EWZBoifk80\
394                                gdHUwHSgMk77vCc2a5KHKLDA"
395            },
396            "type": "m.room_key"
397        })
398    }
399
400    fn forwarded_room_key_event() -> Value {
401        json!({
402            "sender": "@alice:example.org",
403            "sender_device": "DEVICEID",
404            "keys": {
405                "ed25519": ED25519_KEY,
406            },
407            "recipient": "@bob:example.org",
408            "recipient_keys": {
409                "ed25519": ED25519_KEY,
410            },
411            "content": {
412                "algorithm": "m.megolm.v1.aes-sha2",
413                "forwarding_curve25519_key_chain": [
414                    "hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw"
415                ],
416                "room_id": "!Cuyf34gef24t:localhost",
417                "sender_claimed_ed25519_key": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y",
418                "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
419                "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ",
420                "session_key": "AQAAAAq2JpkMceK5f6JrZPJWwzQTn59zliuIv0F7apVLXDcZCCT\
421                                3LqBjD21sULYEO5YTKdpMVhi9i6ZSZhdvZvp//tzRpDT7wpWVWI\
422                                00Y3EPEjmpm/HfZ4MMAKpk+tzJVuuvfAcHBZgpnxBGzYOc/DAqa\
423                                pK7Tk3t3QJ1UMSD94HfAqlb1JF5QBPwoh0fOvD8pJdanB8zxz05\
424                                tKFdR73/vo2Q/zE3"
425            },
426            "type": "m.forwarded_room_key"
427        })
428    }
429
430    fn secret_send_event() -> Value {
431        json!({
432            "sender": "@alice:example.org",
433            "sender_device": "DEVICEID",
434            "keys": {
435                "ed25519": ED25519_KEY,
436            },
437            "recipient": "@bob:example.org",
438            "recipient_keys": {
439                "ed25519": ED25519_KEY,
440            },
441            "content": {
442                "request_id": "randomly_generated_id_9573",
443                "secret": "ThisIsASecretDon'tTellAnyone"
444            },
445            "type": "m.secret.send"
446        })
447    }
448
449    /// Return the JSON for creating sender device keys, and the matching
450    /// `DeviceKeys` object that should be created when the JSON is
451    /// deserialized.
452    fn sender_device_keys() -> (Value, DeviceKeys) {
453        let sender_device_keys_json = json!({
454                "user_id": "@u:s.co",
455                "device_id": "DEV",
456                "algorithms": [
457                    "m.olm.v1.curve25519-aes-sha2"
458                ],
459                "keys": {
460                    "curve25519:DEV": "c29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28",
461                    "ed25519:DEV": "b29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28"
462                },
463                "signatures": {
464                    "@u:s.co": {
465                        "ed25519:DEV": "mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg",
466                        "ed25519:ssk": "mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg"
467                    }
468                }
469            }
470        );
471
472        let user_id = owned_user_id!("@u:s.co");
473        let device_id = device_id!("DEV");
474        let ssk_id = device_id!("ssk");
475
476        let ed25519_device_key_id = KeyId::from_parts(ruma::DeviceKeyAlgorithm::Ed25519, device_id);
477        let curve25519_device_key_id =
478            KeyId::from_parts(ruma::DeviceKeyAlgorithm::Curve25519, device_id);
479        let ed25519_ssk_id = KeyId::from_parts(ruma::DeviceKeyAlgorithm::Ed25519, ssk_id);
480
481        let mut keys = BTreeMap::new();
482        keys.insert(
483            ed25519_device_key_id.clone(),
484            DeviceKey::Ed25519(
485                Ed25519PublicKey::from_base64("b29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28")
486                    .unwrap(),
487            ),
488        );
489        keys.insert(
490            curve25519_device_key_id,
491            DeviceKey::Curve25519(
492                Curve25519PublicKey::from_base64("c29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28")
493                    .unwrap(),
494            ),
495        );
496
497        let mut signatures = Signatures::new();
498        signatures.add_signature(
499            user_id.clone(),
500            ed25519_device_key_id,
501            Ed25519Signature::from_base64(
502                "mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg"
503            ).unwrap()
504        );
505        signatures. add_signature(
506            user_id.clone(),
507            ed25519_ssk_id,
508            Ed25519Signature::from_base64(
509                "mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg"
510            ).unwrap()
511        );
512        let sender_device_keys = DeviceKeys::new(
513            user_id,
514            device_id.to_owned(),
515            vec![EventEncryptionAlgorithm::OlmV1Curve25519AesSha2],
516            keys,
517            signatures,
518        );
519
520        (sender_device_keys_json, sender_device_keys)
521    }
522
523    #[test]
524    fn decrypted_to_device_event_snapshot() {
525        let event_json = room_key_event();
526        let event: DecryptedRoomKeyEvent = serde_json::from_value(event_json)
527            .expect("JSON should deserialize to the right event type");
528
529        with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
530            assert_json_snapshot!(event);
531        })
532    }
533
534    #[test]
535    fn deserialization() -> Result<(), serde_json::Error> {
536        macro_rules! assert_deserialization_result {
537            ( $( $json:path => $to_device_events:ident ),* $(,)? ) => {
538                $(
539                    let json = $json();
540                    let event: AnyDecryptedOlmEvent = serde_json::from_value(json)?;
541
542                    assert_matches!(event, AnyDecryptedOlmEvent::$to_device_events(_));
543                )*
544            }
545        }
546
547        assert_deserialization_result!(
548            // `m.room_key`
549            room_key_event => RoomKey,
550
551            // `m.forwarded_room_key`
552            forwarded_room_key_event => ForwardedRoomKey,
553
554            // `m.secret.send`
555            secret_send_event => SecretSend,
556
557            // `m.dummy`
558            dummy_event => Dummy,
559        );
560
561        Ok(())
562    }
563
564    #[test]
565    fn sender_device_keys_are_deserialized_unstable() {
566        let (sender_device_keys_json, sender_device_keys) = sender_device_keys();
567
568        // Given JSON for a room key event with sender_device_keys using the unstable
569        // prefix
570        let mut event_json = room_key_event();
571        event_json
572            .as_object_mut()
573            .unwrap()
574            .insert("org.matrix.msc4147.device_keys".to_owned(), sender_device_keys_json);
575
576        // When we deserialize it
577        let event: DecryptedRoomKeyEvent = serde_json::from_value(event_json)
578            .expect("JSON should deserialize to the right event type");
579
580        // Then it contains the sender_device_keys
581        assert_eq!(event.sender_device_keys, Some(sender_device_keys));
582    }
583
584    #[test]
585    fn sender_device_keys_are_deserialized() {
586        let (sender_device_keys_json, sender_device_keys) = sender_device_keys();
587
588        // Given JSON for a room key event with sender_device_keys
589        let mut event_json = room_key_event();
590        event_json
591            .as_object_mut()
592            .unwrap()
593            .insert("sender_device_keys".to_owned(), sender_device_keys_json);
594
595        // When we deserialize it
596        let event: DecryptedRoomKeyEvent = serde_json::from_value(event_json)
597            .expect("JSON should deserialize to the right event type");
598
599        // Then it contains the sender_device_keys
600        assert_eq!(event.sender_device_keys, Some(sender_device_keys));
601
602        with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
603            assert_json_snapshot!(event);
604        });
605    }
606
607    #[test]
608    fn test_serialization_cycle() {
609        let event_json = json!({
610            "sender": "@alice:example.org",
611            "keys": {
612                "ed25519": ED25519_KEY,
613            },
614            "recipient": "@bob:example.org",
615            "recipient_keys": {
616                "ed25519": ED25519_KEY,
617            },
618            "content": {
619                "algorithm": "m.megolm.v1.aes-sha2",
620                "room_id": "!Cuyf34gef24t:localhost",
621                "org.matrix.msc3061.shared_history": true,
622                "session_id": "ZFD6+OmV7fVCsJ7Gap8UnORH8EnmiAkes8FAvQuCw/I",
623                "session_key": "AgAAAADNp1EbxXYOGmJtyX4AkD1bvJvAUyPkbIaKxtnGKjv\
624                            SQ3E/4mnuqdM4vsmNzpO1EeWzz1rDkUpYhYE9kP7sJhgLXi\
625                            jVv80fMPHfGc49hPdu8A+xnwD4SQiYdFmSWJOIqsxeo/fiH\
626                            tino//CDQENtcKuEt0I9s0+Kk4YSH310Szse2RQ+vjple31\
627                            QrCexmqfFJzkR/BJ5ogJHrPBQL0LgsPyglIbMTLg7qygIaY\
628                            U5Fe2QdKMH7nTZPNIRHh1RaMfHVETAUJBax88EWZBoifk80\
629                            gdHUwHSgMk77vCc2a5KHKLDA"
630            },
631            "type": "m.room_key"
632        });
633
634        let event: DecryptedRoomKeyEvent = serde_json::from_value(event_json.clone())
635            .expect("JSON should deserialize to the right event type");
636
637        let reserialized =
638            serde_json::to_value(event).expect("We should be able to serialize the event");
639
640        assert_eq!(
641            event_json, reserialized,
642            "The reserialized JSON should match the original value"
643        );
644    }
645}