From c9364dc07787e226c12c351929a6fc42ea09a03c Mon Sep 17 00:00:00 2001 From: strawberry Date: Sun, 18 Feb 2024 20:37:58 -0500 Subject: [PATCH] dont evict admins from room, allow admins to join banned rooms Signed-off-by: strawberry --- src/api/client_server/membership.rs | 12 ++++++-- src/service/admin/mod.rs | 44 +++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs index bb9d9a31..32ee1948 100644 --- a/src/api/client_server/membership.rs +++ b/src/api/client_server/membership.rs @@ -49,7 +49,9 @@ pub async fn join_room_by_id_route( ) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - if services().rooms.metadata.is_banned(&body.room_id)? { + if services().rooms.metadata.is_banned(&body.room_id)? + && !services().users.is_admin(sender_user)? + { return Err(Error::BadRequest( ErrorKind::Forbidden, "This room is banned on this homeserver.", @@ -97,7 +99,9 @@ pub async fn join_room_by_id_or_alias_route( let (servers, room_id) = match OwnedRoomId::try_from(body.room_id_or_alias) { Ok(room_id) => { - if services().rooms.metadata.is_banned(&room_id)? { + if services().rooms.metadata.is_banned(&room_id)? + && !services().users.is_admin(sender_user)? + { return Err(Error::BadRequest( ErrorKind::Forbidden, "This room is banned on this homeserver.", @@ -126,7 +130,9 @@ pub async fn join_room_by_id_or_alias_route( Err(room_alias) => { let response = get_alias_helper(room_alias).await?; - if services().rooms.metadata.is_banned(&response.room_id)? { + if services().rooms.metadata.is_banned(&response.room_id)? + && !services().users.is_admin(sender_user)? + { return Err(Error::BadRequest( ErrorKind::Forbidden, "This room is banned on this homeserver.", diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index 84fb80a8..f73b2498 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -166,7 +166,10 @@ enum RoomCommand { /// - List all rooms the server knows about List { page: Option }, - /// - Bans a room ID from local users joining and evicts all our local users from the room + /// - Bans a room ID from local users joining and evicts all our local users from the room. + /// + /// Server admins (users in the conduwuit admin room) will not be evicted and server admins can still join the room. + /// To evict admins too, use --force (also ignores errors) BanRoomId { #[arg(short, long)] force: bool, @@ -791,13 +794,26 @@ impl Service { AdminCommand::Rooms(command) => match command { RoomCommand::BanRoomId { force, room_id } => { // basic syntax checks on room ID - if !&room_id.to_string().starts_with('!') - || !&room_id.to_string().contains(':') - || room_id.to_string().contains(char::is_whitespace) - { + if !room_id.to_string().contains(':') { return Ok(RoomMessageEventContent::text_plain("Invalid room ID specified. Please note that this requires a full room ID e.g. `!awIh6gGInaS5wLQJwa:example.com`")); } + let admin_room_alias: Box = + format!("#admins:{}", services().globals.server_name()) + .try_into() + .expect("#admins:server_name is a valid alias name"); + let admin_room_id = services() + .rooms + .alias + .resolve_local_alias(&admin_room_alias)? + .expect("Admin room must exist"); + + if room_id.eq(&admin_room_id) { + return Ok(RoomMessageEventContent::text_plain( + "Not allowed to ban the admin room.", + )); + } + services().rooms.metadata.ban_room(&room_id, true)?; debug!("Making all users leave the room {}", &room_id); @@ -809,12 +825,20 @@ impl Service { .filter_map(|user| { user.ok().filter(|local_user| { local_user.server_name() == services().globals.server_name() + // additional wrapped check here is to avoid adding remote users + // who are in the admin room to the list of local users (would fail auth check) + && (local_user.server_name() + == services().globals.server_name() + && services() + .users + .is_admin(local_user) + .unwrap_or(true)) // since this is a force operation, assume user is an admin if somehow this fails }) }) .collect::>() { debug!( - "Attempting leave for user {} in room {} (forced, ignoring all errors)", + "Attempting leave for user {} in room {} (forced, ignoring all errors, evicting admins too)", &local_user, &room_id ); let _ = leave_room(&local_user, &room_id, None).await; @@ -827,6 +851,14 @@ impl Service { .filter_map(|user| { user.ok().filter(|local_user| { local_user.server_name() == services().globals.server_name() + // additional wrapped check here is to avoid adding remote users + // who are in the admin room to the list of local users (would fail auth check) + && (local_user.server_name() + == services().globals.server_name() + && !services() + .users + .is_admin(local_user) + .unwrap_or(false)) }) }) .collect::>()