tuwunel_service/rooms/state_res/events/
member.rs1use std::ops::Deref;
4
5use ruma::{
6 CanonicalJsonObject, OwnedUserId, events::room::member::MembershipState,
7 serde::from_raw_json_value, signatures::to_canonical_json_string_for_signing,
8};
9use serde::Deserialize;
10use serde_json::value::RawValue as RawJsonValue;
11use tuwunel_core::{Err, Error, Result, debug_error, err, matrix::Event};
12
13#[derive(Debug, Clone)]
17pub struct RoomMemberEvent<E: Event>(E);
18
19impl<E: Event> RoomMemberEvent<E> {
20 #[inline]
22 pub fn new(event: E) -> Self { Self(event) }
23
24 #[inline]
26 pub fn membership(&self) -> Result<MembershipState> {
27 RoomMemberEventContent(self.content()).membership()
28 }
29
30 #[inline]
33 pub fn join_authorised_via_users_server(&self) -> Result<Option<OwnedUserId>> {
34 RoomMemberEventContent(self.content()).join_authorised_via_users_server()
35 }
36
37 #[inline]
40 pub fn third_party_invite(&self) -> Result<Option<ThirdPartyInvite>> {
41 RoomMemberEventContent(self.content()).third_party_invite()
42 }
43}
44
45impl<E: Event> Deref for RoomMemberEvent<E> {
46 type Target = E;
47
48 #[inline]
49 fn deref(&self) -> &Self::Target { &self.0 }
50}
51
52pub(crate) trait RoomMemberEventResultExt {
54 fn membership(&self) -> Result<MembershipState>;
58}
59
60impl<E: Event> RoomMemberEventResultExt for Result<RoomMemberEvent<E>> {
61 fn membership(&self) -> Result<MembershipState> {
62 match self {
63 | Ok(event) => event.membership(),
64 | Err(e) if e.is_not_found() => Ok(MembershipState::Leave),
65 | Err(e) if cfg!(test) => panic!("membership(): unexpected: {e}"),
66 | Err(e) => {
67 debug_error!("membership(): unexpected: {e}");
68 Ok(MembershipState::Leave)
69 },
70 }
71 }
72}
73
74pub struct RoomMemberEventContent<'a>(&'a RawJsonValue);
76
77impl<'a> RoomMemberEventContent<'a> {
78 #[inline]
81 #[must_use]
82 pub fn new(content: &'a RawJsonValue) -> Self { Self(content) }
83}
84
85impl RoomMemberEventContent<'_> {
86 pub fn membership(&self) -> Result<MembershipState> {
88 #[derive(Deserialize)]
89 struct RoomMemberContentMembership {
90 membership: MembershipState,
91 }
92
93 let content: RoomMemberContentMembership =
94 from_raw_json_value(self.0).map_err(|err: Error| {
95 err!(Request(InvalidParam(
96 "missing or invalid `membership` field in `m.room.member` event: {err}"
97 )))
98 })?;
99
100 Ok(content.membership)
101 }
102
103 pub fn join_authorised_via_users_server(&self) -> Result<Option<OwnedUserId>> {
106 #[derive(Deserialize)]
107 struct RoomMemberContentJoinAuthorizedViaUsersServer {
108 join_authorised_via_users_server: Option<OwnedUserId>,
109 }
110
111 let content: RoomMemberContentJoinAuthorizedViaUsersServer = from_raw_json_value(self.0)
112 .map_err(|err: Error| {
113 err!(Request(InvalidParam(
114 "invalid `join_authorised_via_users_server` field in `m.room.member` event: \
115 {err}"
116 )))
117 })?;
118
119 Ok(content.join_authorised_via_users_server)
120 }
121
122 pub fn third_party_invite(&self) -> Result<Option<ThirdPartyInvite>> {
125 #[derive(Deserialize)]
126 struct RoomMemberContentThirdPartyInvite {
127 third_party_invite: Option<ThirdPartyInvite>,
128 }
129
130 let content: RoomMemberContentThirdPartyInvite =
131 from_raw_json_value(self.0).map_err(|err: Error| {
132 err!(Request(InvalidParam(
133 "invalid `third_party_invite` field in `m.room.member` event: {err}"
134 )))
135 })?;
136
137 Ok(content.third_party_invite)
138 }
139}
140
141#[derive(Deserialize)]
143pub struct ThirdPartyInvite {
144 signed: CanonicalJsonObject,
146}
147
148impl ThirdPartyInvite {
149 pub fn token(&self) -> Result<&str> {
151 let Some(token_value) = self.signed.get("token") else {
152 return Err!(Request(InvalidParam(
153 "missing `token` field in `third_party_invite.signed` of `m.room.member` event"
154 )));
155 };
156
157 token_value.as_str().ok_or_else(|| {
158 err!(Request(InvalidParam(
159 "unexpected format of `token` field in `third_party_invite.signed` of \
160 `m.room.member` event: expected string, got {token_value:?}"
161 )))
162 })
163 }
164
165 pub fn mxid(&self) -> Result<&str> {
167 let Some(mxid_value) = self.signed.get("mxid") else {
168 return Err!(Request(InvalidParam(
169 "missing `mxid` field in `third_party_invite.signed` of `m.room.member` event"
170 )));
171 };
172
173 mxid_value.as_str().ok_or_else(|| {
174 err!(Request(InvalidParam(
175 "unexpected format of `mxid` field in `third_party_invite.signed` of \
176 `m.room.member` event: expected string, got {mxid_value:?}"
177 )))
178 })
179 }
180
181 pub fn signatures(&self) -> Result<&CanonicalJsonObject> {
183 let Some(signatures_value) = self.signed.get("signatures") else {
184 return Err!(Request(InvalidParam(
185 "missing `signatures` field in `third_party_invite.signed` of `m.room.member` \
186 event"
187 )));
188 };
189
190 signatures_value.as_object().ok_or_else(|| {
191 err!(Request(InvalidParam(
192 "unexpected format of `signatures` field in `third_party_invite.signed` of \
193 `m.room.member` event: expected object, got {signatures_value:?}"
194 )))
195 })
196 }
197
198 pub fn signed_canonical_json(&self) -> Result<String> {
200 to_canonical_json_string_for_signing(&self.signed).map_err(|error| {
201 err!(Request(InvalidParam(
202 "invalid `third_party_invite.signed` field in `m.room.member` event: {error}"
203 )))
204 })
205 }
206}