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
This commit is contained in:
new-years-eve
2026-04-20 14:09:34 +00:00
committed by Ellis Git
parent 202786c46b
commit 834f2caffe
4 changed files with 82 additions and 3 deletions
+29 -3
View File
@@ -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<PartialPdu> = 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::<PartialPdu>()
@@ -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) =
+7
View File
@@ -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(())
}
+22
View File
@@ -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<Vec<String>>,
/// 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<Vec<String>>,
/// display: nested
#[serde(default)]
pub well_known: WellKnownConfig,