Skip to main content

tuwunel_admin/room/moderation/
mod.rs

1mod ban_list_of_rooms;
2mod ban_room;
3mod list_banned_rooms;
4mod unban_room;
5
6use clap::Subcommand;
7use futures::StreamExt;
8use ruma::{OwnedRoomOrAliasId, RoomId};
9use tuwunel_core::{Result, debug, utils::ReadyExt, warn};
10use tuwunel_service::Services;
11
12use crate::admin_command_dispatch;
13
14#[admin_command_dispatch]
15#[derive(Debug, Subcommand)]
16pub(crate) enum RoomModerationCommand {
17	/// - Bans a room from local users joining and evicts all our local users
18	///   (including server
19	/// admins)
20	///   from the room. Also blocks any invites (local and remote) for the
21	///   banned room, and disables federation entirely with it.
22	BanRoom {
23		/// The room in the format of `!roomid:example.com` or a room alias in
24		/// the format of `#roomalias:example.com`
25		room: OwnedRoomOrAliasId,
26	},
27
28	/// - Bans a list of rooms (room IDs and room aliases) from a newline
29	///   delimited codeblock similar to `user deactivate-all`. Applies the same
30	///   steps as ban-room
31	BanListOfRooms,
32
33	/// - Unbans a room to allow local users to join again
34	///
35	/// The room's `m.federate` property is unaffected; it is fixed at room
36	/// creation.
37	UnbanRoom {
38		/// The room in the format of `!roomid:example.com` or a room alias in
39		/// the format of `#roomalias:example.com`
40		room: OwnedRoomOrAliasId,
41	},
42
43	/// - List of all rooms we have banned
44	ListBannedRooms {
45		#[arg(long)]
46		/// Whether to only output room IDs without supplementary room
47		/// information
48		no_details: bool,
49	},
50}
51
52async fn do_ban_room(services: &Services, room_id: &RoomId) {
53	services.metadata.ban_room(room_id);
54
55	debug!("Banned {room_id} successfully");
56
57	debug!("Making all users leave the room {room_id} and forgetting it");
58	let mut users = services
59		.state_cache
60		.room_members(room_id)
61		.ready_filter(|user| services.globals.user_is_local(user))
62		.map(ToOwned::to_owned)
63		.boxed();
64
65	while let Some(ref user_id) = users.next().await {
66		debug!(
67			"Attempting leave for user {user_id} in room {room_id} (ignoring all errors, \
68			 evicting admins too)",
69		);
70
71		let state_lock = services.state.mutex.lock(room_id).await;
72
73		if let Err(e) = services
74			.membership
75			.leave(user_id, room_id, None, false, &state_lock)
76			.await
77		{
78			warn!("Failed to leave room: {e}");
79		}
80
81		drop(state_lock);
82
83		services.state_cache.forget(room_id, user_id);
84	}
85
86	// remove any local aliases, ignore errors
87	services
88		.alias
89		.local_aliases_for_room(room_id)
90		.map(ToOwned::to_owned)
91		.for_each(async |local_alias| {
92			if let Err(e) = services.alias.remove_alias(&local_alias).await {
93				warn!("Error removing alias {local_alias} for {room_id}: {e}");
94			}
95		})
96		.await;
97
98	// unpublish from room directory, ignore errors
99	services.directory.set_not_public(room_id);
100
101	services.metadata.disable_room(room_id);
102}