ruma_federation_api/
membership.rs1use ruma_common::serde::{from_raw_json_value, Raw};
4use ruma_events::AnyStrippedStateEvent;
5use serde::{de, Deserialize, Serialize};
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_matches2::assert_matches;
71 use ruma_common::{serde::Raw, user_id};
72 use ruma_events::{room::member::MembershipState, AnyStrippedStateEvent};
73 use serde_json::{from_value as from_json_value, json};
74
75 use super::RawStrippedState;
76
77 #[test]
78 #[allow(deprecated)]
79 fn deserialize_stripped_state() {
80 let user_id = user_id!("@patrick:localhost");
81 let content = json!({
82 "membership": "join",
83 });
84
85 let stripped_event_json = json!({
87 "content": content,
88 "sender": user_id,
89 "state_key": user_id,
90 "type": "m.room.member",
91 });
92 assert_matches!(
93 from_json_value::<RawStrippedState>(stripped_event_json).unwrap(),
94 RawStrippedState::Stripped(raw_stripped_event)
95 );
96 assert_matches!(
97 raw_stripped_event.deserialize().unwrap(),
98 AnyStrippedStateEvent::RoomMember(stripped_member_event)
99 );
100 assert_eq!(stripped_member_event.sender, user_id);
101 assert_eq!(stripped_member_event.state_key, user_id);
102 assert_eq!(stripped_member_event.content.membership, MembershipState::Join);
103
104 let pdu_event_json = json!({
106 "auth_events": [
107 "$one",
108 "$two",
109 "$three"
110 ],
111 "content": content,
112 "depth": 10,
113 "hashes": {
114 "sha256": "thisisahash"
115 },
116 "origin_server_ts": 1_000_000,
117 "prev_events": [
118 "$one",
119 "$two",
120 "$three"
121 ],
122 "room_id": "!room:localhost",
123 "sender": user_id,
124 "signatures": {
125 "localhost": {
126 "ed25519:1": "thisisakey"
127 }
128 },
129 "state_key": user_id,
130 "type": "m.room.member",
131 });
132 assert_matches!(
133 from_json_value::<RawStrippedState>(pdu_event_json).unwrap(),
134 RawStrippedState::Pdu(_pdu_member_event)
135 );
136 }
137
138 #[test]
139 fn serialize_stripped_state() {
140 let user_id = user_id!("@patrick:localhost");
141 let content = json!({
142 "membership": "join",
143 });
144
145 let stripped_event_json = json!({
147 "content": content,
148 "sender": user_id,
149 "state_key": user_id,
150 "type": "m.room.member",
151 });
152 let raw_stripped_event =
153 Raw::new(&stripped_event_json).unwrap().cast_unchecked::<AnyStrippedStateEvent>();
154 let stripped_state = RawStrippedState::from(raw_stripped_event);
155
156 let stripped_event_json = serde_json::to_string(&stripped_state).unwrap();
157 assert_eq!(
158 stripped_event_json,
159 r#"{"content":{"membership":"join"},"sender":"@patrick:localhost","state_key":"@patrick:localhost","type":"m.room.member"}"#
160 );
161 }
162}