mirror of
https://gitlab.computer.surgery/matrix/grapevine.git
synced 2025-12-17 15:51:23 +01:00
change rustfmt configuration
This change is fully automated, except the `rustfmt.toml` changes and a few clippy directives to allow specific functions with too many lines because they are longer now.
This commit is contained in:
parent
40d6ce230d
commit
0afc1d2f50
123 changed files with 7881 additions and 4687 deletions
|
|
@ -16,7 +16,9 @@ use ruma::{
|
|||
canonical_alias::RoomCanonicalAliasEventContent,
|
||||
create::RoomCreateEventContent,
|
||||
guest_access::{GuestAccess, RoomGuestAccessEventContent},
|
||||
history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
|
||||
history_visibility::{
|
||||
HistoryVisibility, RoomHistoryVisibilityEventContent,
|
||||
},
|
||||
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
message::RoomMessageEventContent,
|
||||
|
|
@ -26,19 +28,19 @@ use ruma::{
|
|||
},
|
||||
TimelineEventType,
|
||||
},
|
||||
EventId, OwnedRoomAliasId, OwnedRoomId, RoomAliasId, RoomId, RoomVersionId, ServerName, UserId,
|
||||
EventId, OwnedRoomAliasId, OwnedRoomId, RoomAliasId, RoomId, RoomVersionId,
|
||||
ServerName, UserId,
|
||||
};
|
||||
use serde_json::value::to_raw_value;
|
||||
use tokio::sync::{mpsc, Mutex, RwLock};
|
||||
use tracing::warn;
|
||||
|
||||
use super::pdu::PduBuilder;
|
||||
use crate::{
|
||||
api::client_server::{leave_all_rooms, AUTO_GEN_PASSWORD_LENGTH},
|
||||
services, utils, Error, PduEvent, Result,
|
||||
};
|
||||
|
||||
use super::pdu::PduBuilder;
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
#[derive(Parser)]
|
||||
#[command(name = "@grapevine:server.name:", version = env!("CARGO_PKG_VERSION"))]
|
||||
|
|
@ -46,11 +48,12 @@ enum AdminCommand {
|
|||
#[command(verbatim_doc_comment)]
|
||||
/// Register an appservice using its registration YAML
|
||||
///
|
||||
/// This command needs a YAML generated by an appservice (such as a bridge),
|
||||
/// which must be provided in a Markdown code-block below the command.
|
||||
/// This command needs a YAML generated by an appservice (such as a
|
||||
/// bridge), which must be provided in a Markdown code-block below the
|
||||
/// command.
|
||||
///
|
||||
/// Registering a new bridge using the ID of an existing bridge will replace
|
||||
/// the old one.
|
||||
/// Registering a new bridge using the ID of an existing bridge will
|
||||
/// replace the old one.
|
||||
///
|
||||
/// [commandbody]()
|
||||
/// # ```
|
||||
|
|
@ -95,8 +98,9 @@ enum AdminCommand {
|
|||
///
|
||||
/// 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.
|
||||
/// 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.
|
||||
///
|
||||
/// [commandbody]()
|
||||
/// # ```
|
||||
|
|
@ -138,11 +142,17 @@ enum AdminCommand {
|
|||
/// Print database memory usage statistics
|
||||
MemoryUsage,
|
||||
|
||||
/// Clears all of Grapevine's database caches with index smaller than the amount
|
||||
ClearDatabaseCaches { amount: u32 },
|
||||
/// Clears all of Grapevine's database caches with index smaller than the
|
||||
/// amount
|
||||
ClearDatabaseCaches {
|
||||
amount: u32,
|
||||
},
|
||||
|
||||
/// Clears all of Grapevine's service caches with index smaller than the amount
|
||||
ClearServiceCaches { amount: u32 },
|
||||
/// Clears all of Grapevine's service caches with index smaller than the
|
||||
/// amount
|
||||
ClearServiceCaches {
|
||||
amount: u32,
|
||||
},
|
||||
|
||||
/// Show configuration values
|
||||
ShowConfig,
|
||||
|
|
@ -162,9 +172,13 @@ enum AdminCommand {
|
|||
},
|
||||
|
||||
/// Disables incoming federation handling for a room.
|
||||
DisableRoom { room_id: Box<RoomId> },
|
||||
DisableRoom {
|
||||
room_id: Box<RoomId>,
|
||||
},
|
||||
/// Enables incoming federation handling for a room again.
|
||||
EnableRoom { room_id: Box<RoomId> },
|
||||
EnableRoom {
|
||||
room_id: Box<RoomId>,
|
||||
},
|
||||
|
||||
/// Verify json signatures
|
||||
/// [commandbody]()
|
||||
|
|
@ -267,31 +281,38 @@ impl Service {
|
|||
}
|
||||
|
||||
pub(crate) fn process_message(&self, room_message: String) {
|
||||
self.sender
|
||||
.send(AdminRoomEvent::ProcessMessage(room_message))
|
||||
.unwrap();
|
||||
self.sender.send(AdminRoomEvent::ProcessMessage(room_message)).unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn send_message(&self, message_content: RoomMessageEventContent) {
|
||||
self.sender
|
||||
.send(AdminRoomEvent::SendMessage(message_content))
|
||||
.unwrap();
|
||||
pub(crate) fn send_message(
|
||||
&self,
|
||||
message_content: RoomMessageEventContent,
|
||||
) {
|
||||
self.sender.send(AdminRoomEvent::SendMessage(message_content)).unwrap();
|
||||
}
|
||||
|
||||
// Parse and process a message from the admin room
|
||||
async fn process_admin_message(&self, room_message: String) -> RoomMessageEventContent {
|
||||
async fn process_admin_message(
|
||||
&self,
|
||||
room_message: String,
|
||||
) -> RoomMessageEventContent {
|
||||
let mut lines = room_message.lines().filter(|l| !l.trim().is_empty());
|
||||
let command_line = lines.next().expect("each string has at least one line");
|
||||
let command_line =
|
||||
lines.next().expect("each string has at least one line");
|
||||
let body: Vec<_> = lines.collect();
|
||||
|
||||
let admin_command = match Self::parse_admin_command(command_line) {
|
||||
Ok(command) => command,
|
||||
Err(error) => {
|
||||
let server_name = services().globals.server_name();
|
||||
let message = error.replace("server.name", server_name.as_str());
|
||||
let message =
|
||||
error.replace("server.name", server_name.as_str());
|
||||
let html_message = Self::usage_to_html(&message, server_name);
|
||||
|
||||
return RoomMessageEventContent::text_html(message, html_message);
|
||||
return RoomMessageEventContent::text_html(
|
||||
message,
|
||||
html_message,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -299,22 +320,28 @@ impl Service {
|
|||
Ok(reply_message) => reply_message,
|
||||
Err(error) => {
|
||||
let markdown_message = format!(
|
||||
"Encountered an error while handling the command:\n\
|
||||
```\n{error}\n```",
|
||||
"Encountered an error while handling the \
|
||||
command:\n```\n{error}\n```",
|
||||
);
|
||||
let html_message = format!(
|
||||
"Encountered an error while handling the command:\n\
|
||||
<pre>\n{error}\n</pre>",
|
||||
"Encountered an error while handling the \
|
||||
command:\n<pre>\n{error}\n</pre>",
|
||||
);
|
||||
|
||||
RoomMessageEventContent::text_html(markdown_message, html_message)
|
||||
RoomMessageEventContent::text_html(
|
||||
markdown_message,
|
||||
html_message,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse chat messages from the admin room into an AdminCommand object
|
||||
fn parse_admin_command(command_line: &str) -> std::result::Result<AdminCommand, String> {
|
||||
// Note: argv[0] is `@grapevine:servername:`, which is treated as the main command
|
||||
fn parse_admin_command(
|
||||
command_line: &str,
|
||||
) -> std::result::Result<AdminCommand, String> {
|
||||
// Note: argv[0] is `@grapevine:servername:`, which is treated as the
|
||||
// main command
|
||||
let mut argv: Vec<_> = command_line.split_whitespace().collect();
|
||||
|
||||
// Replace `help command` with `command --help`
|
||||
|
|
@ -342,18 +369,26 @@ impl Service {
|
|||
) -> Result<RoomMessageEventContent> {
|
||||
let reply_message_content = match command {
|
||||
AdminCommand::RegisterAppservice => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
if body.len() > 2
|
||||
&& body[0].trim() == "```"
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let appservice_config = body[1..body.len() - 1].join("\n");
|
||||
let parsed_config = serde_yaml::from_str::<Registration>(&appservice_config);
|
||||
let parsed_config = serde_yaml::from_str::<Registration>(
|
||||
&appservice_config,
|
||||
);
|
||||
match parsed_config {
|
||||
Ok(yaml) => match services().appservice.register_appservice(yaml).await {
|
||||
Ok(id) => RoomMessageEventContent::text_plain(format!(
|
||||
"Appservice registered with ID: {id}."
|
||||
)),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to register appservice: {e}"
|
||||
)),
|
||||
Ok(yaml) => match services()
|
||||
.appservice
|
||||
.register_appservice(yaml)
|
||||
.await
|
||||
{
|
||||
Ok(id) => RoomMessageEventContent::text_plain(
|
||||
format!("Appservice registered with ID: {id}."),
|
||||
),
|
||||
Err(e) => RoomMessageEventContent::text_plain(
|
||||
format!("Failed to register appservice: {e}"),
|
||||
),
|
||||
},
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Could not parse appservice config: {e}"
|
||||
|
|
@ -361,7 +396,8 @@ impl Service {
|
|||
}
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain(
|
||||
"Expected code block in command body. Add --help for details.",
|
||||
"Expected code block in command body. Add --help for \
|
||||
details.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -372,7 +408,9 @@ impl Service {
|
|||
.unregister_appservice(&appservice_identifier)
|
||||
.await
|
||||
{
|
||||
Ok(()) => RoomMessageEventContent::text_plain("Appservice unregistered."),
|
||||
Ok(()) => RoomMessageEventContent::text_plain(
|
||||
"Appservice unregistered.",
|
||||
),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to unregister appservice: {e}"
|
||||
)),
|
||||
|
|
@ -407,17 +445,25 @@ impl Service {
|
|||
);
|
||||
RoomMessageEventContent::text_plain(output)
|
||||
}
|
||||
AdminCommand::ListLocalUsers => match services().users.list_local_users() {
|
||||
AdminCommand::ListLocalUsers => 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().await;
|
||||
let mut msg: String = format!("Handling {} incoming pdus:\n", map.len());
|
||||
let map =
|
||||
services().globals.roomid_federationhandletime.read().await;
|
||||
let mut msg: String =
|
||||
format!("Handling {} incoming pdus:\n", map.len());
|
||||
|
||||
for (r, (e, i)) in map.iter() {
|
||||
let elapsed = i.elapsed();
|
||||
|
|
@ -431,17 +477,26 @@ impl Service {
|
|||
}
|
||||
RoomMessageEventContent::text_plain(&msg)
|
||||
}
|
||||
AdminCommand::GetAuthChain { event_id } => {
|
||||
AdminCommand::GetAuthChain {
|
||||
event_id,
|
||||
} => {
|
||||
let event_id = Arc::<EventId>::from(event_id);
|
||||
if let Some(event) = services().rooms.timeline.get_pdu_json(&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"))?;
|
||||
.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 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
|
||||
|
|
@ -458,29 +513,47 @@ impl Service {
|
|||
}
|
||||
}
|
||||
AdminCommand::ParsePdu => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
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) {
|
||||
match ruma::signatures::reference_hash(
|
||||
&value,
|
||||
&RoomVersionId::V6,
|
||||
) {
|
||||
Ok(hash) => {
|
||||
let event_id = EventId::parse(format!("${hash}"));
|
||||
let event_id =
|
||||
EventId::parse(format!("${hash}"));
|
||||
|
||||
match serde_json::from_value::<PduEvent>(
|
||||
serde_json::to_value(value).expect("value is json"),
|
||||
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}"
|
||||
)),
|
||||
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!("Could not parse PDU JSON: {e:?}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
|
|
@ -488,10 +561,14 @@ impl Service {
|
|||
)),
|
||||
}
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain("Expected code block in command body.")
|
||||
RoomMessageEventContent::text_plain(
|
||||
"Expected code block in command body.",
|
||||
)
|
||||
}
|
||||
}
|
||||
AdminCommand::GetPdu { event_id } => {
|
||||
AdminCommand::GetPdu {
|
||||
event_id,
|
||||
} => {
|
||||
let mut outlier = false;
|
||||
let mut pdu_json = services()
|
||||
.rooms
|
||||
|
|
@ -499,7 +576,8 @@ impl Service {
|
|||
.get_non_outlier_pdu_json(&event_id)?;
|
||||
if pdu_json.is_none() {
|
||||
outlier = true;
|
||||
pdu_json = services().rooms.timeline.get_pdu_json(&event_id)?;
|
||||
pdu_json =
|
||||
services().rooms.timeline.get_pdu_json(&event_id)?;
|
||||
}
|
||||
match pdu_json {
|
||||
Some(json) => {
|
||||
|
|
@ -516,7 +594,8 @@ impl Service {
|
|||
json_text
|
||||
),
|
||||
format!(
|
||||
"<p>{}</p>\n<pre><code class=\"language-json\">{}\n</code></pre>\n",
|
||||
"<p>{}</p>\n<pre><code \
|
||||
class=\"language-json\">{}\n</code></pre>\n",
|
||||
if outlier {
|
||||
"PDU is outlier"
|
||||
} else {
|
||||
|
|
@ -526,7 +605,9 @@ impl Service {
|
|||
),
|
||||
)
|
||||
}
|
||||
None => RoomMessageEventContent::text_plain("PDU not found."),
|
||||
None => {
|
||||
RoomMessageEventContent::text_plain("PDU not found.")
|
||||
}
|
||||
}
|
||||
}
|
||||
AdminCommand::MemoryUsage => {
|
||||
|
|
@ -537,30 +618,42 @@ impl Service {
|
|||
"Services:\n{response1}\n\nDatabase:\n{response2}"
|
||||
))
|
||||
}
|
||||
AdminCommand::ClearDatabaseCaches { amount } => {
|
||||
AdminCommand::ClearDatabaseCaches {
|
||||
amount,
|
||||
} => {
|
||||
services().globals.db.clear_caches(amount);
|
||||
|
||||
RoomMessageEventContent::text_plain("Done.")
|
||||
}
|
||||
AdminCommand::ClearServiceCaches { amount } => {
|
||||
AdminCommand::ClearServiceCaches {
|
||||
amount,
|
||||
} => {
|
||||
services().clear_caches(amount).await;
|
||||
|
||||
RoomMessageEventContent::text_plain("Done.")
|
||||
}
|
||||
AdminCommand::ShowConfig => {
|
||||
// Construct and send the response
|
||||
RoomMessageEventContent::text_plain(format!("{}", services().globals.config))
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"{}",
|
||||
services().globals.config
|
||||
))
|
||||
}
|
||||
AdminCommand::ResetPassword { username } => {
|
||||
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}"
|
||||
)))
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
format!(
|
||||
"The supplied username is not a valid \
|
||||
username: {e}"
|
||||
),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -589,23 +682,29 @@ impl Service {
|
|||
));
|
||||
}
|
||||
|
||||
let new_password = utils::random_string(AUTO_GEN_PASSWORD_LENGTH);
|
||||
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}"
|
||||
"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 } => {
|
||||
let password =
|
||||
password.unwrap_or_else(|| utils::random_string(AUTO_GEN_PASSWORD_LENGTH));
|
||||
AdminCommand::CreateUser {
|
||||
username,
|
||||
password,
|
||||
} => {
|
||||
let password = password.unwrap_or_else(|| {
|
||||
utils::random_string(AUTO_GEN_PASSWORD_LENGTH)
|
||||
});
|
||||
// Validate user id
|
||||
let user_id = match UserId::parse_with_server_name(
|
||||
username.as_str().to_lowercase(),
|
||||
|
|
@ -613,9 +712,12 @@ impl Service {
|
|||
) {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"The supplied username is not a valid username: {e}"
|
||||
)))
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
format!(
|
||||
"The supplied username is not a valid \
|
||||
username: {e}"
|
||||
),
|
||||
))
|
||||
}
|
||||
};
|
||||
if user_id.is_historical() {
|
||||
|
|
@ -647,24 +749,32 @@ impl Service {
|
|||
.into(),
|
||||
&serde_json::to_value(PushRulesEvent {
|
||||
content: PushRulesEventContent {
|
||||
global: ruma::push::Ruleset::server_default(&user_id),
|
||||
global: ruma::push::Ruleset::server_default(
|
||||
&user_id,
|
||||
),
|
||||
},
|
||||
})
|
||||
.expect("to json value always works"),
|
||||
)?;
|
||||
|
||||
// we dont add a device since we're not the user, just the creator
|
||||
// we dont add a device since we're not the user, just the
|
||||
// creator
|
||||
|
||||
// Inhibit login does not work for guests
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"Created user with user_id: {user_id} and password: {password}"
|
||||
"Created user with user_id: {user_id} and password: \
|
||||
{password}"
|
||||
))
|
||||
}
|
||||
AdminCommand::DisableRoom { room_id } => {
|
||||
AdminCommand::DisableRoom {
|
||||
room_id,
|
||||
} => {
|
||||
services().rooms.metadata.disable_room(&room_id, true)?;
|
||||
RoomMessageEventContent::text_plain("Room disabled.")
|
||||
}
|
||||
AdminCommand::EnableRoom { room_id } => {
|
||||
AdminCommand::EnableRoom {
|
||||
room_id,
|
||||
} => {
|
||||
services().rooms.metadata.disable_room(&room_id, false)?;
|
||||
RoomMessageEventContent::text_plain("Room enabled.")
|
||||
}
|
||||
|
|
@ -677,13 +787,16 @@ impl Service {
|
|||
RoomMessageEventContent::text_plain(format!(
|
||||
"User {user_id} doesn't exist on this server"
|
||||
))
|
||||
} else if user_id.server_name() != services().globals.server_name() {
|
||||
} else if user_id.server_name()
|
||||
!= services().globals.server_name()
|
||||
{
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"User {user_id} is not from this server"
|
||||
))
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"Making {user_id} leave all rooms before deactivation..."
|
||||
"Making {user_id} leave all rooms before \
|
||||
deactivation..."
|
||||
));
|
||||
|
||||
services().users.deactivate_account(&user_id)?;
|
||||
|
|
@ -697,10 +810,18 @@ impl Service {
|
|||
))
|
||||
}
|
||||
}
|
||||
AdminCommand::DeactivateAll { leave_rooms, force } => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
AdminCommand::DeactivateAll {
|
||||
leave_rooms,
|
||||
force,
|
||||
} => {
|
||||
if body.len() > 2
|
||||
&& body[0].trim() == "```"
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let users = body.clone().drain(1..body.len() - 1).collect::<Vec<_>>();
|
||||
let users = body
|
||||
.clone()
|
||||
.drain(1..body.len() - 1)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut user_ids = Vec::new();
|
||||
let mut remote_ids = Vec::new();
|
||||
|
|
@ -710,7 +831,9 @@ impl Service {
|
|||
for &user in &users {
|
||||
match <&UserId>::try_from(user) {
|
||||
Ok(user_id) => {
|
||||
if user_id.server_name() != services().globals.server_name() {
|
||||
if user_id.server_name()
|
||||
!= services().globals.server_name()
|
||||
{
|
||||
remote_ids.push(user_id);
|
||||
} else if !services().users.exists(user_id)? {
|
||||
non_existant_ids.push(user_id);
|
||||
|
|
@ -727,39 +850,59 @@ impl Service {
|
|||
let mut markdown_message = String::new();
|
||||
let mut html_message = String::new();
|
||||
if !invalid_users.is_empty() {
|
||||
markdown_message.push_str("The following user ids are not valid:\n```\n");
|
||||
html_message.push_str("The following user ids are not valid:\n<pre>\n");
|
||||
markdown_message.push_str(
|
||||
"The following user ids are not valid:\n```\n",
|
||||
);
|
||||
html_message.push_str(
|
||||
"The following user ids are not valid:\n<pre>\n",
|
||||
);
|
||||
for invalid_user in invalid_users {
|
||||
writeln!(markdown_message, "{invalid_user}")
|
||||
.expect("write to in-memory buffer should succeed");
|
||||
writeln!(html_message, "{invalid_user}")
|
||||
.expect("write to in-memory buffer should succeed");
|
||||
.expect(
|
||||
"write to in-memory buffer should succeed",
|
||||
);
|
||||
writeln!(html_message, "{invalid_user}").expect(
|
||||
"write to in-memory buffer should succeed",
|
||||
);
|
||||
}
|
||||
markdown_message.push_str("```\n\n");
|
||||
html_message.push_str("</pre>\n\n");
|
||||
}
|
||||
if !remote_ids.is_empty() {
|
||||
markdown_message
|
||||
.push_str("The following users are not from this server:\n```\n");
|
||||
html_message
|
||||
.push_str("The following users are not from this server:\n<pre>\n");
|
||||
markdown_message.push_str(
|
||||
"The following users are not from this \
|
||||
server:\n```\n",
|
||||
);
|
||||
html_message.push_str(
|
||||
"The following users are not from this \
|
||||
server:\n<pre>\n",
|
||||
);
|
||||
for remote_id in remote_ids {
|
||||
writeln!(markdown_message, "{remote_id}")
|
||||
.expect("write to in-memory buffer should succeed");
|
||||
writeln!(html_message, "{remote_id}")
|
||||
.expect("write to in-memory buffer should succeed");
|
||||
writeln!(markdown_message, "{remote_id}").expect(
|
||||
"write to in-memory buffer should succeed",
|
||||
);
|
||||
writeln!(html_message, "{remote_id}").expect(
|
||||
"write to in-memory buffer should succeed",
|
||||
);
|
||||
}
|
||||
markdown_message.push_str("```\n\n");
|
||||
html_message.push_str("</pre>\n\n");
|
||||
}
|
||||
if !non_existant_ids.is_empty() {
|
||||
markdown_message.push_str("The following users do not exist:\n```\n");
|
||||
html_message.push_str("The following users do not exist:\n<pre>\n");
|
||||
markdown_message.push_str(
|
||||
"The following users do not exist:\n```\n",
|
||||
);
|
||||
html_message.push_str(
|
||||
"The following users do not exist:\n<pre>\n",
|
||||
);
|
||||
for non_existant_id in non_existant_ids {
|
||||
writeln!(markdown_message, "{non_existant_id}")
|
||||
.expect("write to in-memory buffer should succeed");
|
||||
writeln!(html_message, "{non_existant_id}")
|
||||
.expect("write to in-memory buffer should succeed");
|
||||
.expect(
|
||||
"write to in-memory buffer should succeed",
|
||||
);
|
||||
writeln!(html_message, "{non_existant_id}").expect(
|
||||
"write to in-memory buffer should succeed",
|
||||
);
|
||||
}
|
||||
markdown_message.push_str("```\n\n");
|
||||
html_message.push_str("</pre>\n\n");
|
||||
|
|
@ -775,21 +918,24 @@ impl Service {
|
|||
let mut admins = Vec::new();
|
||||
|
||||
if !force {
|
||||
user_ids.retain(|&user_id| match services().users.is_admin(user_id) {
|
||||
Ok(is_admin) => {
|
||||
if is_admin {
|
||||
admins.push(user_id.localpart());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
user_ids.retain(|&user_id| {
|
||||
match services().users.is_admin(user_id) {
|
||||
Ok(is_admin) => {
|
||||
if is_admin {
|
||||
admins.push(user_id.localpart());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
Err(_) => false,
|
||||
});
|
||||
}
|
||||
|
||||
for &user_id in &user_ids {
|
||||
if services().users.deactivate_account(user_id).is_ok() {
|
||||
if services().users.deactivate_account(user_id).is_ok()
|
||||
{
|
||||
deactivation_count += 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -807,16 +953,25 @@ impl Service {
|
|||
"Deactivated {deactivation_count} accounts."
|
||||
))
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain(format!("Deactivated {} accounts.\nSkipped admin accounts: {:?}. Use --force to deactivate admin accounts", deactivation_count, admins.join(", ")))
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"Deactivated {} accounts.\nSkipped admin \
|
||||
accounts: {:?}. Use --force to deactivate admin \
|
||||
accounts",
|
||||
deactivation_count,
|
||||
admins.join(", ")
|
||||
))
|
||||
}
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain(
|
||||
"Expected code block in command body. Add --help for details.",
|
||||
"Expected code block in command body. Add --help for \
|
||||
details.",
|
||||
)
|
||||
}
|
||||
}
|
||||
AdminCommand::SignJson => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
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) {
|
||||
|
|
@ -827,20 +982,26 @@ impl Service {
|
|||
&mut value,
|
||||
)
|
||||
.expect("our request json is what ruma expects");
|
||||
let json_text = serde_json::to_string_pretty(&value)
|
||||
.expect("canonical json is valid json");
|
||||
let json_text =
|
||||
serde_json::to_string_pretty(&value)
|
||||
.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(
|
||||
"Expected code block in command body. Add --help for details.",
|
||||
"Expected code block in command body. Add --help for \
|
||||
details.",
|
||||
)
|
||||
}
|
||||
}
|
||||
AdminCommand::VerifyJson => {
|
||||
if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```"
|
||||
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) {
|
||||
|
|
@ -850,22 +1011,35 @@ impl Service {
|
|||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_required_signing_keys(&value, &pub_key_map)
|
||||
.fetch_required_signing_keys(
|
||||
&value,
|
||||
&pub_key_map,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let pub_key_map = pub_key_map.read().await;
|
||||
match ruma::signatures::verify_json(&pub_key_map, &value) {
|
||||
Ok(()) => RoomMessageEventContent::text_plain("Signature correct"),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Signature verification failed: {e}"
|
||||
)),
|
||||
match ruma::signatures::verify_json(
|
||||
&pub_key_map,
|
||||
&value,
|
||||
) {
|
||||
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(
|
||||
"Expected code block in command body. Add --help for details.",
|
||||
"Expected code block in command body. Add --help for \
|
||||
details.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -876,7 +1050,8 @@ impl Service {
|
|||
|
||||
// Utility to turn clap's `--help` text to HTML.
|
||||
fn usage_to_html(text: &str, server_name: &ServerName) -> String {
|
||||
// Replace `@grapevine:servername:-subcmdname` with `@grapevine:servername: subcmdname`
|
||||
// Replace `@grapevine:servername:-subcmdname` with
|
||||
// `@grapevine:servername: subcmdname`
|
||||
let localpart = if services().globals.config.conduit_compat {
|
||||
"conduit"
|
||||
} else {
|
||||
|
|
@ -892,11 +1067,13 @@ impl Service {
|
|||
let text = text.replace("SUBCOMMAND", "COMMAND");
|
||||
let text = text.replace("subcommand", "command");
|
||||
|
||||
// Escape option names (e.g. `<element-id>`) since they look like HTML tags
|
||||
// Escape option names (e.g. `<element-id>`) since they look like HTML
|
||||
// tags
|
||||
let text = text.replace('<', "<").replace('>', ">");
|
||||
|
||||
// Italicize the first line (command name and version text)
|
||||
let re = Regex::new("^(.*?)\n").expect("Regex compilation should not fail");
|
||||
let re =
|
||||
Regex::new("^(.*?)\n").expect("Regex compilation should not fail");
|
||||
let text = re.replace_all(&text, "<em>$1</em>\n");
|
||||
|
||||
// Unmerge wrapped lines
|
||||
|
|
@ -911,8 +1088,8 @@ impl Service {
|
|||
.expect("Regex compilation should not fail");
|
||||
let text = re.replace_all(&text, "<code>$1</code>: $4");
|
||||
|
||||
// Look for a `[commandbody]()` tag. If it exists, use all lines below it that
|
||||
// start with a `#` in the USAGE section.
|
||||
// Look for a `[commandbody]()` tag. If it exists, use all lines below
|
||||
// it that start with a `#` in the USAGE section.
|
||||
let mut text_lines: Vec<&str> = text.lines().collect();
|
||||
let command_body = text_lines
|
||||
.iter()
|
||||
|
|
@ -936,8 +1113,11 @@ impl Service {
|
|||
// This makes the usage of e.g. `register-appservice` more accurate
|
||||
let re = Regex::new("(?m)^USAGE:\n (.*?)\n\n")
|
||||
.expect("Regex compilation should not fail");
|
||||
re.replace_all(&text, "USAGE:\n<pre>$1[nobr]\n[commandbodyblock]</pre>")
|
||||
.replace("[commandbodyblock]", &command_body)
|
||||
re.replace_all(
|
||||
&text,
|
||||
"USAGE:\n<pre>$1[nobr]\n[commandbodyblock]</pre>",
|
||||
)
|
||||
.replace("[commandbodyblock]", &command_body)
|
||||
};
|
||||
|
||||
// Add HTML line-breaks
|
||||
|
|
@ -949,8 +1129,9 @@ impl Service {
|
|||
|
||||
/// Create the admin room.
|
||||
///
|
||||
/// Users in this room are considered admins by grapevine, and the room can be
|
||||
/// used to issue admin commands by talking to the server user inside it.
|
||||
/// Users in this room are considered admins by grapevine, and the room can
|
||||
/// be used to issue admin commands by talking to the server user inside
|
||||
/// it.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub(crate) async fn create_admin_room(&self) -> Result<()> {
|
||||
let room_id = RoomId::new(services().globals.server_name());
|
||||
|
|
@ -993,7 +1174,9 @@ impl Service {
|
|||
| RoomVersionId::V7
|
||||
| RoomVersionId::V8
|
||||
| RoomVersionId::V9
|
||||
| RoomVersionId::V10 => RoomCreateEventContent::new_v1(grapevine_user.clone()),
|
||||
| RoomVersionId::V10 => {
|
||||
RoomCreateEventContent::new_v1(grapevine_user.clone())
|
||||
}
|
||||
RoomVersionId::V11 => RoomCreateEventContent::new_v11(),
|
||||
_ => unreachable!("Validity of room version already checked"),
|
||||
};
|
||||
|
|
@ -1008,7 +1191,8 @@ impl Service {
|
|||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomCreate,
|
||||
content: to_raw_value(&content).expect("event is valid, we just created it"),
|
||||
content: to_raw_value(&content)
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
|
|
@ -1079,8 +1263,10 @@ impl Service {
|
|||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomJoinRules,
|
||||
content: to_raw_value(&RoomJoinRulesEventContent::new(JoinRule::Invite))
|
||||
.expect("event is valid, we just created it"),
|
||||
content: to_raw_value(&RoomJoinRulesEventContent::new(
|
||||
JoinRule::Invite,
|
||||
))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
|
|
@ -1098,9 +1284,11 @@ impl Service {
|
|||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomHistoryVisibility,
|
||||
content: to_raw_value(&RoomHistoryVisibilityEventContent::new(
|
||||
HistoryVisibility::Shared,
|
||||
))
|
||||
content: to_raw_value(
|
||||
&RoomHistoryVisibilityEventContent::new(
|
||||
HistoryVisibility::Shared,
|
||||
),
|
||||
)
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(String::new()),
|
||||
|
|
@ -1134,15 +1322,18 @@ impl Service {
|
|||
.await?;
|
||||
|
||||
// 5. Events implied by name and topic
|
||||
let room_name = format!("{} Admin Room", services().globals.server_name());
|
||||
let room_name =
|
||||
format!("{} Admin Room", services().globals.server_name());
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomName,
|
||||
content: to_raw_value(&RoomNameEventContent::new(room_name))
|
||||
.expect("event is valid, we just created it"),
|
||||
content: to_raw_value(&RoomNameEventContent::new(
|
||||
room_name,
|
||||
))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
|
|
@ -1160,7 +1351,10 @@ impl Service {
|
|||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomTopic,
|
||||
content: to_raw_value(&RoomTopicEventContent {
|
||||
topic: format!("Manage {}", services().globals.server_name()),
|
||||
topic: format!(
|
||||
"Manage {}",
|
||||
services().globals.server_name()
|
||||
),
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
|
|
@ -1174,9 +1368,10 @@ impl Service {
|
|||
.await?;
|
||||
|
||||
// 6. Room alias
|
||||
let alias: OwnedRoomAliasId = format!("#admins:{}", services().globals.server_name())
|
||||
.try_into()
|
||||
.expect("#admins:server_name is a valid alias name");
|
||||
let alias: OwnedRoomAliasId =
|
||||
format!("#admins:{}", services().globals.server_name())
|
||||
.try_into()
|
||||
.expect("#admins:server_name is a valid alias name");
|
||||
|
||||
services()
|
||||
.rooms
|
||||
|
|
@ -1206,7 +1401,8 @@ impl Service {
|
|||
|
||||
/// Gets the room ID of the admin room
|
||||
///
|
||||
/// Errors are propagated from the database, and will have None if there is no admin room
|
||||
/// Errors are propagated from the database, and will have None if there is
|
||||
/// no admin room
|
||||
// Allowed because this function uses `services()`
|
||||
#[allow(clippy::unused_self)]
|
||||
pub(crate) fn get_admin_room(&self) -> Result<Option<OwnedRoomId>> {
|
||||
|
|
@ -1215,10 +1411,7 @@ impl Service {
|
|||
.try_into()
|
||||
.expect("#admins:server_name is a valid alias name");
|
||||
|
||||
services()
|
||||
.rooms
|
||||
.alias
|
||||
.resolve_local_alias(&admin_room_alias)
|
||||
services().rooms.alias.resolve_local_alias(&admin_room_alias)
|
||||
}
|
||||
|
||||
/// Invite the user to the grapevine admin room.
|
||||
|
|
@ -1356,11 +1549,13 @@ mod test {
|
|||
}
|
||||
|
||||
fn get_help_inner(input: &str) {
|
||||
let error = AdminCommand::try_parse_from(["argv[0] doesn't matter", input])
|
||||
.unwrap_err()
|
||||
.to_string();
|
||||
let error =
|
||||
AdminCommand::try_parse_from(["argv[0] doesn't matter", input])
|
||||
.unwrap_err()
|
||||
.to_string();
|
||||
|
||||
// Search for a handful of keywords that suggest the help printed properly
|
||||
// Search for a handful of keywords that suggest the help printed
|
||||
// properly
|
||||
assert!(error.contains("Usage:"));
|
||||
assert!(error.contains("Commands:"));
|
||||
assert!(error.contains("Options:"));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue