ruma_federation_api/
membership.rs1use ruma_common::serde::{Raw, from_raw_json_value};
4use ruma_events::AnyStrippedStateEvent;
5use serde::{Deserialize, Serialize, de};
6use serde_json::value::RawValue as RawJsonValue;
7
8pub mod create_invite;
9pub mod create_join_event;
10pub mod create_knock_event;
11pub mod create_leave_event;
12pub mod prepare_join_event;
13pub mod prepare_knock_event;
14pub mod prepare_leave_event;
15
16#[derive(Clone, Debug, Serialize)]
18#[serde(untagged)]
19#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
20pub enum RawStrippedState {
21 #[deprecated = "Since Matrix 1.16, stripped state events are required to be sent over federation as full PDUs.\
23 It is still possible to receive this variant for backwards compatibility."]
24 Stripped(Raw<AnyStrippedStateEvent>),
25
26 Pdu(Box<RawJsonValue>),
28}
29
30impl<'de> Deserialize<'de> for RawStrippedState {
31 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
32 where
33 D: ::serde::Deserializer<'de>,
34 {
35 #[derive(Deserialize)]
36 struct PotentialPduDeHelper {
37 auth_events: Option<de::IgnoredAny>,
38 prev_events: Option<de::IgnoredAny>,
39 signatures: Option<de::IgnoredAny>,
40 hashes: Option<de::IgnoredAny>,
41 }
42
43 let json = Box::<RawJsonValue>::deserialize(deserializer)?;
44
45 let PotentialPduDeHelper { auth_events, prev_events, signatures, hashes } =
46 from_raw_json_value(&json)?;
47
48 if auth_events.is_some()
49 && prev_events.is_some()
50 && signatures.is_some()
51 && hashes.is_some()
52 {
53 Ok(Self::Pdu(json))
54 } else {
55 #[allow(deprecated)]
56 Ok(Self::Stripped(Raw::from_json(json)))
57 }
58 }
59}
60
61impl From<Raw<AnyStrippedStateEvent>> for RawStrippedState {
62 fn from(value: Raw<AnyStrippedStateEvent>) -> Self {
63 #[allow(deprecated)]
64 Self::Stripped(value)
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use assert_matches::assert_matches;
71 use ruma_common::{serde::Raw, user_id};
72 use ruma_events::{AnyStrippedStateEvent, room::member::MembershipState};
73 use serde_json::{from_value as from_json_value, json};
74 use strass::assert_let;
75
76 use super::RawStrippedState;
77
78 #[test]
79 #[allow(deprecated)]
80 fn deserialize_stripped_state() {
81 let user_id = user_id!("@patrick:localhost");
82 let content = json!({
83 "membership": "join",
84 });
85
86 let stripped_event_json = json!({
88 "content": content,
89 "sender": user_id,
90 "state_key": user_id,
91 "type": "m.room.member",
92 });
93 assert_let!(
94 RawStrippedState::Stripped(raw_stripped_event) =
95 from_json_value::<RawStrippedState>(stripped_event_json).unwrap()
96 );
97 assert_let!(
98 AnyStrippedStateEvent::RoomMember(stripped_member_event) =
99 raw_stripped_event.deserialize().unwrap()
100 );
101 assert_eq!(stripped_member_event.sender, user_id);
102 assert_eq!(stripped_member_event.state_key, user_id);
103 assert_eq!(stripped_member_event.content.membership, MembershipState::Join);
104
105 let pdu_event_json = json!({
107 "auth_events": [
108 "$one",
109 "$two",
110 "$three"
111 ],
112 "content": content,
113 "depth": 10,
114 "hashes": {
115 "sha256": "thisisahash"
116 },
117 "origin_server_ts": 1_000_000,
118 "prev_events": [
119 "$one",
120 "$two",
121 "$three"
122 ],
123 "room_id": "!room:localhost",
124 "sender": user_id,
125 "signatures": {
126 "localhost": {
127 "ed25519:1": "thisisakey"
128 }
129 },
130 "state_key": user_id,
131 "type": "m.room.member",
132 });
133 assert_matches!(
134 from_json_value::<RawStrippedState>(pdu_event_json).unwrap(),
135 RawStrippedState::Pdu(_)
136 );
137 }
138
139 #[test]
140 fn serialize_stripped_state() {
141 let user_id = user_id!("@patrick:localhost");
142 let content = json!({
143 "membership": "join",
144 });
145
146 let stripped_event_json = json!({
148 "content": content,
149 "sender": user_id,
150 "state_key": user_id,
151 "type": "m.room.member",
152 });
153 let raw_stripped_event =
154 Raw::new(&stripped_event_json).unwrap().cast_unchecked::<AnyStrippedStateEvent>();
155 let stripped_state = RawStrippedState::from(raw_stripped_event);
156
157 let stripped_event_json = serde_json::to_string(&stripped_state).unwrap();
158 assert_eq!(
159 stripped_event_json,
160 r#"{"content":{"membership":"join"},"sender":"@patrick:localhost","state_key":"@patrick:localhost","type":"m.room.member"}"#
161 );
162 }
163}