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