tuwunel_service/rooms/state_res/
events.rs1pub mod create;
4pub mod join_rules;
5pub mod member;
6pub mod power_levels;
7pub mod third_party_invite;
8
9use std::borrow::Cow;
10
11use ruma::events::room::member::MembershipState;
12use serde::{Deserialize, Deserializer};
13use serde_json::value::RawValue as RawJsonValue;
14use tuwunel_core::matrix::StateKey;
15
16pub use self::{
17 create::RoomCreateEvent,
18 join_rules::{JoinRule, RoomJoinRulesEvent},
19 member::{RoomMemberEvent, RoomMemberEventContent},
20 power_levels::{RoomPowerLevelsEvent, RoomPowerLevelsIntField},
21 third_party_invite::RoomThirdPartyInviteEvent,
22};
23
24pub(super) struct PowerEvent(pub(super) bool);
40
41#[derive(Deserialize)]
42struct PowerEventFields<'a> {
43 #[serde(rename = "type")]
44 kind: PowerEventType,
45 #[serde(borrow)]
46 sender: Cow<'a, str>,
47 state_key: Option<StateKey>,
48 #[serde(borrow)]
49 content: &'a RawJsonValue,
50}
51
52#[derive(Deserialize)]
53enum PowerEventType {
54 #[serde(rename = "m.room.create")]
55 Create,
56 #[serde(rename = "m.room.power_levels")]
57 PowerLevels,
58 #[serde(rename = "m.room.join_rules")]
59 JoinRules,
60 #[serde(rename = "m.room.member")]
61 Member,
62 #[serde(other)]
63 Other,
64}
65
66impl<'de> Deserialize<'de> for PowerEvent {
67 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
68 where
69 D: Deserializer<'de>,
70 {
71 let event = PowerEventFields::deserialize(deserializer)?;
72 let state_key = event.state_key.as_deref();
73 let is_power = match event.kind {
74 | PowerEventType::Other => false,
75 | PowerEventType::Create
76 | PowerEventType::PowerLevels
77 | PowerEventType::JoinRules => state_key == Some(""),
78 | PowerEventType::Member =>
79 is_power_membership(event.content) && Some(&*event.sender) != state_key,
80 };
81
82 Ok(Self(is_power))
83 }
84}
85
86fn is_power_membership(content: &RawJsonValue) -> bool {
87 RoomMemberEventContent::new(content)
88 .membership()
89 .is_ok_and(|membership| {
90 matches!(membership, MembershipState::Leave | MembershipState::Ban)
91 })
92}
93
94#[cfg(test)]
98pub(super) fn is_power_event<Pdu>(event: &Pdu) -> bool
99where
100 Pdu: tuwunel_core::matrix::Event,
101{
102 use ruma::events::TimelineEventType;
103
104 match event.event_type() {
105 | TimelineEventType::RoomPowerLevels
106 | TimelineEventType::RoomJoinRules
107 | TimelineEventType::RoomCreate => event.state_key() == Some(""),
108 | TimelineEventType::RoomMember => {
109 let content = RoomMemberEventContent::new(event.content());
110 if content.membership().is_ok_and(|membership| {
111 matches!(membership, MembershipState::Leave | MembershipState::Ban)
112 }) {
113 return Some(event.sender().as_str()) != event.state_key();
114 }
115
116 false
117 },
118 | _ => false,
119 }
120}