refactor more of admin code, add unfinished fsck command

Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
strawberry 2024-04-20 17:59:54 -04:00 committed by June
parent 7cbe82668b
commit 6b28bd5ae7
8 changed files with 219 additions and 191 deletions

View file

@ -1,91 +1,16 @@
use std::{collections::BTreeMap, sync::Arc, time::Instant};
use clap::Subcommand;
use ruma::{
api::client::error::ErrorKind, events::room::message::RoomMessageEventContent, CanonicalJsonObject, EventId,
RoomId, RoomVersionId, ServerName,
RoomId, RoomVersionId,
};
use tokio::sync::RwLock;
use tracing::{debug, error, info, warn};
use tracing_subscriber::EnvFilter;
use super::DebugCommand;
use crate::{api::server_server::parse_incoming_pdu, services, utils::HtmlEscape, Error, PduEvent, Result};
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
pub(crate) enum DebugCommand {
/// - Get the auth_chain of a PDU
GetAuthChain {
/// An event ID (the $ character followed by the base64 reference hash)
event_id: Box<EventId>,
},
/// - Parse and print a PDU from a JSON
///
/// The PDU event is only checked for validity and is not added to the
/// database.
///
/// This command needs a JSON blob provided in a Markdown code block below
/// the command.
ParsePdu,
/// - Retrieve and print a PDU by ID from the conduwuit database
GetPdu {
/// An event ID (a $ followed by the base64 reference hash)
event_id: Box<EventId>,
},
/// - Attempts to retrieve a PDU from a remote server. Inserts it into our
/// database/timeline if found and we do not have this PDU already
/// (following normal event auth rules, handles it as an incoming PDU).
GetRemotePdu {
/// An event ID (a $ followed by the base64 reference hash)
event_id: Box<EventId>,
/// Argument for us to attempt to fetch the event from the
/// specified remote server.
server: Box<ServerName>,
},
/// - Gets all the room state events for the specified room.
///
/// This is functionally equivalent to `GET
/// /_matrix/client/v3/rooms/{roomid}/state`, except the admin command does
/// *not* check if the sender user is allowed to see state events. This is
/// done because it's implied that server admins here have database access
/// and can see/get room info themselves anyways if they were malicious
/// admins.
///
/// Of course the check is still done on the actual client API.
GetRoomState {
/// Room ID
room_id: Box<RoomId>,
},
/// - Sends a federation request to the remote server's
/// `/_matrix/federation/v1/version` endpoint and measures the latency it
/// took for the server to respond
Ping {
server: Box<ServerName>,
},
/// - Forces device lists for all local and remote users to be updated (as
/// having new keys available)
ForceDeviceListUpdates,
/// - Change tracing log level/filter on the fly
///
/// This accepts the same format as the `log` config option.
ChangeLogLevel {
/// Log level/filter
filter: Option<String>,
/// Resets the log level/filter to the one in your config
#[arg(short, long)]
reset: bool,
},
}
pub(crate) async fn process(command: DebugCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
DebugCommand::GetAuthChain {

View file

@ -0,0 +1,80 @@
use clap::Subcommand;
use ruma::{EventId, RoomId, ServerName};
#[allow(clippy::module_inception)]
pub(crate) mod debug;
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
pub(crate) enum DebugCommand {
/// - Get the auth_chain of a PDU
GetAuthChain {
/// An event ID (the $ character followed by the base64 reference hash)
event_id: Box<EventId>,
},
/// - Parse and print a PDU from a JSON
///
/// The PDU event is only checked for validity and is not added to the
/// database.
///
/// This command needs a JSON blob provided in a Markdown code block below
/// the command.
ParsePdu,
/// - Retrieve and print a PDU by ID from the conduwuit database
GetPdu {
/// An event ID (a $ followed by the base64 reference hash)
event_id: Box<EventId>,
},
/// - Attempts to retrieve a PDU from a remote server. Inserts it into our
/// database/timeline if found and we do not have this PDU already
/// (following normal event auth rules, handles it as an incoming PDU).
GetRemotePdu {
/// An event ID (a $ followed by the base64 reference hash)
event_id: Box<EventId>,
/// Argument for us to attempt to fetch the event from the
/// specified remote server.
server: Box<ServerName>,
},
/// - Gets all the room state events for the specified room.
///
/// This is functionally equivalent to `GET
/// /_matrix/client/v3/rooms/{roomid}/state`, except the admin command does
/// *not* check if the sender user is allowed to see state events. This is
/// done because it's implied that server admins here have database access
/// and can see/get room info themselves anyways if they were malicious
/// admins.
///
/// Of course the check is still done on the actual client API.
GetRoomState {
/// Room ID
room_id: Box<RoomId>,
},
/// - Sends a federation request to the remote server's
/// `/_matrix/federation/v1/version` endpoint and measures the latency it
/// took for the server to respond
Ping {
server: Box<ServerName>,
},
/// - Forces device lists for all local and remote users to be updated (as
/// having new keys available)
ForceDeviceListUpdates,
/// - Change tracing log level/filter on the fly
///
/// This accepts the same format as the `log` config option.
ChangeLogLevel {
/// Log level/filter
filter: Option<String>,
/// Resets the log level/filter to the one in your config
#[arg(short, long)]
reset: bool,
},
}

18
src/service/admin/fsck.rs Normal file
View file

@ -0,0 +1,18 @@
use clap::Subcommand;
use ruma::events::room::message::RoomMessageEventContent;
use crate::{services, Result};
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
pub(crate) enum FsckCommand {
Register,
}
pub(crate) async fn fsck(command: FsckCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
match command {
FsckCommand::Register => {
todo!()
},
}
}

View file

@ -30,7 +30,7 @@ use super::pdu::PduBuilder;
use crate::{
service::admin::{
appservice::AppserviceCommand, debug::DebugCommand, federation::FederationCommand, media::MediaCommand,
query::query::QueryCommand, room::RoomCommand, server::ServerCommand, user::UserCommand,
query::QueryCommand, room::RoomCommand, server::ServerCommand, user::UserCommand,
},
services, Error, Result,
};
@ -38,6 +38,7 @@ use crate::{
pub(crate) mod appservice;
pub(crate) mod debug;
pub(crate) mod federation;
pub(crate) mod fsck;
pub(crate) mod media;
pub(crate) mod query;
pub(crate) mod room;
@ -279,12 +280,12 @@ impl Service {
let reply_message_content = match command {
AdminCommand::Appservices(command) => appservice::process(command, body).await?,
AdminCommand::Media(command) => media::process(command, body).await?,
AdminCommand::Users(command) => user::process(command, body).await?,
AdminCommand::Users(command) => user::user::process(command, body).await?,
AdminCommand::Rooms(command) => room::process(command, body).await?,
AdminCommand::Federation(command) => federation::process(command, body).await?,
AdminCommand::Server(command) => server::process(command, body).await?,
AdminCommand::Debug(command) => debug::process(command, body).await?,
AdminCommand::Query(command) => query::query::process(command, body).await?,
AdminCommand::Debug(command) => debug::debug::process(command, body).await?,
AdminCommand::Query(command) => query::process(command, body).await?,
};
Ok(reply_message_content)

View file

@ -1,8 +1,54 @@
#[allow(clippy::module_inception)]
pub(crate) mod query;
pub(crate) mod account_data;
pub(crate) mod appservice;
pub(crate) mod globals;
pub(crate) mod presence;
pub(crate) mod room_alias;
use clap::Subcommand;
use ruma::events::room::message::RoomMessageEventContent;
use self::{
account_data::{account_data, AccountData},
appservice::{appservice, Appservice},
globals::{globals, Globals},
presence::{presence, Presence},
room_alias::{room_alias, RoomAlias},
};
use crate::Result;
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// Query tables from database
pub(crate) enum QueryCommand {
/// - account_data.rs iterators and getters
#[command(subcommand)]
AccountData(AccountData),
/// - appservice.rs iterators and getters
#[command(subcommand)]
Appservice(Appservice),
/// - presence.rs iterators and getters
#[command(subcommand)]
Presence(Presence),
/// - rooms/alias.rs iterators and getters
#[command(subcommand)]
RoomAlias(RoomAlias),
/// - globals.rs iterators and getters
#[command(subcommand)]
Globals(Globals),
}
/// Processes admin query commands
#[allow(non_snake_case)]
pub(crate) async fn process(command: QueryCommand, _body: Vec<&str>) -> Result<RoomMessageEventContent> {
match command {
QueryCommand::AccountData(AccountData) => account_data(AccountData).await,
QueryCommand::Appservice(Appservice) => appservice(Appservice).await,
QueryCommand::Presence(Presence) => presence(Presence).await,
QueryCommand::RoomAlias(RoomAlias) => room_alias(RoomAlias).await,
QueryCommand::Globals(Globals) => globals(Globals).await,
}
}

View file

@ -1,48 +0,0 @@
use clap::Subcommand;
use ruma::events::room::message::RoomMessageEventContent;
use super::{
account_data::{account_data, AccountData},
appservice::{appservice, Appservice},
globals::{globals, Globals},
presence::{presence, Presence},
room_alias::{room_alias, RoomAlias},
};
use crate::Result;
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
/// Query tables from database
pub(crate) enum QueryCommand {
/// - account_data.rs iterators and getters
#[command(subcommand)]
AccountData(AccountData),
/// - appservice.rs iterators and getters
#[command(subcommand)]
Appservice(Appservice),
/// - presence.rs iterators and getters
#[command(subcommand)]
Presence(Presence),
/// - rooms/alias.rs iterators and getters
#[command(subcommand)]
RoomAlias(RoomAlias),
/// - globals.rs iterators and getters
#[command(subcommand)]
Globals(Globals),
}
/// Processes admin query commands
#[allow(non_snake_case)]
pub(crate) async fn process(command: QueryCommand, _body: Vec<&str>) -> Result<RoomMessageEventContent> {
match command {
QueryCommand::AccountData(AccountData) => account_data(AccountData).await,
QueryCommand::Appservice(Appservice) => appservice(Appservice).await,
QueryCommand::Presence(Presence) => presence(Presence).await,
QueryCommand::RoomAlias(RoomAlias) => room_alias(RoomAlias).await,
QueryCommand::Globals(Globals) => globals(Globals).await,
}
}

View file

@ -0,0 +1,63 @@
#[allow(clippy::module_inception)]
pub(crate) mod user;
use clap::Subcommand;
use ruma::UserId;
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
pub(crate) enum UserCommand {
/// - Create a new user
Create {
/// Username of the new user
username: String,
/// Password of the new user, if unspecified one is generated
password: Option<String>,
},
/// - Reset user password
ResetPassword {
/// Username of the user for whom the password should be reset
username: String,
},
/// - Deactivate a user
///
/// User will not be removed from all rooms by default.
/// Use --leave-rooms to force the user to leave all rooms
Deactivate {
#[arg(short, long)]
leave_rooms: bool,
user_id: Box<UserId>,
},
/// - Deactivate a list of users
///
/// Recommended to use in conjunction with list-local-users.
///
/// Users will not be removed from joined rooms by default.
/// Can be overridden with --leave-rooms flag.
/// Removing a mass amount of users from a room may cause a significant
/// amount of leave events. The time to leave rooms may depend significantly
/// on joined rooms and servers.
///
/// This command needs a newline separated list of users provided in a
/// Markdown code block below the command.
DeactivateAll {
#[arg(short, long)]
/// Remove users from their joined rooms
leave_rooms: bool,
#[arg(short, long)]
/// Also deactivate admin accounts
force: bool,
},
/// - List local users in the database
List,
/// - Lists all the rooms (local and remote) that the specified user is
/// joined in
ListJoinedRooms {
user_id: Box<UserId>,
},
}

View file

@ -1,74 +1,17 @@
use std::{fmt::Write as _, sync::Arc};
use clap::Subcommand;
use itertools::Itertools;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, UserId};
use tracing::{error, info, warn};
use super::UserCommand;
use crate::{
api::client_server::{join_room_by_id_helper, leave_all_rooms, AUTO_GEN_PASSWORD_LENGTH},
service::admin::{escape_html, get_room_info},
services, utils, Result,
};
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
pub(crate) enum UserCommand {
/// - Create a new user
Create {
/// Username of the new user
username: String,
/// Password of the new user, if unspecified one is generated
password: Option<String>,
},
/// - Reset user password
ResetPassword {
/// Username of the user for whom the password should be reset
username: String,
},
/// - Deactivate a user
///
/// User will not be removed from all rooms by default.
/// Use --leave-rooms to force the user to leave all rooms
Deactivate {
#[arg(short, long)]
leave_rooms: bool,
user_id: Box<UserId>,
},
/// - Deactivate a list of users
///
/// Recommended to use in conjunction with list-local-users.
///
/// Users will not be removed from joined rooms by default.
/// Can be overridden with --leave-rooms flag.
/// Removing a mass amount of users from a room may cause a significant
/// amount of leave events. The time to leave rooms may depend significantly
/// on joined rooms and servers.
///
/// This command needs a newline separated list of users provided in a
/// Markdown code block below the command.
DeactivateAll {
#[arg(short, long)]
/// Remove users from their joined rooms
leave_rooms: bool,
#[arg(short, long)]
/// Also deactivate admin accounts
force: bool,
},
/// - List local users in the database
List,
/// - Lists all the rooms (local and remote) that the specified user is
/// joined in
ListJoinedRooms {
user_id: Box<UserId>,
},
}
pub(crate) async fn process(command: UserCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
match command {
UserCommand::List => match services().users.list_local_users() {