Skip to main content

ruma_events/room/encrypted/
unstable_state.rs

1//! Types for `m.room.encrypted` state events, as defined in [MSC4362][msc].
2//!
3//! [msc]: https://github.com/matrix-org/matrix-spec-proposals/pull/4362
4use ruma_common::room_version_rules::RedactionRules;
5use ruma_macros::EventContent;
6use serde::{Deserialize, Serialize};
7
8use crate::{
9    PossiblyRedactedStateEventContent, RedactContent, StateEventType, StaticEventContent,
10    room::encrypted::EncryptedEventScheme,
11};
12
13/// The content of an `m.room.encrypted` state event.
14#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
15#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
16#[ruma_event(type = "m.room.encrypted", kind = State, state_key_type = String, custom_possibly_redacted)]
17pub struct StateRoomEncryptedEventContent {
18    /// Algorithm-specific fields.
19    #[serde(flatten)]
20    pub scheme: EncryptedEventScheme,
21}
22
23/// The possibly redacted form of [`StateRoomEncryptedEventContent`].
24#[derive(Clone, Debug, Default, Serialize, Deserialize)]
25#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
26pub struct PossiblyRedactedStateRoomEncryptedEventContent {
27    /// Algorithm-specific fields.
28    #[serde(flatten, skip_serializing_if = "Option::is_none")]
29    pub scheme: Option<EncryptedEventScheme>,
30}
31
32impl StaticEventContent for PossiblyRedactedStateRoomEncryptedEventContent {
33    const TYPE: &'static str = StateRoomEncryptedEventContent::TYPE;
34    type IsPrefix = <StateRoomEncryptedEventContent as StaticEventContent>::IsPrefix;
35}
36
37impl PossiblyRedactedStateEventContent for PossiblyRedactedStateRoomEncryptedEventContent {
38    type StateKey = String;
39
40    fn event_type(&self) -> StateEventType {
41        StateEventType::RoomEncrypted
42    }
43}
44
45impl RedactContent for PossiblyRedactedStateRoomEncryptedEventContent {
46    type Redacted = Self;
47
48    fn redact(self, _rules: &RedactionRules) -> Self::Redacted {
49        Self { scheme: None }
50    }
51}
52
53impl From<StateRoomEncryptedEventContent> for PossiblyRedactedStateRoomEncryptedEventContent {
54    fn from(value: StateRoomEncryptedEventContent) -> Self {
55        let StateRoomEncryptedEventContent { scheme } = value;
56        Self { scheme: Some(scheme) }
57    }
58}
59
60impl From<RedactedStateRoomEncryptedEventContent>
61    for PossiblyRedactedStateRoomEncryptedEventContent
62{
63    fn from(_value: RedactedStateRoomEncryptedEventContent) -> Self {
64        Self { scheme: None }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use js_int::uint;
71    use ruma_common::canonical_json::assert_to_canonical_json_eq;
72    use serde_json::{from_value as from_json_value, json};
73    use strass::assert_let;
74
75    use crate::{
76        AnyStateEvent, StateEvent,
77        room::encrypted::{
78            EncryptedEventScheme, MegolmV1AesSha2ContentInit,
79            unstable_state::StateRoomEncryptedEventContent,
80        },
81    };
82
83    #[test]
84    fn serialize_content() {
85        let key_verification_start_content = StateRoomEncryptedEventContent {
86            scheme: EncryptedEventScheme::MegolmV1AesSha2(
87                MegolmV1AesSha2ContentInit {
88                    ciphertext: "ciphertext".into(),
89                    sender_key: "sender_key".into(),
90                    device_id: "device_id".into(),
91                    session_id: "session_id".into(),
92                }
93                .into(),
94            ),
95        };
96
97        assert_to_canonical_json_eq!(
98            key_verification_start_content,
99            json!({
100                "algorithm": "m.megolm.v1.aes-sha2",
101                "ciphertext": "ciphertext",
102                "sender_key": "sender_key",
103                "device_id": "device_id",
104                "session_id": "session_id",
105            }),
106        );
107    }
108
109    #[test]
110    #[allow(deprecated)]
111    fn deserialize_content() {
112        let json_data = json!({
113            "algorithm": "m.megolm.v1.aes-sha2",
114            "ciphertext": "ciphertext",
115            "session_id": "session_id",
116        });
117
118        let content: StateRoomEncryptedEventContent = from_json_value(json_data).unwrap();
119
120        assert_let!(EncryptedEventScheme::MegolmV1AesSha2(scheme) = content.scheme);
121        assert_eq!(scheme.ciphertext, "ciphertext");
122        assert_eq!(scheme.sender_key, None);
123        assert_eq!(scheme.device_id, None);
124        assert_eq!(scheme.session_id, "session_id");
125    }
126
127    #[test]
128    #[allow(deprecated)]
129    fn deserialize_event() {
130        let json_data = json!({
131            "type": "m.room.encrypted",
132            "event_id": "$event_id:example.com",
133            "room_id": "!roomid:example.com",
134            "sender": "@example:example.com",
135            "origin_server_ts": 1_234_567_890,
136            "state_key": "",
137            "content": {
138                "algorithm": "m.megolm.v1.aes-sha2",
139                "ciphertext": "ciphertext",
140                "session_id": "session_id",
141            }
142        });
143        let event = from_json_value::<AnyStateEvent>(json_data).unwrap();
144
145        assert_let!(AnyStateEvent::RoomEncrypted(StateEvent::Original(ev)) = event);
146
147        assert_let!(EncryptedEventScheme::MegolmV1AesSha2(scheme) = ev.content.scheme);
148        assert_eq!(scheme.ciphertext, "ciphertext");
149        assert_eq!(scheme.sender_key, None);
150        assert_eq!(scheme.device_id, None);
151        assert_eq!(scheme.session_id, "session_id");
152
153        assert_eq!(ev.sender, "@example:example.com");
154        assert_eq!(ev.room_id, "!roomid:example.com");
155        assert_eq!(ev.origin_server_ts.0, uint!(1_234_567_890));
156        assert_eq!(ev.state_key, "");
157    }
158}