split admin room moderation commands
prior stack frame allocated 170 KiB Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
fc1b8326e6
commit
db2c9f28b6
|
@ -2,6 +2,6 @@ array-size-threshold = 4096
|
|||
cognitive-complexity-threshold = 94 # TODO reduce me ALARA
|
||||
excessive-nesting-threshold = 11 # TODO reduce me to 4 or 5
|
||||
future-size-threshold = 7745 # TODO reduce me ALARA
|
||||
stack-size-threshold = 173577 # reduce me ALARA
|
||||
stack-size-threshold = 144000 # reduce me ALARA
|
||||
too-many-lines-threshold = 700 # TODO reduce me to <= 100
|
||||
type-complexity-threshold = 250 # reduce me to ~200
|
||||
|
|
|
@ -18,91 +18,103 @@ pub(crate) async fn process(command: RoomModerationCommand, body: Vec<&str>) ->
|
|||
force,
|
||||
room,
|
||||
disable_federation,
|
||||
} => {
|
||||
debug!("Got room alias or ID: {}", room);
|
||||
} => ban_room(body, force, room, disable_federation).await,
|
||||
RoomModerationCommand::BanListOfRooms {
|
||||
force,
|
||||
disable_federation,
|
||||
} => ban_list_of_rooms(body, force, disable_federation).await,
|
||||
RoomModerationCommand::UnbanRoom {
|
||||
room,
|
||||
enable_federation,
|
||||
} => unban_room(body, room, enable_federation).await,
|
||||
RoomModerationCommand::ListBannedRooms => list_banned_rooms(body).await,
|
||||
}
|
||||
}
|
||||
|
||||
let admin_room_alias: Box<RoomAliasId> = format!("#admins:{}", services().globals.server_name())
|
||||
.try_into()
|
||||
.expect("#admins:server_name is a valid alias name");
|
||||
async fn ban_room(
|
||||
_body: Vec<&str>, force: bool, room: Box<RoomOrAliasId>, disable_federation: bool,
|
||||
) -> Result<RoomMessageEventContent> {
|
||||
debug!("Got room alias or ID: {}", room);
|
||||
|
||||
if let Some(admin_room_id) = Service::get_admin_room().await? {
|
||||
if room.to_string().eq(&admin_room_id) || room.to_string().eq(&admin_room_alias) {
|
||||
return Ok(RoomMessageEventContent::text_plain("Not allowed to ban the admin room."));
|
||||
}
|
||||
let admin_room_alias: Box<RoomAliasId> = format!("#admins:{}", services().globals.server_name())
|
||||
.try_into()
|
||||
.expect("#admins:server_name is a valid alias name");
|
||||
|
||||
if let Some(admin_room_id) = Service::get_admin_room().await? {
|
||||
if room.to_string().eq(&admin_room_id) || room.to_string().eq(&admin_room_alias) {
|
||||
return Ok(RoomMessageEventContent::text_plain("Not allowed to ban the admin room."));
|
||||
}
|
||||
}
|
||||
|
||||
let room_id = if room.is_room_id() {
|
||||
let room_id = match RoomId::parse(&room) {
|
||||
Ok(room_id) => room_id,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to parse room ID {room}. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
|
||||
)))
|
||||
},
|
||||
};
|
||||
|
||||
debug!("Room specified is a room ID, banning room ID");
|
||||
|
||||
services().rooms.metadata.ban_room(&room_id, true)?;
|
||||
|
||||
room_id
|
||||
} else if room.is_room_alias_id() {
|
||||
let room_alias = match RoomAliasId::parse(&room) {
|
||||
Ok(room_alias) => room_alias,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to parse room ID {room}. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
|
||||
)))
|
||||
},
|
||||
};
|
||||
|
||||
debug!(
|
||||
"Room specified is not a room ID, attempting to resolve room alias to a room ID locally, if not using \
|
||||
get_alias_helper to fetch room ID remotely"
|
||||
);
|
||||
|
||||
let room_id = if let Some(room_id) = services().rooms.alias.resolve_local_alias(&room_alias)? {
|
||||
room_id
|
||||
} else {
|
||||
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
|
||||
|
||||
match get_alias_helper(room_alias, None).await {
|
||||
Ok(response) => {
|
||||
debug!("Got federation response fetching room ID for room {room}: {:?}", response);
|
||||
response.room_id
|
||||
},
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to resolve room alias {room} to a room ID: {e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
let room_id = if room.is_room_id() {
|
||||
let room_id = match RoomId::parse(&room) {
|
||||
Ok(room_id) => room_id,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to parse room ID {room}. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
|
||||
)))
|
||||
},
|
||||
};
|
||||
services().rooms.metadata.ban_room(&room_id, true)?;
|
||||
|
||||
debug!("Room specified is a room ID, banning room ID");
|
||||
room_id
|
||||
} else {
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
"Room specified is not a room ID or room alias. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`)",
|
||||
));
|
||||
};
|
||||
|
||||
services().rooms.metadata.ban_room(&room_id, true)?;
|
||||
|
||||
room_id
|
||||
} else if room.is_room_alias_id() {
|
||||
let room_alias = match RoomAliasId::parse(&room) {
|
||||
Ok(room_alias) => room_alias,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to parse room ID {room}. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
|
||||
)))
|
||||
},
|
||||
};
|
||||
|
||||
debug!(
|
||||
"Room specified is not a room ID, attempting to resolve room alias to a room ID locally, if not \
|
||||
using get_alias_helper to fetch room ID remotely"
|
||||
);
|
||||
|
||||
let room_id = if let Some(room_id) = services().rooms.alias.resolve_local_alias(&room_alias)? {
|
||||
room_id
|
||||
} else {
|
||||
debug!(
|
||||
"We don't have this room alias to a room ID locally, attempting to fetch room ID over \
|
||||
federation"
|
||||
);
|
||||
|
||||
match get_alias_helper(room_alias, None).await {
|
||||
Ok(response) => {
|
||||
debug!("Got federation response fetching room ID for room {room}: {:?}", response);
|
||||
response.room_id
|
||||
},
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to resolve room alias {room} to a room ID: {e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
services().rooms.metadata.ban_room(&room_id, true)?;
|
||||
|
||||
room_id
|
||||
} else {
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
"Room specified is not a room ID or room alias. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`)",
|
||||
));
|
||||
};
|
||||
|
||||
debug!("Making all users leave the room {}", &room);
|
||||
if force {
|
||||
for local_user in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.filter_map(|user| {
|
||||
user.ok().filter(|local_user| {
|
||||
user_is_local(local_user)
|
||||
debug!("Making all users leave the room {}", &room);
|
||||
if force {
|
||||
for local_user in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.filter_map(|user| {
|
||||
user.ok().filter(|local_user| {
|
||||
user_is_local(local_user)
|
||||
// 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)
|
||||
&& (user_is_local(local_user)
|
||||
|
@ -110,18 +122,221 @@ pub(crate) async fn process(command: RoomModerationCommand, body: Vec<&str>) ->
|
|||
.users
|
||||
.is_admin(local_user)
|
||||
.unwrap_or(true)) // since this is a force
|
||||
// operation, assume user
|
||||
// is an admin if somehow
|
||||
// this fails
|
||||
// operation, assume user
|
||||
// is an admin if somehow
|
||||
// this fails
|
||||
})
|
||||
})
|
||||
.collect::<Vec<OwnedUserId>>()
|
||||
{
|
||||
debug!(
|
||||
"Attempting leave for user {} in room {} (forced, ignoring all errors, evicting admins too)",
|
||||
&local_user, &room_id
|
||||
);
|
||||
|
||||
if let Err(e) = leave_room(&local_user, &room_id, None).await {
|
||||
warn!(%e, "Failed to leave room");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for local_user in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.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::<Vec<OwnedUserId>>()
|
||||
{
|
||||
debug!("Attempting leave for user {} in room {}", &local_user, &room_id);
|
||||
if let Err(e) = leave_room(&local_user, &room_id, None).await {
|
||||
error!(
|
||||
"Error attempting to make local user {} leave room {} during room banning: {}",
|
||||
&local_user, &room_id, e
|
||||
);
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Error attempting to make local user {} leave room {} during room banning (room is still banned \
|
||||
but not removing any more users): {}\nIf you would like to ignore errors, use --force",
|
||||
&local_user, &room_id, e
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if disable_federation {
|
||||
services().rooms.metadata.disable_room(&room_id, true)?;
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
"Room banned, removed all our local users, and disabled incoming federation with room.",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain(
|
||||
"Room banned and removed all our local users, use `!admin federation disable-room` to stop receiving new \
|
||||
inbound federation events as well if needed.",
|
||||
))
|
||||
}
|
||||
|
||||
async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: bool) -> Result<RoomMessageEventContent> {
|
||||
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" {
|
||||
let rooms_s = body.clone().drain(1..body.len() - 1).collect::<Vec<_>>();
|
||||
|
||||
let admin_room_alias: Box<RoomAliasId> = format!("#admins:{}", services().globals.server_name())
|
||||
.try_into()
|
||||
.expect("#admins:server_name is a valid alias name");
|
||||
|
||||
let mut room_ban_count: usize = 0;
|
||||
let mut room_ids: Vec<OwnedRoomId> = Vec::new();
|
||||
|
||||
for &room in &rooms_s {
|
||||
match <&RoomOrAliasId>::try_from(room) {
|
||||
Ok(room_alias_or_id) => {
|
||||
if let Some(admin_room_id) = Service::get_admin_room().await? {
|
||||
if room.to_owned().eq(&admin_room_id) || room.to_owned().eq(&admin_room_alias) {
|
||||
info!("User specified admin room in bulk ban list, ignoring");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if room_alias_or_id.is_room_id() {
|
||||
let room_id = match RoomId::parse(room_alias_or_id) {
|
||||
Ok(room_id) => room_id,
|
||||
Err(e) => {
|
||||
if force {
|
||||
// ignore rooms we failed to parse if we're force banning
|
||||
warn!(
|
||||
"Error parsing room \"{room}\" during bulk room banning, ignoring error and \
|
||||
logging here: {e}"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"{room} is not a valid room ID or room alias, please fix the list and try again: \
|
||||
{e}"
|
||||
)));
|
||||
},
|
||||
};
|
||||
|
||||
room_ids.push(room_id);
|
||||
}
|
||||
|
||||
if room_alias_or_id.is_room_alias_id() {
|
||||
match RoomAliasId::parse(room_alias_or_id) {
|
||||
Ok(room_alias) => {
|
||||
let room_id =
|
||||
if let Some(room_id) = services().rooms.alias.resolve_local_alias(&room_alias)? {
|
||||
room_id
|
||||
} else {
|
||||
debug!(
|
||||
"We don't have this room alias to a room ID locally, attempting to fetch \
|
||||
room ID over federation"
|
||||
);
|
||||
|
||||
match get_alias_helper(room_alias, None).await {
|
||||
Ok(response) => {
|
||||
debug!(
|
||||
"Got federation response fetching room ID for room {room}: {:?}",
|
||||
response
|
||||
);
|
||||
response.room_id
|
||||
},
|
||||
Err(e) => {
|
||||
// don't fail if force blocking
|
||||
if force {
|
||||
warn!("Failed to resolve room alias {room} to a room ID: {e}");
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to resolve room alias {room} to a room ID: {e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
room_ids.push(room_id);
|
||||
},
|
||||
Err(e) => {
|
||||
if force {
|
||||
// ignore rooms we failed to parse if we're force deleting
|
||||
error!(
|
||||
"Error parsing room \"{room}\" during bulk room banning, ignoring error and \
|
||||
logging here: {e}"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"{room} is not a valid room ID or room alias, please fix the list and try again: \
|
||||
{e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
if force {
|
||||
// ignore rooms we failed to parse if we're force deleting
|
||||
error!(
|
||||
"Error parsing room \"{room}\" during bulk room banning, ignoring error and logging here: \
|
||||
{e}"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"{room} is not a valid room ID or room alias, please fix the list and try again: {e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
for room_id in room_ids {
|
||||
if services().rooms.metadata.ban_room(&room_id, true).is_ok() {
|
||||
debug!("Banned {room_id} successfully");
|
||||
room_ban_count = room_ban_count.saturating_add(1);
|
||||
}
|
||||
|
||||
debug!("Making all users leave the room {}", &room_id);
|
||||
if force {
|
||||
for local_user in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.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::<Vec<OwnedUserId>>()
|
||||
{
|
||||
debug!(
|
||||
"Attempting leave for user {} in room {} (forced, ignoring all errors, evicting admins too)",
|
||||
&local_user, &room_id
|
||||
&local_user, room_id
|
||||
);
|
||||
|
||||
if let Err(e) = leave_room(&local_user, &room_id, None).await {
|
||||
warn!(%e, "Failed to leave room");
|
||||
}
|
||||
|
@ -134,215 +349,6 @@ pub(crate) async fn process(command: RoomModerationCommand, body: Vec<&str>) ->
|
|||
.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::<Vec<OwnedUserId>>()
|
||||
{
|
||||
debug!("Attempting leave for user {} in room {}", &local_user, &room_id);
|
||||
if let Err(e) = leave_room(&local_user, &room_id, None).await {
|
||||
error!(
|
||||
"Error attempting to make local user {} leave room {} during room banning: {}",
|
||||
&local_user, &room_id, e
|
||||
);
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Error attempting to make local user {} leave room {} during room banning (room is still \
|
||||
banned but not removing any more users): {}\nIf you would like to ignore errors, use \
|
||||
--force",
|
||||
&local_user, &room_id, e
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if disable_federation {
|
||||
services().rooms.metadata.disable_room(&room_id, true)?;
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
"Room banned, removed all our local users, and disabled incoming federation with room.",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain(
|
||||
"Room banned and removed all our local users, use `!admin federation disable-room` to stop receiving \
|
||||
new inbound federation events as well if needed.",
|
||||
))
|
||||
},
|
||||
RoomModerationCommand::BanListOfRooms {
|
||||
force,
|
||||
disable_federation,
|
||||
} => {
|
||||
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```" {
|
||||
let rooms_s = body.clone().drain(1..body.len() - 1).collect::<Vec<_>>();
|
||||
|
||||
let admin_room_alias: Box<RoomAliasId> = format!("#admins:{}", services().globals.server_name())
|
||||
.try_into()
|
||||
.expect("#admins:server_name is a valid alias name");
|
||||
|
||||
let mut room_ban_count: usize = 0;
|
||||
let mut room_ids: Vec<OwnedRoomId> = Vec::new();
|
||||
|
||||
for &room in &rooms_s {
|
||||
match <&RoomOrAliasId>::try_from(room) {
|
||||
Ok(room_alias_or_id) => {
|
||||
if let Some(admin_room_id) = Service::get_admin_room().await? {
|
||||
if room.to_owned().eq(&admin_room_id) || room.to_owned().eq(&admin_room_alias) {
|
||||
info!("User specified admin room in bulk ban list, ignoring");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if room_alias_or_id.is_room_id() {
|
||||
let room_id = match RoomId::parse(room_alias_or_id) {
|
||||
Ok(room_id) => room_id,
|
||||
Err(e) => {
|
||||
if force {
|
||||
// ignore rooms we failed to parse if we're force banning
|
||||
warn!(
|
||||
"Error parsing room \"{room}\" during bulk room banning, ignoring \
|
||||
error and logging here: {e}"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"{room} is not a valid room ID or room alias, please fix the list and try \
|
||||
again: {e}"
|
||||
)));
|
||||
},
|
||||
};
|
||||
|
||||
room_ids.push(room_id);
|
||||
}
|
||||
|
||||
if room_alias_or_id.is_room_alias_id() {
|
||||
match RoomAliasId::parse(room_alias_or_id) {
|
||||
Ok(room_alias) => {
|
||||
let room_id = if let Some(room_id) =
|
||||
services().rooms.alias.resolve_local_alias(&room_alias)?
|
||||
{
|
||||
room_id
|
||||
} else {
|
||||
debug!(
|
||||
"We don't have this room alias to a room ID locally, attempting to \
|
||||
fetch room ID over federation"
|
||||
);
|
||||
|
||||
match get_alias_helper(room_alias, None).await {
|
||||
Ok(response) => {
|
||||
debug!(
|
||||
"Got federation response fetching room ID for room {room}: \
|
||||
{:?}",
|
||||
response
|
||||
);
|
||||
response.room_id
|
||||
},
|
||||
Err(e) => {
|
||||
// don't fail if force blocking
|
||||
if force {
|
||||
warn!("Failed to resolve room alias {room} to a room ID: {e}");
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to resolve room alias {room} to a room ID: {e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
room_ids.push(room_id);
|
||||
},
|
||||
Err(e) => {
|
||||
if force {
|
||||
// ignore rooms we failed to parse if we're force deleting
|
||||
error!(
|
||||
"Error parsing room \"{room}\" during bulk room banning, ignoring \
|
||||
error and logging here: {e}"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"{room} is not a valid room ID or room alias, please fix the list and try \
|
||||
again: {e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
if force {
|
||||
// ignore rooms we failed to parse if we're force deleting
|
||||
error!(
|
||||
"Error parsing room \"{room}\" during bulk room banning, ignoring error and \
|
||||
logging here: {e}"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"{room} is not a valid room ID or room alias, please fix the list and try again: {e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
for room_id in room_ids {
|
||||
if services().rooms.metadata.ban_room(&room_id, true).is_ok() {
|
||||
debug!("Banned {room_id} successfully");
|
||||
room_ban_count = room_ban_count.saturating_add(1);
|
||||
}
|
||||
|
||||
debug!("Making all users leave the room {}", &room_id);
|
||||
if force {
|
||||
for local_user in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.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::<Vec<OwnedUserId>>()
|
||||
{
|
||||
debug!(
|
||||
"Attempting leave for user {} in room {} (forced, ignoring all errors, evicting \
|
||||
admins too)",
|
||||
&local_user, room_id
|
||||
);
|
||||
if let Err(e) = leave_room(&local_user, &room_id, None).await {
|
||||
warn!(%e, "Failed to leave room");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for local_user in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.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()
|
||||
|
@ -351,154 +357,150 @@ pub(crate) async fn process(command: RoomModerationCommand, body: Vec<&str>) ->
|
|||
.users
|
||||
.is_admin(local_user)
|
||||
.unwrap_or(false))
|
||||
})
|
||||
})
|
||||
.collect::<Vec<OwnedUserId>>()
|
||||
{
|
||||
debug!("Attempting leave for user {} in room {}", &local_user, &room_id);
|
||||
if let Err(e) = leave_room(&local_user, &room_id, None).await {
|
||||
error!(
|
||||
"Error attempting to make local user {} leave room {} during bulk room banning: {}",
|
||||
&local_user, &room_id, e
|
||||
);
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Error attempting to make local user {} leave room {} during room banning (room \
|
||||
is still banned but not removing any more users and not banning any more rooms): \
|
||||
{}\nIf you would like to ignore errors, use --force",
|
||||
&local_user, &room_id, e
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if disable_federation {
|
||||
services().rooms.metadata.disable_room(&room_id, true)?;
|
||||
})
|
||||
})
|
||||
.collect::<Vec<OwnedUserId>>()
|
||||
{
|
||||
debug!("Attempting leave for user {} in room {}", &local_user, &room_id);
|
||||
if let Err(e) = leave_room(&local_user, &room_id, None).await {
|
||||
error!(
|
||||
"Error attempting to make local user {} leave room {} during bulk room banning: {}",
|
||||
&local_user, &room_id, e
|
||||
);
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Error attempting to make local user {} leave room {} during room banning (room is still \
|
||||
banned but not removing any more users and not banning any more rooms): {}\nIf you would \
|
||||
like to ignore errors, use --force",
|
||||
&local_user, &room_id, e
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if disable_federation {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Finished bulk room ban, banned {room_ban_count} total rooms, evicted all users, and disabled \
|
||||
incoming federation with the room."
|
||||
)));
|
||||
}
|
||||
if disable_federation {
|
||||
services().rooms.metadata.disable_room(&room_id, true)?;
|
||||
}
|
||||
}
|
||||
|
||||
if disable_federation {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Finished bulk room ban, banned {room_ban_count} total rooms, evicted all users, and disabled \
|
||||
incoming federation with the room."
|
||||
)));
|
||||
}
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Finished bulk room ban, banned {room_ban_count} total rooms and evicted all users."
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain(
|
||||
"Expected code block in command body. Add --help for details.",
|
||||
))
|
||||
}
|
||||
|
||||
async fn unban_room(
|
||||
_body: Vec<&str>, room: Box<RoomOrAliasId>, enable_federation: bool,
|
||||
) -> Result<RoomMessageEventContent> {
|
||||
let room_id = if room.is_room_id() {
|
||||
let room_id = match RoomId::parse(&room) {
|
||||
Ok(room_id) => room_id,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Finished bulk room ban, banned {room_ban_count} total rooms and evicted all users."
|
||||
)));
|
||||
}
|
||||
"Failed to parse room ID {room}. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
|
||||
)))
|
||||
},
|
||||
};
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain(
|
||||
"Expected code block in command body. Add --help for details.",
|
||||
))
|
||||
},
|
||||
RoomModerationCommand::UnbanRoom {
|
||||
room,
|
||||
enable_federation,
|
||||
} => {
|
||||
let room_id = if room.is_room_id() {
|
||||
let room_id = match RoomId::parse(&room) {
|
||||
Ok(room_id) => room_id,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to parse room ID {room}. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
|
||||
)))
|
||||
},
|
||||
};
|
||||
debug!("Room specified is a room ID, unbanning room ID");
|
||||
|
||||
debug!("Room specified is a room ID, unbanning room ID");
|
||||
services().rooms.metadata.ban_room(&room_id, false)?;
|
||||
|
||||
services().rooms.metadata.ban_room(&room_id, false)?;
|
||||
room_id
|
||||
} else if room.is_room_alias_id() {
|
||||
let room_alias = match RoomAliasId::parse(&room) {
|
||||
Ok(room_alias) => room_alias,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to parse room ID {room}. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
|
||||
)))
|
||||
},
|
||||
};
|
||||
|
||||
room_id
|
||||
} else if room.is_room_alias_id() {
|
||||
let room_alias = match RoomAliasId::parse(&room) {
|
||||
Ok(room_alias) => room_alias,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to parse room ID {room}. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`): {e}"
|
||||
)))
|
||||
},
|
||||
};
|
||||
debug!(
|
||||
"Room specified is not a room ID, attempting to resolve room alias to a room ID locally, if not using \
|
||||
get_alias_helper to fetch room ID remotely"
|
||||
);
|
||||
|
||||
debug!(
|
||||
"Room specified is not a room ID, attempting to resolve room alias to a room ID locally, if not \
|
||||
using get_alias_helper to fetch room ID remotely"
|
||||
);
|
||||
let room_id = if let Some(room_id) = services().rooms.alias.resolve_local_alias(&room_alias)? {
|
||||
room_id
|
||||
} else {
|
||||
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
|
||||
|
||||
let room_id = if let Some(room_id) = services().rooms.alias.resolve_local_alias(&room_alias)? {
|
||||
room_id
|
||||
} else {
|
||||
debug!(
|
||||
"We don't have this room alias to a room ID locally, attempting to fetch room ID over \
|
||||
federation"
|
||||
);
|
||||
|
||||
match get_alias_helper(room_alias, None).await {
|
||||
Ok(response) => {
|
||||
debug!("Got federation response fetching room ID for room {room}: {:?}", response);
|
||||
response.room_id
|
||||
},
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to resolve room alias {room} to a room ID: {e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
services().rooms.metadata.ban_room(&room_id, false)?;
|
||||
|
||||
room_id
|
||||
} else {
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
"Room specified is not a room ID or room alias. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`)",
|
||||
));
|
||||
};
|
||||
|
||||
if enable_federation {
|
||||
services().rooms.metadata.disable_room(&room_id, false)?;
|
||||
return Ok(RoomMessageEventContent::text_plain("Room unbanned."));
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain(
|
||||
"Room unbanned, you may need to re-enable federation with the room using enable-room if this is a \
|
||||
remote room to make it fully functional.",
|
||||
))
|
||||
},
|
||||
RoomModerationCommand::ListBannedRooms => {
|
||||
let rooms = services()
|
||||
.rooms
|
||||
.metadata
|
||||
.list_banned_rooms()
|
||||
.collect::<Result<Vec<_>, _>>();
|
||||
|
||||
match rooms {
|
||||
Ok(room_ids) => {
|
||||
// TODO: add room name from our state cache if available, default to the room ID
|
||||
// as the room name if we dont have it TODO: do same if we have a room alias for
|
||||
// this
|
||||
let plain_list = room_ids.iter().fold(String::new(), |mut output, room_id| {
|
||||
writeln!(output, "- `{room_id}`").unwrap();
|
||||
output
|
||||
});
|
||||
|
||||
let html_list = room_ids.iter().fold(String::new(), |mut output, room_id| {
|
||||
writeln!(output, "<li><code>{}</code></li>", escape_html(room_id.as_ref())).unwrap();
|
||||
output
|
||||
});
|
||||
|
||||
let plain = format!("Rooms:\n{plain_list}");
|
||||
let html = format!("Rooms:\n<ul>{html_list}</ul>");
|
||||
Ok(RoomMessageEventContent::text_html(plain, html))
|
||||
match get_alias_helper(room_alias, None).await {
|
||||
Ok(response) => {
|
||||
debug!("Got federation response fetching room ID for room {room}: {:?}", response);
|
||||
response.room_id
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to list banned rooms: {}", e);
|
||||
Ok(RoomMessageEventContent::text_plain(format!("Unable to list room aliases: {e}")))
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to resolve room alias {room} to a room ID: {e}"
|
||||
)));
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
services().rooms.metadata.ban_room(&room_id, false)?;
|
||||
|
||||
room_id
|
||||
} else {
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
"Room specified is not a room ID or room alias. Please note that this requires a full room ID \
|
||||
(`!awIh6gGInaS5wLQJwa:example.com`) or a room alias (`#roomalias:example.com`)",
|
||||
));
|
||||
};
|
||||
|
||||
if enable_federation {
|
||||
services().rooms.metadata.disable_room(&room_id, false)?;
|
||||
return Ok(RoomMessageEventContent::text_plain("Room unbanned."));
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain(
|
||||
"Room unbanned, you may need to re-enable federation with the room using enable-room if this is a remote room \
|
||||
to make it fully functional.",
|
||||
))
|
||||
}
|
||||
|
||||
async fn list_banned_rooms(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
|
||||
let rooms = services()
|
||||
.rooms
|
||||
.metadata
|
||||
.list_banned_rooms()
|
||||
.collect::<Result<Vec<_>, _>>();
|
||||
|
||||
match rooms {
|
||||
Ok(room_ids) => {
|
||||
// TODO: add room name from our state cache if available, default to the room ID
|
||||
// as the room name if we dont have it TODO: do same if we have a room alias for
|
||||
// this
|
||||
let plain_list = room_ids.iter().fold(String::new(), |mut output, room_id| {
|
||||
writeln!(output, "- `{room_id}`").unwrap();
|
||||
output
|
||||
});
|
||||
|
||||
let html_list = room_ids.iter().fold(String::new(), |mut output, room_id| {
|
||||
writeln!(output, "<li><code>{}</code></li>", escape_html(room_id.as_ref())).unwrap();
|
||||
output
|
||||
});
|
||||
|
||||
let plain = format!("Rooms:\n{plain_list}");
|
||||
let html = format!("Rooms:\n<ul>{html_list}</ul>");
|
||||
Ok(RoomMessageEventContent::text_html(plain, html))
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to list banned rooms: {}", e);
|
||||
Ok(RoomMessageEventContent::text_plain(format!("Unable to list room aliases: {e}")))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue