ruma_events/room/
server_acl.rs
1use ruma_common::ServerName;
6use ruma_macros::EventContent;
7use serde::{Deserialize, Serialize};
8use wildmatch::WildMatch;
9
10use crate::EmptyStateKey;
11
12#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
16#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
17#[ruma_event(type = "m.room.server_acl", kind = State, state_key_type = EmptyStateKey)]
18pub struct RoomServerAclEventContent {
19 #[serde(
25 default = "ruma_common::serde::default_true",
26 skip_serializing_if = "ruma_common::serde::is_true"
27 )]
28 pub allow_ip_literals: bool,
29
30 #[serde(default, skip_serializing_if = "Vec::is_empty")]
37 pub allow: Vec<String>,
38
39 #[serde(default, skip_serializing_if = "Vec::is_empty")]
46 pub deny: Vec<String>,
47}
48
49impl RoomServerAclEventContent {
50 pub fn new(allow_ip_literals: bool, allow: Vec<String>, deny: Vec<String>) -> Self {
53 Self { allow_ip_literals, allow, deny }
54 }
55
56 pub fn is_allowed(&self, server_name: &ServerName) -> bool {
58 if !self.allow_ip_literals && server_name.is_ip_literal() {
59 return false;
60 }
61
62 let host = server_name.host();
63
64 self.deny.iter().all(|d| !WildMatch::new(d).matches(host))
65 && self.allow.iter().any(|a| WildMatch::new(a).matches(host))
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use ruma_common::server_name;
72 use serde_json::{from_value as from_json_value, json};
73
74 use super::RoomServerAclEventContent;
75 use crate::OriginalStateEvent;
76
77 #[test]
78 fn default_values() {
79 let json_data = json!({
80 "content": {},
81 "event_id": "$h29iv0s8:example.com",
82 "origin_server_ts": 1,
83 "room_id": "!n8f893n9:example.com",
84 "sender": "@carl:example.com",
85 "state_key": "",
86 "type": "m.room.server_acl"
87 });
88
89 let server_acl_event: OriginalStateEvent<RoomServerAclEventContent> =
90 from_json_value(json_data).unwrap();
91
92 assert!(server_acl_event.content.allow_ip_literals);
93 assert_eq!(server_acl_event.content.allow.len(), 0);
94 assert_eq!(server_acl_event.content.deny.len(), 0);
95 }
96
97 #[test]
98 fn acl_ignores_port() {
99 let acl_event = RoomServerAclEventContent {
100 allow_ip_literals: true,
101 allow: vec!["*".to_owned()],
102 deny: vec!["1.1.1.1".to_owned()],
103 };
104 assert!(!acl_event.is_allowed(server_name!("1.1.1.1:8000")));
105 }
106
107 #[test]
108 fn acl_allow_ip_literal() {
109 let acl_event = RoomServerAclEventContent {
110 allow_ip_literals: true,
111 allow: vec!["*".to_owned()],
112 deny: Vec::new(),
113 };
114 assert!(acl_event.is_allowed(server_name!("1.1.1.1")));
115 }
116
117 #[test]
118 fn acl_deny_ip_literal() {
119 let acl_event = RoomServerAclEventContent {
120 allow_ip_literals: false,
121 allow: vec!["*".to_owned()],
122 deny: Vec::new(),
123 };
124 assert!(!acl_event.is_allowed(server_name!("1.1.1.1")));
125 }
126
127 #[test]
128 fn acl_deny() {
129 let acl_event = RoomServerAclEventContent {
130 allow_ip_literals: false,
131 allow: vec!["*".to_owned()],
132 deny: vec!["matrix.org".to_owned()],
133 };
134 assert!(!acl_event.is_allowed(server_name!("matrix.org")));
135 assert!(acl_event.is_allowed(server_name!("conduit.rs")));
136 }
137
138 #[test]
139 fn acl_explicit_allow() {
140 let acl_event = RoomServerAclEventContent {
141 allow_ip_literals: false,
142 allow: vec!["conduit.rs".to_owned()],
143 deny: Vec::new(),
144 };
145 assert!(!acl_event.is_allowed(server_name!("matrix.org")));
146 assert!(acl_event.is_allowed(server_name!("conduit.rs")));
147 }
148
149 #[test]
150 fn acl_explicit_glob_1() {
151 let acl_event = RoomServerAclEventContent {
152 allow_ip_literals: false,
153 allow: vec!["*.matrix.org".to_owned()],
154 deny: Vec::new(),
155 };
156 assert!(!acl_event.is_allowed(server_name!("matrix.org")));
157 assert!(acl_event.is_allowed(server_name!("server.matrix.org")));
158 }
159
160 #[test]
161 fn acl_explicit_glob_2() {
162 let acl_event = RoomServerAclEventContent {
163 allow_ip_literals: false,
164 allow: vec!["matrix??.org".to_owned()],
165 deny: Vec::new(),
166 };
167 assert!(!acl_event.is_allowed(server_name!("matrix1.org")));
168 assert!(acl_event.is_allowed(server_name!("matrix02.org")));
169 }
170
171 #[test]
172 fn acl_ipv6_glob() {
173 let acl_event = RoomServerAclEventContent {
174 allow_ip_literals: true,
175 allow: vec!["[2001:db8:1234::1]".to_owned()],
176 deny: Vec::new(),
177 };
178 assert!(!acl_event.is_allowed(server_name!("[2001:db8:1234::2]")));
179 assert!(acl_event.is_allowed(server_name!("[2001:db8:1234::1]")));
180 }
181}