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
71    use assert_matches2::assert_matches;
72    use js_int::uint;
73    use ruma_common::canonical_json::assert_to_canonical_json_eq;
74    use serde_json::{from_value as from_json_value, json};
75
76    use crate::{
77        AnyStateEvent, StateEvent,
78        room::encrypted::{
79            EncryptedEventScheme, MegolmV1AesSha2ContentInit,
80            unstable_state::StateRoomEncryptedEventContent,
81        },
82    };
83
84    #[test]
85    fn serialize_content() {
86        let key_verification_start_content = StateRoomEncryptedEventContent {
87            scheme: EncryptedEventScheme::MegolmV1AesSha2(
88                MegolmV1AesSha2ContentInit {
89                    ciphertext: "ciphertext".into(),
90                    sender_key: "sender_key".into(),
91                    device_id: "device_id".into(),
92                    session_id: "session_id".into(),
93                }
94                .into(),
95            ),
96        };
97
98        assert_to_canonical_json_eq!(
99            key_verification_start_content,
100            json!({
101                "algorithm": "m.megolm.v1.aes-sha2",
102                "ciphertext": "ciphertext",
103                "sender_key": "sender_key",
104                "device_id": "device_id",
105                "session_id": "session_id",
106            }),
107        );
108    }
109
110    #[test]
111    #[allow(deprecated)]
112    fn deserialize_content() {
113        let json_data = json!({
114            "algorithm": "m.megolm.v1.aes-sha2",
115            "ciphertext": "ciphertext",
116            "session_id": "session_id",
117        });
118
119        let content: StateRoomEncryptedEventContent = from_json_value(json_data).unwrap();
120
121        assert_matches!(content.scheme, EncryptedEventScheme::MegolmV1AesSha2(scheme));
122        assert_eq!(scheme.ciphertext, "ciphertext");
123        assert_eq!(scheme.sender_key, None);
124        assert_eq!(scheme.device_id, None);
125        assert_eq!(scheme.session_id, "session_id");
126    }
127
128    #[test]
129    #[allow(deprecated)]
130    fn deserialize_event() {
131        let json_data = json!({
132            "type": "m.room.encrypted",
133            "event_id": "$event_id:example.com",
134            "room_id": "!roomid:example.com",
135            "sender": "@example:example.com",
136            "origin_server_ts": 1_234_567_890,
137            "state_key": "",
138            "content": {
139                "algorithm": "m.megolm.v1.aes-sha2",
140                "ciphertext": "ciphertext",
141                "session_id": "session_id",
142            }
143        });
144        let event = from_json_value::<AnyStateEvent>(json_data).unwrap();
145
146        assert_matches!(event, AnyStateEvent::RoomEncrypted(StateEvent::Original(ev)));
147
148        assert_matches!(ev.content.scheme, EncryptedEventScheme::MegolmV1AesSha2(scheme));
149        assert_eq!(scheme.ciphertext, "ciphertext");
150        assert_eq!(scheme.sender_key, None);
151        assert_eq!(scheme.device_id, None);
152        assert_eq!(scheme.session_id, "session_id");
153
154        assert_eq!(ev.sender, "@example:example.com");
155        assert_eq!(ev.room_id, "!roomid:example.com");
156        assert_eq!(ev.origin_server_ts.0, uint!(1_234_567_890));
157        assert_eq!(ev.state_key, "");
158    }
159}