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, 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(error) if error.is_not_found() => Ok(MembershipState::Leave),
65 | Err(error) => Err(error),
66 }
67 }
68}
69
70pub struct RoomMemberEventContent<'a>(&'a RawJsonValue);
72
73impl<'a> RoomMemberEventContent<'a> {
74 #[inline]
77 #[must_use]
78 pub fn new(content: &'a RawJsonValue) -> Self { Self(content) }
79}
80
81impl RoomMemberEventContent<'_> {
82 pub fn membership(&self) -> Result<MembershipState> {
84 #[derive(Deserialize)]
85 struct RoomMemberContentMembership {
86 membership: MembershipState,
87 }
88
89 let content: RoomMemberContentMembership =
90 from_raw_json_value(self.0).map_err(|err: Error| {
91 err!(Request(InvalidParam(
92 "missing or invalid `membership` field in `m.room.member` event: {err}"
93 )))
94 })?;
95
96 Ok(content.membership)
97 }
98
99 pub fn join_authorised_via_users_server(&self) -> Result<Option<OwnedUserId>> {
102 #[derive(Deserialize)]
103 struct RoomMemberContentJoinAuthorizedViaUsersServer {
104 join_authorised_via_users_server: Option<OwnedUserId>,
105 }
106
107 let content: RoomMemberContentJoinAuthorizedViaUsersServer = from_raw_json_value(self.0)
108 .map_err(|err: Error| {
109 err!(Request(InvalidParam(
110 "invalid `join_authorised_via_users_server` field in `m.room.member` event: \
111 {err}"
112 )))
113 })?;
114
115 Ok(content.join_authorised_via_users_server)
116 }
117
118 pub fn third_party_invite(&self) -> Result<Option<ThirdPartyInvite>> {
121 #[derive(Deserialize)]
122 struct RoomMemberContentThirdPartyInvite {
123 third_party_invite: Option<ThirdPartyInvite>,
124 }
125
126 let content: RoomMemberContentThirdPartyInvite =
127 from_raw_json_value(self.0).map_err(|err: Error| {
128 err!(Request(InvalidParam(
129 "invalid `third_party_invite` field in `m.room.member` event: {err}"
130 )))
131 })?;
132
133 Ok(content.third_party_invite)
134 }
135}
136
137#[derive(Deserialize)]
139pub struct ThirdPartyInvite {
140 signed: CanonicalJsonObject,
142}
143
144impl ThirdPartyInvite {
145 pub fn token(&self) -> Result<&str> {
147 let Some(token_value) = self.signed.get("token") else {
148 return Err!(Request(InvalidParam(
149 "missing `token` field in `third_party_invite.signed` of `m.room.member` event"
150 )));
151 };
152
153 token_value.as_str().ok_or_else(|| {
154 err!(Request(InvalidParam(
155 "unexpected format of `token` field in `third_party_invite.signed` of \
156 `m.room.member` event: expected string, got {token_value:?}"
157 )))
158 })
159 }
160
161 pub fn mxid(&self) -> Result<&str> {
163 let Some(mxid_value) = self.signed.get("mxid") else {
164 return Err!(Request(InvalidParam(
165 "missing `mxid` field in `third_party_invite.signed` of `m.room.member` event"
166 )));
167 };
168
169 mxid_value.as_str().ok_or_else(|| {
170 err!(Request(InvalidParam(
171 "unexpected format of `mxid` field in `third_party_invite.signed` of \
172 `m.room.member` event: expected string, got {mxid_value:?}"
173 )))
174 })
175 }
176
177 pub fn signatures(&self) -> Result<&CanonicalJsonObject> {
179 let Some(signatures_value) = self.signed.get("signatures") else {
180 return Err!(Request(InvalidParam(
181 "missing `signatures` field in `third_party_invite.signed` of `m.room.member` \
182 event"
183 )));
184 };
185
186 signatures_value.as_object().ok_or_else(|| {
187 err!(Request(InvalidParam(
188 "unexpected format of `signatures` field in `third_party_invite.signed` of \
189 `m.room.member` event: expected object, got {signatures_value:?}"
190 )))
191 })
192 }
193
194 pub fn signed_canonical_json(&self) -> Result<String> {
196 to_canonical_json_string_for_signing(&self.signed).map_err(|error| {
197 err!(Request(InvalidParam(
198 "invalid `third_party_invite.signed` field in `m.room.member` event: {error}"
199 )))
200 })
201 }
202}