From 834f2caffecd1bb24bc4aeba06a12c6d5134e3f3 Mon Sep 17 00:00:00 2001 From: new-years-eve Date: Mon, 20 Apr 2026 14:09:34 +0000 Subject: [PATCH] feat: Add config option for a default ACL on room creation This allows for rooms to be created with a m.room.server_acl event by default. This event can be thought of as part of the initial_state events, although it is not provided by the client. Implements #775 --- conduwuit-example.toml | 24 ++++++++++++++++++++++++ src/api/client/room/create.rs | 32 +++++++++++++++++++++++++++++--- src/core/config/check.rs | 7 +++++++ src/core/config/mod.rs | 22 ++++++++++++++++++++++ 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/conduwuit-example.toml b/conduwuit-example.toml index 255cda3cf..bce9e6419 100644 --- a/conduwuit-example.toml +++ b/conduwuit-example.toml @@ -624,6 +624,30 @@ # #default_room_version = "12" +# A default allow value for the Access Control List when creating a room. +# +# If a list is provided, new rooms will be created with +# a m.room.server_acl event. Only servers which match one of the patterns +# in the list will be permitted to participate in the room. +# +# ACLs in existing rooms will not be updated automatically. This is not +# a substitute for moderation bots. +# +#default_room_acl_allow = + +# A default deny value for the Access Control List when creating a room. +# +# If a list is provided, new rooms will be created with +# a m.room.server_acl event. Servers which match one of the patterns +# in the list will be NOT permitted to participate in the room. +# +# This config cannot be used if the default_room_acl_allow config is used. +# +# ACLs in existing rooms will not be updated automatically. This is not +# a substitute for moderation bots. +# +#default_room_acl_deny = + # Enable OpenTelemetry OTLP tracing export. This replaces the deprecated # Jaeger exporter. Traces will be sent via OTLP to a collector (such as # Jaeger) that supports the OpenTelemetry Protocol. diff --git a/src/api/client/room/create.rs b/src/api/client/room/create.rs index f8c9702f8..c6e4180eb 100644 --- a/src/api/client/room/create.rs +++ b/src/api/client/room/create.rs @@ -24,6 +24,7 @@ use ruma::{ member::{MembershipState, RoomMemberEventContent}, name::RoomNameEventContent, power_levels::RoomPowerLevelsEventContent, + server_acl::RoomServerAclEventContent, topic::RoomTopicEventContent, }, }, @@ -477,7 +478,32 @@ pub(crate) async fn create_room_route( .boxed() .await?; - // 6. Events listed in initial_state + // 6. Initial state events provided by the homeserver + + let mut server_initial_state: Vec = Vec::new(); + + if let Some(allow_list) = services.server.config.default_room_acl_allow.clone() { + server_initial_state.push(PartialPdu::state( + String::new(), + &RoomServerAclEventContent::new(true, allow_list, vec![]), + )); + } else if let Some(deny_list) = services.server.config.default_room_acl_deny.clone() { + server_initial_state.push(PartialPdu::state( + String::new(), + &RoomServerAclEventContent::new(true, vec!["*".to_owned()], deny_list), + )); + } + + for pdu in server_initial_state { + services + .rooms + .timeline + .build_and_append_pdu(pdu, sender_user, Some(&room_id), &state_lock) + .boxed() + .await?; + } + + // 7. Events listed in initial_state for event in &body.initial_state { let mut partial_pdu = event .deserialize_as_unchecked::() @@ -505,7 +531,7 @@ pub(crate) async fn create_room_route( .await?; } - // 7. Events implied by name and topic + // 8. Events implied by name and topic if let Some(name) = &body.name { services .rooms @@ -534,7 +560,7 @@ pub(crate) async fn create_room_route( .await?; } - // 8. Events implied by invite (and TODO: invite_3pid) + // 9. Events implied by invite (and TODO: invite_3pid) drop(state_lock); for recipient_user in &invitees { if let Err(e) = diff --git a/src/core/config/check.rs b/src/core/config/check.rs index b98c46966..d2293e368 100644 --- a/src/core/config/check.rs +++ b/src/core/config/check.rs @@ -254,6 +254,13 @@ pub fn check(config: &Config) -> Result { )); } + if config.default_room_acl_allow.is_some() && config.default_room_acl_deny.is_some() { + return Err!(Config( + "default_room_acl_deny", + "Cannot provide a value for both default_room_acl_allow and default_room_acl_deny" + )); + } + Ok(()) } diff --git a/src/core/config/mod.rs b/src/core/config/mod.rs index 284e78bcc..6083e5056 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -760,6 +760,28 @@ pub struct Config { #[serde(default = "default_default_room_version")] pub default_room_version: RoomVersionId, + /// A default allow value for the Access Control List when creating a room. + /// + /// If a list is provided, new rooms will be created with + /// a m.room.server_acl event. Only servers which match one of the patterns + /// in the list will be permitted to participate in the room. + /// + /// ACLs in existing rooms will not be updated automatically. This is not + /// a substitute for moderation bots. + pub default_room_acl_allow: Option>, + + /// A default deny value for the Access Control List when creating a room. + /// + /// If a list is provided, new rooms will be created with + /// a m.room.server_acl event. Servers which match one of the patterns + /// in the list will be NOT permitted to participate in the room. + /// + /// This config cannot be used if the default_room_acl_allow config is used. + /// + /// ACLs in existing rooms will not be updated automatically. This is not + /// a substitute for moderation bots. + pub default_room_acl_deny: Option>, + /// display: nested #[serde(default)] pub well_known: WellKnownConfig,