Rework admin commands to use subcommands.
This commit doesn't add, remove, or change any commands, it only organizes them
This commit is contained in:
parent
5106203d67
commit
3e9c564209
1 changed files with 587 additions and 504 deletions
|
@ -5,7 +5,7 @@ use std::{
|
|||
time::Instant,
|
||||
};
|
||||
|
||||
use clap::Parser;
|
||||
use clap::{Parser, Subcommand};
|
||||
use regex::Regex;
|
||||
use ruma::{
|
||||
events::{
|
||||
|
@ -41,6 +41,37 @@ use super::pdu::PduBuilder;
|
|||
#[derive(Parser)]
|
||||
#[command(name = "@conduit:server.name:", version = env!("CARGO_PKG_VERSION"))]
|
||||
enum AdminCommand {
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing appservices
|
||||
Appservice(AppserviceCommand),
|
||||
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing local users
|
||||
User(UserCommand),
|
||||
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing rooms
|
||||
Room(RoomCommand),
|
||||
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing federation
|
||||
Federation(FederationCommand),
|
||||
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing the server
|
||||
Server(ServerCommand),
|
||||
|
||||
#[command(subcommand)]
|
||||
// TODO: should i split out debug commands to a separate thing? the
|
||||
// debug commands seem like they could fit in the other categories fine
|
||||
// this is more like a "miscellaneous" category than a debug one
|
||||
/// Commands for debugging things
|
||||
Debug(DebugCommand),
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
#[derive(Subcommand)]
|
||||
enum AppserviceCommand {
|
||||
#[command(verbatim_doc_comment)]
|
||||
/// Register an appservice using its registration YAML
|
||||
///
|
||||
|
@ -54,33 +85,42 @@ enum AdminCommand {
|
|||
/// # ```
|
||||
/// # yaml content here
|
||||
/// # ```
|
||||
RegisterAppservice,
|
||||
Register,
|
||||
|
||||
/// Unregister an appservice using its ID
|
||||
///
|
||||
/// You can find the ID using the `list-appservices` command.
|
||||
UnregisterAppservice {
|
||||
Unregister {
|
||||
/// The appservice to unregister
|
||||
appservice_identifier: String,
|
||||
},
|
||||
|
||||
/// List all the currently registered appservices
|
||||
ListAppservices,
|
||||
List,
|
||||
}
|
||||
|
||||
/// List all rooms the server knows about
|
||||
ListRooms,
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
#[derive(Subcommand)]
|
||||
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>,
|
||||
},
|
||||
|
||||
/// List users in the database
|
||||
ListLocalUsers,
|
||||
|
||||
/// List all rooms we are currently handling an incoming pdu from
|
||||
IncomingFederation,
|
||||
/// 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
|
||||
DeactivateUser {
|
||||
Deactivate {
|
||||
#[arg(short, long)]
|
||||
leave_rooms: bool,
|
||||
user_id: Box<UserId>,
|
||||
|
@ -109,6 +149,49 @@ enum AdminCommand {
|
|||
force: bool,
|
||||
},
|
||||
|
||||
/// List local users in the database
|
||||
List,
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
#[derive(Subcommand)]
|
||||
enum RoomCommand {
|
||||
/// List all rooms the server knows about
|
||||
List,
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
#[derive(Subcommand)]
|
||||
enum FederationCommand {
|
||||
/// List all rooms we are currently handling an incoming pdu from
|
||||
IncomingFederation,
|
||||
|
||||
/// Disables incoming federation handling for a room.
|
||||
DisableRoom { room_id: Box<RoomId> },
|
||||
|
||||
/// Enables incoming federation handling for a room again.
|
||||
EnableRoom { room_id: Box<RoomId> },
|
||||
|
||||
#[command(verbatim_doc_comment)]
|
||||
/// Verify json signatures
|
||||
/// [commandbody]
|
||||
/// # ```
|
||||
/// # json here
|
||||
/// # ```
|
||||
SignJson,
|
||||
|
||||
#[command(verbatim_doc_comment)]
|
||||
/// Verify json signatures
|
||||
/// [commandbody]
|
||||
/// # ```
|
||||
/// # json here
|
||||
/// # ```
|
||||
VerifyJson,
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
#[derive(Subcommand)]
|
||||
enum DebugCommand {
|
||||
/// Get the auth_chain of a PDU
|
||||
GetAuthChain {
|
||||
/// An event ID (the $ character followed by the base64 reference hash)
|
||||
|
@ -132,6 +215,13 @@ enum AdminCommand {
|
|||
/// An event ID (a $ followed by the base64 reference hash)
|
||||
event_id: Box<EventId>,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
#[derive(Subcommand)]
|
||||
enum ServerCommand {
|
||||
/// Show configuration values
|
||||
ShowConfig,
|
||||
|
||||
/// Print database memory usage statistics
|
||||
MemoryUsage,
|
||||
|
@ -141,42 +231,6 @@ enum AdminCommand {
|
|||
|
||||
/// Clears all of Conduit's service caches with index smaller than the amount
|
||||
ClearServiceCaches { amount: u32 },
|
||||
|
||||
/// Show configuration values
|
||||
ShowConfig,
|
||||
|
||||
/// Reset user password
|
||||
ResetPassword {
|
||||
/// Username of the user for whom the password should be reset
|
||||
username: String,
|
||||
},
|
||||
|
||||
/// Create a new user
|
||||
CreateUser {
|
||||
/// Username of the new user
|
||||
username: String,
|
||||
/// Password of the new user, if unspecified one is generated
|
||||
password: Option<String>,
|
||||
},
|
||||
|
||||
/// Disables incoming federation handling for a room.
|
||||
DisableRoom { room_id: Box<RoomId> },
|
||||
/// Enables incoming federation handling for a room again.
|
||||
EnableRoom { room_id: Box<RoomId> },
|
||||
|
||||
/// Verify json signatures
|
||||
/// [commandbody]
|
||||
/// # ```
|
||||
/// # json here
|
||||
/// # ```
|
||||
SignJson,
|
||||
|
||||
/// Verify json signatures
|
||||
/// [commandbody]
|
||||
/// # ```
|
||||
/// # json here
|
||||
/// # ```
|
||||
VerifyJson,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -341,8 +395,11 @@ impl Service {
|
|||
body: Vec<&str>,
|
||||
) -> Result<RoomMessageEventContent> {
|
||||
let reply_message_content = match command {
|
||||
AdminCommand::RegisterAppservice => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
AdminCommand::Appservice(command) => match command {
|
||||
AppserviceCommand::Register => {
|
||||
if body.len() > 2
|
||||
&& body[0].trim() == "```"
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let appservice_config = body[1..body.len() - 1].join("\n");
|
||||
let parsed_config =
|
||||
|
@ -366,7 +423,7 @@ impl Service {
|
|||
)
|
||||
}
|
||||
}
|
||||
AdminCommand::UnregisterAppservice {
|
||||
AppserviceCommand::Unregister {
|
||||
appservice_identifier,
|
||||
} => match services()
|
||||
.appservice
|
||||
|
@ -377,7 +434,7 @@ impl Service {
|
|||
"Failed to unregister appservice: {e}"
|
||||
)),
|
||||
},
|
||||
AdminCommand::ListAppservices => {
|
||||
AppserviceCommand::List => {
|
||||
if let Ok(appservices) = services()
|
||||
.appservice
|
||||
.iter_ids()
|
||||
|
@ -398,217 +455,18 @@ impl Service {
|
|||
RoomMessageEventContent::text_plain("Failed to get appservices.")
|
||||
}
|
||||
}
|
||||
AdminCommand::ListRooms => {
|
||||
let room_ids = services().rooms.metadata.iter_ids();
|
||||
let output = format!(
|
||||
"Rooms:\n{}",
|
||||
room_ids
|
||||
.filter_map(|r| r.ok())
|
||||
.map(|id| id.to_string()
|
||||
+ "\tMembers: "
|
||||
+ &services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_joined_count(&id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(0)
|
||||
.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
);
|
||||
RoomMessageEventContent::text_plain(output)
|
||||
}
|
||||
AdminCommand::ListLocalUsers => match services().users.list_local_users() {
|
||||
},
|
||||
AdminCommand::User(command) => match command {
|
||||
UserCommand::List => match services().users.list_local_users() {
|
||||
Ok(users) => {
|
||||
let mut msg: String = format!("Found {} local user account(s):\n", users.len());
|
||||
let mut msg: String =
|
||||
format!("Found {} local user account(s):\n", users.len());
|
||||
msg += &users.join("\n");
|
||||
RoomMessageEventContent::text_plain(&msg)
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(e.to_string()),
|
||||
},
|
||||
AdminCommand::IncomingFederation => {
|
||||
let map = services()
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.read()
|
||||
.unwrap();
|
||||
let mut msg: String = format!("Handling {} incoming pdus:\n", map.len());
|
||||
|
||||
for (r, (e, i)) in map.iter() {
|
||||
let elapsed = i.elapsed();
|
||||
msg += &format!(
|
||||
"{} {}: {}m{}s\n",
|
||||
r,
|
||||
e,
|
||||
elapsed.as_secs() / 60,
|
||||
elapsed.as_secs() % 60
|
||||
);
|
||||
}
|
||||
RoomMessageEventContent::text_plain(&msg)
|
||||
}
|
||||
AdminCommand::GetAuthChain { event_id } => {
|
||||
let event_id = Arc::<EventId>::from(event_id);
|
||||
if let Some(event) = services().rooms.timeline.get_pdu_json(&event_id)? {
|
||||
let room_id_str = event
|
||||
.get("room_id")
|
||||
.and_then(|val| val.as_str())
|
||||
.ok_or_else(|| Error::bad_database("Invalid event in database"))?;
|
||||
|
||||
let room_id = <&RoomId>::try_from(room_id_str).map_err(|_| {
|
||||
Error::bad_database("Invalid room id field in event in database")
|
||||
})?;
|
||||
let start = Instant::now();
|
||||
let count = services()
|
||||
.rooms
|
||||
.auth_chain
|
||||
.get_auth_chain(room_id, vec![event_id])
|
||||
.await?
|
||||
.count();
|
||||
let elapsed = start.elapsed();
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"Loaded auth chain with length {count} in {elapsed:?}"
|
||||
))
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain("Event not found.")
|
||||
}
|
||||
}
|
||||
AdminCommand::ParsePdu => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let string = body[1..body.len() - 1].join("\n");
|
||||
match serde_json::from_str(&string) {
|
||||
Ok(value) => {
|
||||
match ruma::signatures::reference_hash(&value, &RoomVersionId::V6) {
|
||||
Ok(hash) => {
|
||||
let event_id = EventId::parse(format!("${hash}"));
|
||||
|
||||
match serde_json::from_value::<PduEvent>(
|
||||
serde_json::to_value(value).expect("value is json"),
|
||||
) {
|
||||
Ok(pdu) => RoomMessageEventContent::text_plain(format!(
|
||||
"EventId: {event_id:?}\n{pdu:#?}"
|
||||
)),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"EventId: {event_id:?}\nCould not parse event: {e}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Could not parse PDU JSON: {e:?}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Invalid json in command body: {e}"
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain("Expected code block in command body.")
|
||||
}
|
||||
}
|
||||
AdminCommand::GetPdu { event_id } => {
|
||||
let mut outlier = false;
|
||||
let mut pdu_json = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.get_non_outlier_pdu_json(&event_id)?;
|
||||
if pdu_json.is_none() {
|
||||
outlier = true;
|
||||
pdu_json = services().rooms.timeline.get_pdu_json(&event_id)?;
|
||||
}
|
||||
match pdu_json {
|
||||
Some(json) => {
|
||||
let json_text = serde_json::to_string_pretty(&json)
|
||||
.expect("canonical json is valid json");
|
||||
RoomMessageEventContent::text_html(
|
||||
format!(
|
||||
"{}\n```json\n{}\n```",
|
||||
if outlier {
|
||||
"PDU is outlier"
|
||||
} else {
|
||||
"PDU was accepted"
|
||||
},
|
||||
json_text
|
||||
),
|
||||
format!(
|
||||
"<p>{}</p>\n<pre><code class=\"language-json\">{}\n</code></pre>\n",
|
||||
if outlier {
|
||||
"PDU is outlier"
|
||||
} else {
|
||||
"PDU was accepted"
|
||||
},
|
||||
HtmlEscape(&json_text)
|
||||
),
|
||||
)
|
||||
}
|
||||
None => RoomMessageEventContent::text_plain("PDU not found."),
|
||||
}
|
||||
}
|
||||
AdminCommand::MemoryUsage => {
|
||||
let response1 = services().memory_usage();
|
||||
let response2 = services().globals.db.memory_usage();
|
||||
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"Services:\n{response1}\n\nDatabase:\n{response2}"
|
||||
))
|
||||
}
|
||||
AdminCommand::ClearDatabaseCaches { amount } => {
|
||||
services().globals.db.clear_caches(amount);
|
||||
|
||||
RoomMessageEventContent::text_plain("Done.")
|
||||
}
|
||||
AdminCommand::ClearServiceCaches { amount } => {
|
||||
services().clear_caches(amount);
|
||||
|
||||
RoomMessageEventContent::text_plain("Done.")
|
||||
}
|
||||
AdminCommand::ShowConfig => {
|
||||
// Construct and send the response
|
||||
RoomMessageEventContent::text_plain(format!("{}", services().globals.config))
|
||||
}
|
||||
AdminCommand::ResetPassword { username } => {
|
||||
let user_id = match UserId::parse_with_server_name(
|
||||
username.as_str().to_lowercase(),
|
||||
services().globals.server_name(),
|
||||
) {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"The supplied username is not a valid username: {e}"
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
// Check if the specified user is valid
|
||||
if !services().users.exists(&user_id)?
|
||||
|| user_id
|
||||
== UserId::parse_with_server_name(
|
||||
"conduit",
|
||||
services().globals.server_name(),
|
||||
)
|
||||
.expect("conduit user exists")
|
||||
{
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
"The specified user does not exist!",
|
||||
));
|
||||
}
|
||||
|
||||
let new_password = utils::random_string(AUTO_GEN_PASSWORD_LENGTH);
|
||||
|
||||
match services()
|
||||
.users
|
||||
.set_password(&user_id, Some(new_password.as_str()))
|
||||
{
|
||||
Ok(()) => RoomMessageEventContent::text_plain(format!(
|
||||
"Successfully reset the password for user {user_id}: {new_password}"
|
||||
)),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Couldn't reset the password for user {user_id}: {e}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
AdminCommand::CreateUser { username, password } => {
|
||||
UserCommand::Create { username, password } => {
|
||||
let password =
|
||||
password.unwrap_or_else(|| utils::random_string(AUTO_GEN_PASSWORD_LENGTH));
|
||||
// Validate user id
|
||||
|
@ -670,15 +528,7 @@ impl Service {
|
|||
"Created user with user_id: {user_id} and password: {password}"
|
||||
))
|
||||
}
|
||||
AdminCommand::DisableRoom { room_id } => {
|
||||
services().rooms.metadata.disable_room(&room_id, true)?;
|
||||
RoomMessageEventContent::text_plain("Room disabled.")
|
||||
}
|
||||
AdminCommand::EnableRoom { room_id } => {
|
||||
services().rooms.metadata.disable_room(&room_id, false)?;
|
||||
RoomMessageEventContent::text_plain("Room enabled.")
|
||||
}
|
||||
AdminCommand::DeactivateUser {
|
||||
UserCommand::Deactivate {
|
||||
leave_rooms,
|
||||
user_id,
|
||||
} => {
|
||||
|
@ -703,8 +553,51 @@ impl Service {
|
|||
))
|
||||
}
|
||||
}
|
||||
AdminCommand::DeactivateAll { leave_rooms, force } => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
UserCommand::ResetPassword { username } => {
|
||||
let user_id = match UserId::parse_with_server_name(
|
||||
username.as_str().to_lowercase(),
|
||||
services().globals.server_name(),
|
||||
) {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"The supplied username is not a valid username: {e}"
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
// Check if the specified user is valid
|
||||
if !services().users.exists(&user_id)?
|
||||
|| user_id
|
||||
== UserId::parse_with_server_name(
|
||||
"conduit",
|
||||
services().globals.server_name(),
|
||||
)
|
||||
.expect("conduit user exists")
|
||||
{
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
"The specified user does not exist!",
|
||||
));
|
||||
}
|
||||
|
||||
let new_password = utils::random_string(AUTO_GEN_PASSWORD_LENGTH);
|
||||
|
||||
match services()
|
||||
.users
|
||||
.set_password(&user_id, Some(new_password.as_str()))
|
||||
{
|
||||
Ok(()) => RoomMessageEventContent::text_plain(format!(
|
||||
"Successfully reset the password for user {user_id}: {new_password}"
|
||||
)),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Couldn't reset the password for user {user_id}: {e}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
UserCommand::DeactivateAll { leave_rooms, force } => {
|
||||
if body.len() > 2
|
||||
&& body[0].trim() == "```"
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let usernames = body.clone().drain(1..body.len() - 1).collect::<Vec<_>>();
|
||||
|
||||
|
@ -762,8 +655,63 @@ impl Service {
|
|||
)
|
||||
}
|
||||
}
|
||||
AdminCommand::SignJson => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
},
|
||||
AdminCommand::Room(command) => match command {
|
||||
RoomCommand::List => {
|
||||
let room_ids = services().rooms.metadata.iter_ids();
|
||||
let output = format!(
|
||||
"Rooms:\n{}",
|
||||
room_ids
|
||||
.filter_map(|r| r.ok())
|
||||
.map(|id| id.to_string()
|
||||
+ "\tMembers: "
|
||||
+ &services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_joined_count(&id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(0)
|
||||
.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
);
|
||||
RoomMessageEventContent::text_plain(output)
|
||||
}
|
||||
},
|
||||
AdminCommand::Federation(command) => match command {
|
||||
FederationCommand::DisableRoom { room_id } => {
|
||||
services().rooms.metadata.disable_room(&room_id, true)?;
|
||||
RoomMessageEventContent::text_plain("Room disabled.")
|
||||
}
|
||||
FederationCommand::EnableRoom { room_id } => {
|
||||
services().rooms.metadata.disable_room(&room_id, false)?;
|
||||
RoomMessageEventContent::text_plain("Room enabled.")
|
||||
}
|
||||
FederationCommand::IncomingFederation => {
|
||||
let map = services()
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.read()
|
||||
.unwrap();
|
||||
let mut msg: String = format!("Handling {} incoming pdus:\n", map.len());
|
||||
|
||||
for (r, (e, i)) in map.iter() {
|
||||
let elapsed = i.elapsed();
|
||||
msg += &format!(
|
||||
"{} {}: {}m{}s\n",
|
||||
r,
|
||||
e,
|
||||
elapsed.as_secs() / 60,
|
||||
elapsed.as_secs() % 60
|
||||
);
|
||||
}
|
||||
RoomMessageEventContent::text_plain(&msg)
|
||||
}
|
||||
FederationCommand::SignJson => {
|
||||
if body.len() > 2
|
||||
&& body[0].trim() == "```"
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let string = body[1..body.len() - 1].join("\n");
|
||||
match serde_json::from_str(&string) {
|
||||
|
@ -778,7 +726,9 @@ impl Service {
|
|||
.expect("canonical json is valid json");
|
||||
RoomMessageEventContent::text_plain(json_text)
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!("Invalid json: {e}")),
|
||||
Err(e) => {
|
||||
RoomMessageEventContent::text_plain(format!("Invalid json: {e}"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain(
|
||||
|
@ -786,8 +736,10 @@ impl Service {
|
|||
)
|
||||
}
|
||||
}
|
||||
AdminCommand::VerifyJson => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
FederationCommand::VerifyJson => {
|
||||
if body.len() > 2
|
||||
&& body[0].trim() == "```"
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let string = body[1..body.len() - 1].join("\n");
|
||||
match serde_json::from_str(&string) {
|
||||
|
@ -802,13 +754,17 @@ impl Service {
|
|||
|
||||
let pub_key_map = pub_key_map.read().unwrap();
|
||||
match ruma::signatures::verify_json(&pub_key_map, &value) {
|
||||
Ok(_) => RoomMessageEventContent::text_plain("Signature correct"),
|
||||
Ok(_) => {
|
||||
RoomMessageEventContent::text_plain("Signature correct")
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Signature verification failed: {e}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!("Invalid json: {e}")),
|
||||
Err(e) => {
|
||||
RoomMessageEventContent::text_plain(format!("Invalid json: {e}"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain(
|
||||
|
@ -816,6 +772,133 @@ impl Service {
|
|||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
AdminCommand::Server(command) => match command {
|
||||
ServerCommand::ShowConfig => {
|
||||
// Construct and send the response
|
||||
RoomMessageEventContent::text_plain(format!("{}", services().globals.config))
|
||||
}
|
||||
ServerCommand::MemoryUsage => {
|
||||
let response1 = services().memory_usage();
|
||||
let response2 = services().globals.db.memory_usage();
|
||||
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"Services:\n{response1}\n\nDatabase:\n{response2}"
|
||||
))
|
||||
}
|
||||
ServerCommand::ClearDatabaseCaches { amount } => {
|
||||
services().globals.db.clear_caches(amount);
|
||||
|
||||
RoomMessageEventContent::text_plain("Done.")
|
||||
}
|
||||
ServerCommand::ClearServiceCaches { amount } => {
|
||||
services().clear_caches(amount);
|
||||
|
||||
RoomMessageEventContent::text_plain("Done.")
|
||||
}
|
||||
},
|
||||
AdminCommand::Debug(command) => match command {
|
||||
DebugCommand::GetAuthChain { event_id } => {
|
||||
let event_id = Arc::<EventId>::from(event_id);
|
||||
if let Some(event) = services().rooms.timeline.get_pdu_json(&event_id)? {
|
||||
let room_id_str = event
|
||||
.get("room_id")
|
||||
.and_then(|val| val.as_str())
|
||||
.ok_or_else(|| Error::bad_database("Invalid event in database"))?;
|
||||
|
||||
let room_id = <&RoomId>::try_from(room_id_str).map_err(|_| {
|
||||
Error::bad_database("Invalid room id field in event in database")
|
||||
})?;
|
||||
let start = Instant::now();
|
||||
let count = services()
|
||||
.rooms
|
||||
.auth_chain
|
||||
.get_auth_chain(room_id, vec![event_id])
|
||||
.await?
|
||||
.count();
|
||||
let elapsed = start.elapsed();
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"Loaded auth chain with length {count} in {elapsed:?}"
|
||||
))
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain("Event not found.")
|
||||
}
|
||||
}
|
||||
DebugCommand::ParsePdu => {
|
||||
if body.len() > 2
|
||||
&& body[0].trim() == "```"
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let string = body[1..body.len() - 1].join("\n");
|
||||
match serde_json::from_str(&string) {
|
||||
Ok(value) => {
|
||||
match ruma::signatures::reference_hash(&value, &RoomVersionId::V6) {
|
||||
Ok(hash) => {
|
||||
let event_id = EventId::parse(format!("${hash}"));
|
||||
|
||||
match serde_json::from_value::<PduEvent>(
|
||||
serde_json::to_value(value).expect("value is json"),
|
||||
) {
|
||||
Ok(pdu) => RoomMessageEventContent::text_plain(
|
||||
format!("EventId: {event_id:?}\n{pdu:#?}"),
|
||||
),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"EventId: {event_id:?}\nCould not parse event: {e}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Could not parse PDU JSON: {e:?}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Invalid json in command body: {e}"
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain("Expected code block in command body.")
|
||||
}
|
||||
}
|
||||
DebugCommand::GetPdu { event_id } => {
|
||||
let mut outlier = false;
|
||||
let mut pdu_json = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.get_non_outlier_pdu_json(&event_id)?;
|
||||
if pdu_json.is_none() {
|
||||
outlier = true;
|
||||
pdu_json = services().rooms.timeline.get_pdu_json(&event_id)?;
|
||||
}
|
||||
match pdu_json {
|
||||
Some(json) => {
|
||||
let json_text = serde_json::to_string_pretty(&json)
|
||||
.expect("canonical json is valid json");
|
||||
RoomMessageEventContent::text_html(
|
||||
format!(
|
||||
"{}\n```json\n{}\n```",
|
||||
if outlier {
|
||||
"PDU is outlier"
|
||||
} else {
|
||||
"PDU was accepted"
|
||||
},
|
||||
json_text
|
||||
),
|
||||
format!(
|
||||
"<p>{}</p>\n<pre><code class=\"language-json\">{}\n</code></pre>\n",
|
||||
if outlier {
|
||||
"PDU is outlier"
|
||||
} else {
|
||||
"PDU was accepted"
|
||||
},
|
||||
HtmlEscape(&json_text)
|
||||
),
|
||||
)
|
||||
}
|
||||
None => RoomMessageEventContent::text_plain("PDU not found."),
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(reply_message_content)
|
||||
|
|
Loading…
Add table
Reference in a new issue