tuwunel_matrix/room/state/resolution/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};
12
13use crate::Event;
14
15#[derive(Debug, Clone)]
19pub struct RoomMemberEvent<E: Event>(E);
20
21impl<E: Event> RoomMemberEvent<E> {
22 #[inline]
24 pub fn new(event: E) -> Self { Self(event) }
25
26 #[inline]
28 pub fn membership(&self) -> Result<MembershipState> {
29 RoomMemberEventContent(self.content()).membership()
30 }
31
32 #[inline]
35 pub fn join_authorised_via_users_server(&self) -> Result<Option<OwnedUserId>> {
36 RoomMemberEventContent(self.content()).join_authorised_via_users_server()
37 }
38
39 #[inline]
42 pub fn third_party_invite(&self) -> Result<Option<ThirdPartyInvite>> {
43 RoomMemberEventContent(self.content()).third_party_invite()
44 }
45}
46
47impl<E: Event> Deref for RoomMemberEvent<E> {
48 type Target = E;
49
50 #[inline]
51 fn deref(&self) -> &Self::Target { &self.0 }
52}
53
54pub(crate) trait RoomMemberEventResultExt {
56 fn membership(self) -> Result<MembershipState>;
60}
61
62impl<E: Event> RoomMemberEventResultExt for Result<RoomMemberEvent<E>> {
63 fn membership(self) -> Result<MembershipState> {
64 match self {
65 | Ok(event) => event.membership(),
66 | Err(error) if error.is_not_found() => Ok(MembershipState::Leave),
67 | Err(error) => Err(error),
68 }
69 }
70}
71
72pub struct RoomMemberEventContent<'a>(&'a RawJsonValue);
74
75impl<'a> RoomMemberEventContent<'a> {
76 #[inline]
79 #[must_use]
80 pub fn new(content: &'a RawJsonValue) -> Self { Self(content) }
81}
82
83impl RoomMemberEventContent<'_> {
84 pub fn membership(&self) -> Result<MembershipState> {
86 #[derive(Deserialize)]
87 struct RoomMemberContentMembership {
88 membership: MembershipState,
89 }
90
91 let content: RoomMemberContentMembership =
92 from_raw_json_value(self.0).map_err(|err: Error| {
93 err!(Request(InvalidParam(
94 "missing or invalid `membership` field in `m.room.member` event: {err}"
95 )))
96 })?;
97
98 Ok(content.membership)
99 }
100
101 pub fn join_authorised_via_users_server(&self) -> Result<Option<OwnedUserId>> {
104 #[derive(Deserialize)]
105 struct RoomMemberContentJoinAuthorizedViaUsersServer {
106 join_authorised_via_users_server: Option<OwnedUserId>,
107 }
108
109 let content: RoomMemberContentJoinAuthorizedViaUsersServer = from_raw_json_value(self.0)
110 .map_err(|err: Error| {
111 err!(Request(InvalidParam(
112 "invalid `join_authorised_via_users_server` field in `m.room.member` event: \
113 {err}"
114 )))
115 })?;
116
117 Ok(content.join_authorised_via_users_server)
118 }
119
120 pub fn third_party_invite(&self) -> Result<Option<ThirdPartyInvite>> {
123 #[derive(Deserialize)]
124 struct RoomMemberContentThirdPartyInvite {
125 third_party_invite: Option<ThirdPartyInvite>,
126 }
127
128 let content: RoomMemberContentThirdPartyInvite =
129 from_raw_json_value(self.0).map_err(|err: Error| {
130 err!(Request(InvalidParam(
131 "invalid `third_party_invite` field in `m.room.member` event: {err}"
132 )))
133 })?;
134
135 Ok(content.third_party_invite)
136 }
137}
138
139#[derive(Deserialize)]
141pub struct ThirdPartyInvite {
142 signed: CanonicalJsonObject,
144}
145
146impl ThirdPartyInvite {
147 pub fn token(&self) -> Result<&str> {
149 let Some(token_value) = self.signed.get("token") else {
150 return Err!(Request(InvalidParam(
151 "missing `token` field in `third_party_invite.signed` of `m.room.member` event"
152 )));
153 };
154
155 token_value.as_str().ok_or_else(|| {
156 err!(Request(InvalidParam(
157 "unexpected format of `token` field in `third_party_invite.signed` of \
158 `m.room.member` event: expected string, got {token_value:?}"
159 )))
160 })
161 }
162
163 pub fn mxid(&self) -> Result<&str> {
165 let Some(mxid_value) = self.signed.get("mxid") else {
166 return Err!(Request(InvalidParam(
167 "missing `mxid` field in `third_party_invite.signed` of `m.room.member` event"
168 )));
169 };
170
171 mxid_value.as_str().ok_or_else(|| {
172 err!(Request(InvalidParam(
173 "unexpected format of `mxid` field in `third_party_invite.signed` of \
174 `m.room.member` event: expected string, got {mxid_value:?}"
175 )))
176 })
177 }
178
179 pub fn signatures(&self) -> Result<&CanonicalJsonObject> {
181 let Some(signatures_value) = self.signed.get("signatures") else {
182 return Err!(Request(InvalidParam(
183 "missing `signatures` field in `third_party_invite.signed` of `m.room.member` \
184 event"
185 )));
186 };
187
188 signatures_value.as_object().ok_or_else(|| {
189 err!(Request(InvalidParam(
190 "unexpected format of `signatures` field in `third_party_invite.signed` of \
191 `m.room.member` event: expected object, got {signatures_value:?}"
192 )))
193 })
194 }
195
196 pub fn signed_canonical_json(&self) -> Result<String> {
198 to_canonical_json_string_for_signing(&self.signed).map_err(|error| {
199 err!(Request(InvalidParam(
200 "invalid `third_party_invite.signed` field in `m.room.member` event: {error}"
201 )))
202 })
203 }
204}