feat: Config defined admin list

Closes !1246
This commit is contained in:
Terry 2025-12-30 22:54:10 +00:00 committed by Jade Ellis
parent 21324b748f
commit f8c1e9bcde
No known key found for this signature in database
GPG key ID: 8705A2A3EBF77BD2
6 changed files with 86 additions and 47 deletions

View file

@ -1590,6 +1590,18 @@
#
#admin_room_tag = "m.server_notice"
# A list of Matrix IDs that are qualified as server admins.
#
# Any Matrix IDs within this list are regarded as an admin
# regardless of whether they are in the admin room or not
#
#admins_list = []
# Defines whether those within the admin room are added to the
# admins_list.
#
#admins_from_room = true
# Sentry.io crash/panic reporting, performance monitoring/metrics, etc.
# This is NOT enabled by default.
#

View file

@ -461,8 +461,10 @@ pub(super) async fn force_join_list_of_local_users(
);
}
let Ok(admin_room) = self.services.admin.get_admin_room().await else {
return Err!("There is not an admin room to check for server admins.",);
let server_admins = self.services.admin.get_admins().await;
if server_admins.is_empty() {
return Err!("There are no admins set for this server.");
};
let (room_id, servers) = self
@ -482,15 +484,6 @@ pub(super) async fn force_join_list_of_local_users(
return Err!("We are not joined in this room.");
}
let server_admins: Vec<_> = self
.services
.rooms
.state_cache
.active_local_users_in_room(&admin_room)
.map(ToOwned::to_owned)
.collect()
.await;
if !self
.services
.rooms
@ -583,8 +576,10 @@ pub(super) async fn force_join_all_local_users(
);
}
let Ok(admin_room) = self.services.admin.get_admin_room().await else {
return Err!("There is not an admin room to check for server admins.",);
let server_admins = self.services.admin.get_admins().await;
if server_admins.is_empty() {
return Err!("There are no admins set for this server.");
};
let (room_id, servers) = self
@ -604,15 +599,6 @@ pub(super) async fn force_join_all_local_users(
return Err!("We are not joined in this room.");
}
let server_admins: Vec<_> = self
.services
.rooms
.state_cache
.active_local_users_in_room(&admin_room)
.map(ToOwned::to_owned)
.collect()
.await;
if !self
.services
.rooms

View file

@ -1,6 +1,5 @@
use axum::{Json, extract::State, response::IntoResponse};
use conduwuit::{Error, Result};
use futures::StreamExt;
use ruma::api::client::{
discovery::{
discover_homeserver::{self, HomeserverInfo, SlidingSyncProxyInfo},
@ -71,21 +70,18 @@ pub(crate) async fn well_known_support(
// Try to add admin users as contacts if no contacts are configured
if contacts.is_empty() {
if let Ok(admin_room) = services.admin.get_admin_room().await {
let admin_users = services.rooms.state_cache.room_members(&admin_room);
let mut stream = admin_users;
let admin_users = services.admin.get_admins().await;
while let Some(user_id) = stream.next().await {
// Skip server user
if *user_id == services.globals.server_user {
continue;
}
contacts.push(Contact {
role: role_value.clone(),
email_address: None,
matrix_id: Some(user_id.to_owned()),
});
for user_id in admin_users.iter() {
if *user_id == services.globals.server_user {
continue;
}
contacts.push(Contact {
role: role_value.clone(),
email_address: None,
matrix_id: Some(user_id.to_owned()),
});
}
}

View file

@ -1819,6 +1819,22 @@ pub struct Config {
#[serde(default = "default_admin_room_tag")]
pub admin_room_tag: String,
/// A list of Matrix IDs that are qualified as server admins.
///
/// Any Matrix IDs within this list are regarded as an admin
/// regardless of whether they are in the admin room or not
///
/// default: []
#[serde(default)]
pub admins_list: Vec<OwnedUserId>,
/// Defines whether those within the admin room are added to the
/// admins_list.
///
/// default: true
#[serde(default = "true_fn")]
pub admins_from_room: bool,
/// Sentry.io crash/panic reporting, performance monitoring/metrics, etc.
/// This is NOT enabled by default.
#[serde(default)]

View file

@ -1,6 +1,8 @@
use std::collections::BTreeMap;
use conduwuit::{Err, Result, debug_info, debug_warn, error, implement, matrix::pdu::PduBuilder};
use conduwuit::{
Err, Result, debug_info, debug_warn, error, implement, matrix::pdu::PduBuilder, warn,
};
use ruma::{
RoomId, UserId,
events::{
@ -176,6 +178,19 @@ async fn set_room_tag(&self, room_id: &RoomId, user_id: &UserId, tag: &str) -> R
pub async fn revoke_admin(&self, user_id: &UserId) -> Result {
use MembershipState::{Invite, Join, Knock, Leave};
if self
.services
.server
.config
.admins_list
.contains(&user_id.to_owned())
{
warn!(
"Revoking the admin status of {user_id} will not be persistent as they are within \
the admins_list."
)
}
let Ok(room_id) = self.get_admin_room().await else {
return Err!(error!("No admin room available or created."));
};

View file

@ -14,10 +14,10 @@ use conduwuit_core::{
Error, Event, Result, Server, debug, err, error, error::default_log, pdu::PduBuilder,
};
pub use create::create_admin_room;
use futures::{Future, FutureExt, TryFutureExt};
use futures::{Future, FutureExt, StreamExt, TryFutureExt};
use loole::{Receiver, Sender};
use ruma::{
Mxc, OwnedEventId, OwnedMxcUri, OwnedRoomId, RoomId, UInt, UserId,
Mxc, OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedUserId, RoomId, UInt, UserId,
events::{
Mentions,
room::{
@ -349,16 +349,30 @@ impl Service {
handle(services, command).await
}
/// Returns the list of admins for this server. First loads
/// the admin_list from the configuration, then adds users from
/// the admin room if applicable.
pub async fn get_admins(&self) -> Vec<OwnedUserId> {
let mut generated_admin_list: Vec<OwnedUserId> =
self.services.server.config.admins_list.clone();
if self.services.server.config.admins_from_room {
if let Ok(admin_room) = self.get_admin_room().await {
let admin_users = self.services.state_cache.room_members(&admin_room);
let mut stream = admin_users;
while let Some(user_id) = stream.next().await {
generated_admin_list.push(user_id.to_owned());
}
}
}
generated_admin_list
}
/// Checks whether a given user is an admin of this server
pub async fn user_is_admin(&self, user_id: &UserId) -> bool {
let Ok(admin_room) = self.get_admin_room().await else {
return false;
};
self.services
.state_cache
.is_joined(user_id, &admin_room)
.await
self.get_admins().await.contains(&user_id.to_owned())
}
/// Gets the room ID of the admin room