From 08d60b3d376b63462f769d4b9bd3bbfb560d501a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 17 Jan 2022 12:47:39 +0100 Subject: [PATCH] events: Add is_allowed method to RoomServerAclEventContent --- crates/ruma-events/CHANGELOG.md | 1 + crates/ruma-events/Cargo.toml | 1 + crates/ruma-events/src/room/server_acl.rs | 100 ++++++++++++++++++++++ 3 files changed, 102 insertions(+) diff --git a/crates/ruma-events/CHANGELOG.md b/crates/ruma-events/CHANGELOG.md index 95fc6e8c..4e70e72e 100644 --- a/crates/ruma-events/CHANGELOG.md +++ b/crates/ruma-events/CHANGELOG.md @@ -14,6 +14,7 @@ Breaking changes: Improvements: +* Add `is_allowed` to `RoomServerAclEventContent` * Add `room::message::MessageType::body` accessor method * Implement `Redact` for event structs (in addition to `Any` event enums) * Add `room::message::RoomMessageEventContent::{body, msgtype}` accessor methods diff --git a/crates/ruma-events/Cargo.toml b/crates/ruma-events/Cargo.toml index 3c5a1006..128d3fa2 100644 --- a/crates/ruma-events/Cargo.toml +++ b/crates/ruma-events/Cargo.toml @@ -35,6 +35,7 @@ ruma-serde = { version = "0.5.0", path = "../ruma-serde" } serde = { version = "1.0.118", features = ["derive"] } serde_json = { version = "1.0.60", features = ["raw_value"] } thiserror = "1.0.26" +wildmatch = "2.0.0" [dev-dependencies] assign = "1.1.1" diff --git a/crates/ruma-events/src/room/server_acl.rs b/crates/ruma-events/src/room/server_acl.rs index 893a4b03..90b25808 100644 --- a/crates/ruma-events/src/room/server_acl.rs +++ b/crates/ruma-events/src/room/server_acl.rs @@ -3,7 +3,9 @@ //! [`m.room.server_acl`]: https://spec.matrix.org/v1.1/client-server-api/#mroomserver_acl use ruma_events_macros::EventContent; +use ruma_identifiers::ServerName; use serde::{Deserialize, Serialize}; +use wildmatch::WildMatch; /// The content of an `m.room.server_acl` event. /// @@ -45,10 +47,23 @@ impl RoomServerAclEventContent { pub fn new(allow_ip_literals: bool, allow: Vec, deny: Vec) -> Self { Self { allow_ip_literals, allow, deny } } + + /// Returns true if and only if the server is allowed by the ACL rules. + pub fn is_allowed(&self, server_name: &ServerName) -> bool { + if !self.allow_ip_literals && server_name.is_ip_literal() { + return false; + } + + let host = server_name.host(); + + self.deny.iter().all(|d| !WildMatch::new(d).matches(host)) + && self.allow.iter().any(|a| WildMatch::new(a).matches(host)) + } } #[cfg(test)] mod tests { + use ruma_identifiers::server_name; use serde_json::{from_value as from_json_value, json}; use super::RoomServerAclEventContent; @@ -73,4 +88,89 @@ mod tests { assert!(server_acl_event.content.allow.is_empty()); assert!(server_acl_event.content.deny.is_empty()); } + + #[test] + fn acl_ignores_port() { + let acl_event = RoomServerAclEventContent { + allow_ip_literals: true, + allow: vec!["*".to_owned()], + deny: vec!["1.1.1.1".to_owned()], + }; + assert!(!acl_event.is_allowed(server_name!("1.1.1.1:8000"))); + } + + #[test] + fn acl_allow_ip_literal() { + let acl_event = RoomServerAclEventContent { + allow_ip_literals: true, + allow: vec!["*".to_owned()], + deny: Vec::new(), + }; + assert!(acl_event.is_allowed(server_name!("1.1.1.1"))); + } + + #[test] + fn acl_deny_ip_literal() { + let acl_event = RoomServerAclEventContent { + allow_ip_literals: false, + allow: vec!["*".to_owned()], + deny: Vec::new(), + }; + assert!(!acl_event.is_allowed(server_name!("1.1.1.1"))); + } + + #[test] + fn acl_deny() { + let acl_event = RoomServerAclEventContent { + allow_ip_literals: false, + allow: vec!["*".to_owned()], + deny: vec!["matrix.org".to_owned()], + }; + assert!(!acl_event.is_allowed(server_name!("matrix.org"))); + assert!(acl_event.is_allowed(server_name!("conduit.rs"))); + } + + #[test] + fn acl_explicit_allow() { + let acl_event = RoomServerAclEventContent { + allow_ip_literals: false, + allow: vec!["conduit.rs".to_owned()], + deny: Vec::new(), + }; + assert!(!acl_event.is_allowed(server_name!("matrix.org"))); + assert!(acl_event.is_allowed(server_name!("conduit.rs"))); + } + + #[test] + fn acl_explicit_glob_1() { + let acl_event = RoomServerAclEventContent { + allow_ip_literals: false, + allow: vec!["*.matrix.org".to_owned()], + deny: Vec::new(), + }; + assert!(!acl_event.is_allowed(server_name!("matrix.org"))); + assert!(acl_event.is_allowed(server_name!("server.matrix.org"))); + } + + #[test] + fn acl_explicit_glob_2() { + let acl_event = RoomServerAclEventContent { + allow_ip_literals: false, + allow: vec!["matrix??.org".to_owned()], + deny: Vec::new(), + }; + assert!(!acl_event.is_allowed(server_name!("matrix1.org"))); + assert!(acl_event.is_allowed(server_name!("matrix02.org"))); + } + + #[test] + fn acl_ipv6_glob() { + let acl_event = RoomServerAclEventContent { + allow_ip_literals: true, + allow: vec!["[2001:db8:1234::1]".to_owned()], + deny: Vec::new(), + }; + assert!(!acl_event.is_allowed(server_name!("[2001:db8:1234::2]"))); + assert!(acl_event.is_allowed(server_name!("[2001:db8:1234::1]"))); + } }