From 6e609185847023cfb3caf85b98f03a6e3efb6e2e Mon Sep 17 00:00:00 2001 From: nexy7574 Date: Wed, 2 Jul 2025 00:41:34 +0100 Subject: [PATCH] feat: Suspend new users on registration --- conduwuit-example.toml | 11 +++++++++++ src/api/client/account.rs | 20 ++++++++++++++++++++ src/core/config/mod.rs | 11 +++++++++++ src/service/admin/mod.rs | 16 +++++++++++++++- 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/conduwuit-example.toml b/conduwuit-example.toml index 1a8be2aa..794ab870 100644 --- a/conduwuit-example.toml +++ b/conduwuit-example.toml @@ -398,6 +398,17 @@ # #allow_registration = false +# If registration is enabled, and this setting is true, new users +# registered after the first admin user will be automatically suspended +# and will require an admin to run `!admin users unsuspend `. +# +# Suspended users are still able to read messages, make profile updates, +# leave rooms, and deactivate their account, however cannot send messages, +# invites, or create/join or otherwise modify rooms. +# They are effectively read-only. +# +#suspend_on_register = false + # Enabling this setting opens registration to anyone without restrictions. # This makes your server vulnerable to abuse # diff --git a/src/api/client/account.rs b/src/api/client/account.rs index 32f2530c..32ac7bc2 100644 --- a/src/api/client/account.rs +++ b/src/api/client/account.rs @@ -2,6 +2,7 @@ use std::fmt::Write; use axum::extract::State; use axum_client_ip::InsecureClientIp; +use axum_extra::headers::UserAgent; use conduwuit::{ Err, Error, Result, debug_info, err, error, info, is_equal_to, matrix::pdu::PduBuilder, @@ -490,6 +491,25 @@ pub(crate) async fn register_route( { services.admin.make_user_admin(&user_id).await?; warn!("Granting {user_id} admin privileges as the first user"); + } else if services.config.suspend_on_register { + // This is not an admin, suspend them. + // Note that we can still do auto joins for suspended users + services + .users + .suspend_account(&user_id, &services.globals.server_user) + .await; + // And send an @room notice to the admin room, to prompt admins to review the + // new user and ideally unsuspend them if deemed appropriate. + if services.server.config.admin_room_notices { + services + .admin + .send_loud_message(RoomMessageEventContent::text_plain(format!( + "User {user_id} has been suspended as they are not the first user \ + on this server. Please review and unsuspend them if appropriate." + ))) + .await + .ok(); + } } } } diff --git a/src/core/config/mod.rs b/src/core/config/mod.rs index d4a10345..c735193b 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -513,6 +513,17 @@ pub struct Config { #[serde(default)] pub allow_registration: bool, + /// If registration is enabled, and this setting is true, new users + /// registered after the first admin user will be automatically suspended + /// and will require an admin to run `!admin users unsuspend `. + /// + /// Suspended users are still able to read messages, make profile updates, + /// leave rooms, and deactivate their account, however cannot send messages, + /// invites, or create/join or otherwise modify rooms. + /// They are effectively read-only. + #[serde(default)] + pub suspend_on_register: bool, + /// Enabling this setting opens registration to anyone without restrictions. /// This makes your server vulnerable to abuse #[serde(default)] diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index 86e12c3c..11d93cc2 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -18,7 +18,10 @@ use futures::{FutureExt, TryFutureExt}; use loole::{Receiver, Sender}; use ruma::{ OwnedEventId, OwnedRoomId, RoomId, UserId, - events::room::message::{Relation, RoomMessageEventContent}, + events::{ + Mentions, + room::message::{Relation, RoomMessageEventContent}, + }, }; use tokio::sync::RwLock; @@ -158,6 +161,17 @@ impl Service { .await } + /// Sends a message, the same as send_message() but with an @room ping to + /// notify all users in the room. + pub async fn send_loud_message( + &self, + mut message_content: RoomMessageEventContent, + ) -> Result<()> { + // Add @room ping + message_content = message_content.add_mentions(Mentions::with_room_mention()); + self.send_message(message_content).await + } + /// Posts a command to the command processor queue and returns. Processing /// will take place on the service worker's task asynchronously. Errors if /// the queue is full.