ruma_events/
room_key_bundle.rs

1//! Types for the `m.room_key_bundle` event defined in [MSC4268].
2//!
3//! [MSC4268]: https://github.com/matrix-org/matrix-spec-proposals/pull/4268
4
5use ruma_common::OwnedRoomId;
6use ruma_macros::EventContent;
7use serde::{Deserialize, Serialize};
8
9use crate::room::EncryptedFile;
10
11/// The content of an `m.room_key_bundle` event.
12///
13/// Typically encrypted as an `m.room.encrypted` event, then sent as a to-device event.
14///
15/// This event is defined in [MSC4268](https://github.com/matrix-org/matrix-spec-proposals/pull/4268)
16#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
17#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
18#[ruma_event(type = "io.element.msc4268.room_key_bundle", alias = "m.room_key_bundle", kind = ToDevice)]
19pub struct ToDeviceRoomKeyBundleEventContent {
20    /// The room that these keys are for.
21    pub room_id: OwnedRoomId,
22
23    /// The location and encryption info of the key bundle.
24    pub file: EncryptedFile,
25}
26
27impl ToDeviceRoomKeyBundleEventContent {
28    /// Creates a new `ToDeviceRoomKeyBundleEventContent` with the given room ID, and
29    /// [`EncryptedFile`] which contains the room keys from the bundle.
30    pub fn new(room_id: OwnedRoomId, file: EncryptedFile) -> Self {
31        Self { room_id, file }
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use std::collections::BTreeMap;
38
39    use ruma_common::{owned_mxc_uri, owned_room_id, serde::Base64};
40    use serde_json::json;
41
42    use super::ToDeviceRoomKeyBundleEventContent;
43    use crate::room::{EncryptedFile, JsonWebKey};
44
45    #[test]
46    fn serialization() {
47        let content = ToDeviceRoomKeyBundleEventContent {
48            room_id: owned_room_id!("!testroomid:example.org"),
49            file: EncryptedFile {
50                url: owned_mxc_uri!("mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"),
51                key: JsonWebKey {
52                    kty: "A256CTR".to_owned(),
53                    key_ops: vec!["encrypt".to_owned(), "decrypt".to_owned()],
54                    alg: "A256CTR".to_owned(),
55                    k: Base64::parse("aWF6-32KGYaC3A_FEUCk1Bt0JA37zP0wrStgmdCaW-0").unwrap(),
56                    ext: true,
57                },
58                iv: Base64::parse("w+sE15fzSc0AAAAAAAAAAA").unwrap(),
59                hashes: BTreeMap::from([(
60                    "sha256".to_owned(),
61                    Base64::parse("fdSLu/YkRx3Wyh3KQabP3rd6+SFiKg5lsJZQHtkSAYA").unwrap(),
62                )]),
63                v: "v2".to_owned(),
64            },
65        };
66
67        let serialized = serde_json::to_value(content).unwrap();
68
69        assert_eq!(
70            serialized,
71            json!({
72                "room_id": "!testroomid:example.org",
73                "file": {
74                    "v": "v2",
75                    "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
76                    "key": {
77                        "alg": "A256CTR",
78                        "ext": true,
79                        "k": "aWF6-32KGYaC3A_FEUCk1Bt0JA37zP0wrStgmdCaW-0",
80                        "key_ops": ["encrypt","decrypt"],
81                        "kty": "A256CTR"
82                    },
83                    "iv": "w+sE15fzSc0AAAAAAAAAAA",
84                    "hashes": {
85                        "sha256": "fdSLu/YkRx3Wyh3KQabP3rd6+SFiKg5lsJZQHtkSAYA"
86                    }
87                }
88            }),
89            "The serialized value should match the declared JSON Value"
90        );
91    }
92}