apply new rustfmt.toml changes, fix some clippy lints

Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
strawberry 2024-12-15 00:05:47 -05:00
parent 0317cc8cc5
commit 77e0b76408
No known key found for this signature in database
296 changed files with 7147 additions and 4300 deletions

View file

@ -21,3 +21,4 @@ indent_size = 2
[*.rs]
indent_style = tab
max_line_length = 98

View file

@ -3,7 +3,7 @@ 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 = 196608 # reduce me ALARA
too-many-lines-threshold = 700 # TODO reduce me to <= 100
too-many-lines-threshold = 780 # TODO reduce me to <= 100
type-complexity-threshold = 250 # reduce me to ~200
disallowed-macros = [
@ -13,3 +13,7 @@ disallowed-macros = [
{ path = "log::debug", reason = "use conduwuit_core::debug" },
{ path = "log::trace", reason = "use conduwuit_core::trace" },
]
disallowed-methods = [
{ path = "tokio::spawn", reason = "use and pass conduuwit_core::server::Server::runtime() to spawn from"},
]

View file

@ -2,9 +2,8 @@ array_width = 80
chain_width = 60
comment_width = 80
condense_wildcard_suffixes = true
edition = "2021"
edition = "2024"
fn_call_width = 80
fn_params_layout = "Compressed"
fn_single_line = true
format_code_in_doc_comments = true
format_macro_bodies = true
@ -14,13 +13,20 @@ group_imports = "StdExternalCrate"
hard_tabs = true
hex_literal_case = "Upper"
imports_granularity = "Crate"
match_arm_blocks = false
match_arm_leading_pipes = "Always"
match_block_trailing_comma = true
max_width = 120
max_width = 98
newline_style = "Unix"
normalize_comments = false
overflow_delimited_expr = true
reorder_impl_items = true
reorder_imports = true
single_line_if_else_max_width = 60
single_line_let_else_max_width = 80
struct_lit_width = 40
tab_spaces = 4
unstable_features = true
use_field_init_shorthand = true
use_small_heuristics = "Off"
use_try_shorthand = true

View file

@ -3,9 +3,10 @@ use conduwuit::Result;
use ruma::events::room::message::RoomMessageEventContent;
use crate::{
appservice, appservice::AppserviceCommand, check, check::CheckCommand, command::Command, debug,
debug::DebugCommand, federation, federation::FederationCommand, media, media::MediaCommand, query,
query::QueryCommand, room, room::RoomCommand, server, server::ServerCommand, user, user::UserCommand,
appservice, appservice::AppserviceCommand, check, check::CheckCommand, command::Command,
debug, debug::DebugCommand, federation, federation::FederationCommand, media,
media::MediaCommand, query, query::QueryCommand, room, room::RoomCommand, server,
server::ServerCommand, user, user::UserCommand,
};
#[derive(Debug, Parser)]
@ -49,18 +50,21 @@ pub(super) enum AdminCommand {
}
#[tracing::instrument(skip_all, name = "command")]
pub(super) async fn process(command: AdminCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
command: AdminCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
use AdminCommand::*;
Ok(match command {
Appservices(command) => appservice::process(command, context).await?,
Media(command) => media::process(command, context).await?,
Users(command) => user::process(command, context).await?,
Rooms(command) => room::process(command, context).await?,
Federation(command) => federation::process(command, context).await?,
Server(command) => server::process(command, context).await?,
Debug(command) => debug::process(command, context).await?,
Query(command) => query::process(command, context).await?,
Check(command) => check::process(command, context).await?,
| Appservices(command) => appservice::process(command, context).await?,
| Media(command) => media::process(command, context).await?,
| Users(command) => user::process(command, context).await?,
| Rooms(command) => room::process(command, context).await?,
| Federation(command) => federation::process(command, context).await?,
| Server(command) => server::process(command, context).await?,
| Debug(command) => debug::process(command, context).await?,
| Query(command) => query::process(command, context).await?,
| Check(command) => check::process(command, context).await?,
})
}

View file

@ -4,7 +4,9 @@ use crate::{admin_command, Result};
#[admin_command]
pub(super) async fn register(&self) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
@ -14,55 +16,63 @@ pub(super) async fn register(&self) -> Result<RoomMessageEventContent> {
let appservice_config_body = self.body[1..self.body.len().checked_sub(1).unwrap()].join("\n");
let parsed_config = serde_yaml::from_str::<Registration>(&appservice_config_body);
match parsed_config {
Ok(registration) => match self
| Ok(registration) => match self
.services
.appservice
.register_appservice(&registration, &appservice_config_body)
.await
{
Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
| Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
"Appservice registered with ID: {}",
registration.id
))),
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to register appservice: {e}"
))),
},
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Could not parse appservice config as YAML: {e}"
))),
}
}
#[admin_command]
pub(super) async fn unregister(&self, appservice_identifier: String) -> Result<RoomMessageEventContent> {
pub(super) async fn unregister(
&self,
appservice_identifier: String,
) -> Result<RoomMessageEventContent> {
match self
.services
.appservice
.unregister_appservice(&appservice_identifier)
.await
{
Ok(()) => Ok(RoomMessageEventContent::text_plain("Appservice unregistered.")),
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
| Ok(()) => Ok(RoomMessageEventContent::text_plain("Appservice unregistered.")),
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to unregister appservice: {e}"
))),
}
}
#[admin_command]
pub(super) async fn show_appservice_config(&self, appservice_identifier: String) -> Result<RoomMessageEventContent> {
pub(super) async fn show_appservice_config(
&self,
appservice_identifier: String,
) -> Result<RoomMessageEventContent> {
match self
.services
.appservice
.get_registration(&appservice_identifier)
.await
{
Some(config) => {
let config_str = serde_yaml::to_string(&config).expect("config should've been validated on register");
let output = format!("Config for {appservice_identifier}:\n\n```yaml\n{config_str}\n```",);
| Some(config) => {
let config_str = serde_yaml::to_string(&config)
.expect("config should've been validated on register");
let output =
format!("Config for {appservice_identifier}:\n\n```yaml\n{config_str}\n```",);
Ok(RoomMessageEventContent::notice_markdown(output))
},
None => Ok(RoomMessageEventContent::text_plain("Appservice does not exist.")),
| None => Ok(RoomMessageEventContent::text_plain("Appservice does not exist.")),
}
}

View file

@ -19,8 +19,9 @@ pub(super) async fn check_all_users(&self) -> Result<RoomMessageEventContent> {
let ok_count = users.iter().filter(|_user| true).count();
let message = format!(
"Database query completed in {query_time:?}:\n\n```\nTotal entries: {total:?}\nFailure/Invalid user count: \
{err_count:?}\nSuccess/Valid user count: {ok_count:?}\n```"
"Database query completed in {query_time:?}:\n\n```\nTotal entries: \
{total:?}\nFailure/Invalid user count: {err_count:?}\nSuccess/Valid user count: \
{ok_count:?}\n```"
);
Ok(RoomMessageEventContent::notice_markdown(message))

View file

@ -11,8 +11,11 @@ pub(super) enum CheckCommand {
AllUsers,
}
pub(super) async fn process(command: CheckCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
command: CheckCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
Ok(match command {
CheckCommand::AllUsers => context.check_all_users().await?,
| CheckCommand::AllUsers => context.check_all_users().await?,
})
}

View file

@ -6,7 +6,9 @@ use std::{
time::{Instant, SystemTime},
};
use conduwuit::{debug_error, err, info, trace, utils, utils::string::EMPTY, warn, Error, PduEvent, Result};
use conduwuit::{
debug_error, err, info, trace, utils, utils::string::EMPTY, warn, Error, PduEvent, Result,
};
use futures::{FutureExt, StreamExt};
use ruma::{
api::{client::error::ErrorKind, federation::event::get_room_state},
@ -26,7 +28,10 @@ pub(super) async fn echo(&self, message: Vec<String>) -> Result<RoomMessageEvent
}
#[admin_command]
pub(super) async fn get_auth_chain(&self, event_id: Box<EventId>) -> Result<RoomMessageEventContent> {
pub(super) async fn get_auth_chain(
&self,
event_id: Box<EventId>,
) -> Result<RoomMessageEventContent> {
let Ok(event) = self.services.rooms.timeline.get_pdu_json(&event_id).await else {
return Ok(RoomMessageEventContent::notice_plain("Event not found."));
};
@ -68,20 +73,26 @@ pub(super) async fn parse_pdu(&self) -> Result<RoomMessageEventContent> {
let string = self.body[1..self.body.len().saturating_sub(1)].join("\n");
match serde_json::from_str(&string) {
Ok(value) => match ruma::signatures::reference_hash(&value, &RoomVersionId::V6) {
Ok(hash) => {
| 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) => Ok(RoomMessageEventContent::text_plain(format!("EventId: {event_id:?}\n{pdu:#?}"))),
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
match serde_json::from_value::<PduEvent>(
serde_json::to_value(value).expect("value is json"),
) {
| Ok(pdu) => Ok(RoomMessageEventContent::text_plain(format!(
"EventId: {event_id:?}\n{pdu:#?}"
))),
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"EventId: {event_id:?}\nCould not parse event: {e}"
))),
}
},
Err(e) => Ok(RoomMessageEventContent::text_plain(format!("Could not parse PDU JSON: {e:?}"))),
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Could not parse PDU JSON: {e:?}"
))),
},
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Invalid json in command body: {e}"
))),
}
@ -103,8 +114,9 @@ pub(super) async fn get_pdu(&self, event_id: Box<EventId>) -> Result<RoomMessage
}
match pdu_json {
Ok(json) => {
let json_text = serde_json::to_string_pretty(&json).expect("canonical json is valid json");
| Ok(json) => {
let json_text =
serde_json::to_string_pretty(&json).expect("canonical json is valid json");
Ok(RoomMessageEventContent::notice_markdown(format!(
"{}\n```json\n{}\n```",
if outlier {
@ -115,13 +127,15 @@ pub(super) async fn get_pdu(&self, event_id: Box<EventId>) -> Result<RoomMessage
json_text
)))
},
Err(_) => Ok(RoomMessageEventContent::text_plain("PDU not found locally.")),
| Err(_) => Ok(RoomMessageEventContent::text_plain("PDU not found locally.")),
}
}
#[admin_command]
pub(super) async fn get_remote_pdu_list(
&self, server: Box<ServerName>, force: bool,
&self,
server: Box<ServerName>,
force: bool,
) -> Result<RoomMessageEventContent> {
if !self.services.globals.config.allow_federation {
return Ok(RoomMessageEventContent::text_plain(
@ -131,8 +145,8 @@ pub(super) async fn get_remote_pdu_list(
if server == self.services.globals.server_name() {
return Ok(RoomMessageEventContent::text_plain(
"Not allowed to send federation requests to ourselves. Please use `get-pdu` for fetching local PDUs from \
the database.",
"Not allowed to send federation requests to ourselves. Please use `get-pdu` for \
fetching local PDUs from the database.",
));
}
@ -184,7 +198,9 @@ pub(super) async fn get_remote_pdu_list(
#[admin_command]
pub(super) async fn get_remote_pdu(
&self, event_id: Box<EventId>, server: Box<ServerName>,
&self,
event_id: Box<EventId>,
server: Box<ServerName>,
) -> Result<RoomMessageEventContent> {
if !self.services.globals.config.allow_federation {
return Ok(RoomMessageEventContent::text_plain(
@ -194,29 +210,31 @@ pub(super) async fn get_remote_pdu(
if server == self.services.globals.server_name() {
return Ok(RoomMessageEventContent::text_plain(
"Not allowed to send federation requests to ourselves. Please use `get-pdu` for fetching local PDUs.",
"Not allowed to send federation requests to ourselves. Please use `get-pdu` for \
fetching local PDUs.",
));
}
match self
.services
.sending
.send_federation_request(
&server,
ruma::api::federation::event::get_event::v1::Request {
.send_federation_request(&server, ruma::api::federation::event::get_event::v1::Request {
event_id: event_id.clone().into(),
include_unredacted_content: None,
},
)
})
.await
{
Ok(response) => {
let json: CanonicalJsonObject = serde_json::from_str(response.pdu.get()).map_err(|e| {
| Ok(response) => {
let json: CanonicalJsonObject =
serde_json::from_str(response.pdu.get()).map_err(|e| {
warn!(
"Requested event ID {event_id} from server but failed to convert from RawValue to \
CanonicalJsonObject (malformed event/response?): {e}"
"Requested event ID {event_id} from server but failed to convert from \
RawValue to CanonicalJsonObject (malformed event/response?): {e}"
);
Error::BadRequest(ErrorKind::Unknown, "Received response from server but failed to parse PDU")
Error::BadRequest(
ErrorKind::Unknown,
"Received response from server but failed to parse PDU",
)
})?;
trace!("Attempting to parse PDU: {:?}", &response.pdu);
@ -229,8 +247,8 @@ pub(super) async fn get_remote_pdu(
.await;
let (event_id, value, room_id) = match parsed_result {
Ok(t) => t,
Err(e) => {
| Ok(t) => t,
| Err(e) => {
warn!("Failed to parse PDU: {e}");
info!("Full PDU: {:?}", &response.pdu);
return Ok(RoomMessageEventContent::text_plain(format!(
@ -250,21 +268,27 @@ pub(super) async fn get_remote_pdu(
.boxed()
.await?;
let json_text = serde_json::to_string_pretty(&json).expect("canonical json is valid json");
let json_text =
serde_json::to_string_pretty(&json).expect("canonical json is valid json");
Ok(RoomMessageEventContent::notice_markdown(format!(
"{}\n```json\n{}\n```",
"Got PDU from specified server and handled as backfilled PDU successfully. Event body:", json_text
"Got PDU from specified server and handled as backfilled PDU successfully. \
Event body:",
json_text
)))
},
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Remote server did not have PDU or failed sending request to remote server: {e}"
))),
}
}
#[admin_command]
pub(super) async fn get_room_state(&self, room: OwnedRoomOrAliasId) -> Result<RoomMessageEventContent> {
pub(super) async fn get_room_state(
&self,
room: OwnedRoomOrAliasId,
) -> Result<RoomMessageEventContent> {
let room_id = self.services.rooms.alias.resolve(&room).await?;
let room_state: Vec<_> = self
.services
@ -285,7 +309,8 @@ pub(super) async fn get_room_state(&self, room: OwnedRoomOrAliasId) -> Result<Ro
let json = serde_json::to_string_pretty(&room_state).map_err(|e| {
warn!("Failed converting room state vector in our database to pretty JSON: {e}");
Error::bad_database(
"Failed to convert room state events to pretty JSON, possible invalid room state events in our database",
"Failed to convert room state events to pretty JSON, possible invalid room state \
events in our database",
)
})?;
@ -305,10 +330,13 @@ pub(super) async fn ping(&self, server: Box<ServerName>) -> Result<RoomMessageEv
match self
.services
.sending
.send_federation_request(&server, ruma::api::federation::discovery::get_server_version::v1::Request {})
.send_federation_request(
&server,
ruma::api::federation::discovery::get_server_version::v1::Request {},
)
.await
{
Ok(response) => {
| Ok(response) => {
let ping_time = timer.elapsed();
let json_text_res = serde_json::to_string_pretty(&response.server);
@ -323,8 +351,11 @@ pub(super) async fn ping(&self, server: Box<ServerName>) -> Result<RoomMessageEv
"Got non-JSON response which took {ping_time:?} time:\n{response:?}"
)))
},
Err(e) => {
warn!("Failed sending federation request to specified server from ping debug command: {e}");
| Err(e) => {
warn!(
"Failed sending federation request to specified server from ping debug command: \
{e}"
);
Ok(RoomMessageEventContent::text_plain(format!(
"Failed sending federation request to specified server:\n\n{e}",
)))
@ -347,13 +378,17 @@ pub(super) async fn force_device_list_updates(&self) -> Result<RoomMessageEventC
}
#[admin_command]
pub(super) async fn change_log_level(&self, filter: Option<String>, reset: bool) -> Result<RoomMessageEventContent> {
pub(super) async fn change_log_level(
&self,
filter: Option<String>,
reset: bool,
) -> Result<RoomMessageEventContent> {
let handles = &["console"];
if reset {
let old_filter_layer = match EnvFilter::try_new(&self.services.globals.config.log) {
Ok(s) => s,
Err(e) => {
| Ok(s) => s,
| Err(e) => {
return Ok(RoomMessageEventContent::text_plain(format!(
"Log level from config appears to be invalid now: {e}"
)));
@ -367,13 +402,13 @@ pub(super) async fn change_log_level(&self, filter: Option<String>, reset: bool)
.reload
.reload(&old_filter_layer, Some(handles))
{
Ok(()) => {
| Ok(()) => {
return Ok(RoomMessageEventContent::text_plain(format!(
"Successfully changed log level back to config value {}",
self.services.globals.config.log
)));
},
Err(e) => {
| Err(e) => {
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to modify and reload the global tracing log level: {e}"
)));
@ -383,8 +418,8 @@ pub(super) async fn change_log_level(&self, filter: Option<String>, reset: bool)
if let Some(filter) = filter {
let new_filter_layer = match EnvFilter::try_new(filter) {
Ok(s) => s,
Err(e) => {
| Ok(s) => s,
| Err(e) => {
return Ok(RoomMessageEventContent::text_plain(format!(
"Invalid log level filter specified: {e}"
)));
@ -398,10 +433,10 @@ pub(super) async fn change_log_level(&self, filter: Option<String>, reset: bool)
.reload
.reload(&new_filter_layer, Some(handles))
{
Ok(()) => {
| Ok(()) => {
return Ok(RoomMessageEventContent::text_plain("Successfully changed log level"));
},
Err(e) => {
| Err(e) => {
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to modify and reload the global tracing log level: {e}"
)));
@ -414,7 +449,9 @@ pub(super) async fn change_log_level(&self, filter: Option<String>, reset: bool)
#[admin_command]
pub(super) async fn sign_json(&self) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
@ -423,21 +460,24 @@ pub(super) async fn sign_json(&self) -> Result<RoomMessageEventContent> {
let string = self.body[1..self.body.len().checked_sub(1).unwrap()].join("\n");
match serde_json::from_str(&string) {
Ok(mut value) => {
| Ok(mut value) => {
self.services
.server_keys
.sign_json(&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");
Ok(RoomMessageEventContent::text_plain(json_text))
},
Err(e) => Ok(RoomMessageEventContent::text_plain(format!("Invalid json: {e}"))),
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!("Invalid json: {e}"))),
}
}
#[admin_command]
pub(super) async fn verify_json(&self) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
@ -446,13 +486,13 @@ pub(super) async fn verify_json(&self) -> Result<RoomMessageEventContent> {
let string = self.body[1..self.body.len().checked_sub(1).unwrap()].join("\n");
match serde_json::from_str::<CanonicalJsonObject>(&string) {
Ok(value) => match self.services.server_keys.verify_json(&value, None).await {
Ok(()) => Ok(RoomMessageEventContent::text_plain("Signature correct")),
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
| Ok(value) => match self.services.server_keys.verify_json(&value, None).await {
| Ok(()) => Ok(RoomMessageEventContent::text_plain("Signature correct")),
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Signature verification failed: {e}"
))),
},
Err(e) => Ok(RoomMessageEventContent::text_plain(format!("Invalid json: {e}"))),
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!("Invalid json: {e}"))),
}
}
@ -462,9 +502,10 @@ pub(super) async fn verify_pdu(&self, event_id: Box<EventId>) -> Result<RoomMess
event.remove("event_id");
let msg = match self.services.server_keys.verify_event(&event, None).await {
Ok(ruma::signatures::Verified::Signatures) => "signatures OK, but content hash failed (redaction).",
Ok(ruma::signatures::Verified::All) => "signatures and hashes OK.",
Err(e) => return Err(e),
| Ok(ruma::signatures::Verified::Signatures) =>
"signatures OK, but content hash failed (redaction).",
| Ok(ruma::signatures::Verified::All) => "signatures and hashes OK.",
| Err(e) => return Err(e),
};
Ok(RoomMessageEventContent::notice_plain(msg))
@ -472,7 +513,10 @@ pub(super) async fn verify_pdu(&self, event_id: Box<EventId>) -> Result<RoomMess
#[admin_command]
#[tracing::instrument(skip(self))]
pub(super) async fn first_pdu_in_room(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
pub(super) async fn first_pdu_in_room(
&self,
room_id: Box<RoomId>,
) -> Result<RoomMessageEventContent> {
if !self
.services
.rooms
@ -498,7 +542,10 @@ pub(super) async fn first_pdu_in_room(&self, room_id: Box<RoomId>) -> Result<Roo
#[admin_command]
#[tracing::instrument(skip(self))]
pub(super) async fn latest_pdu_in_room(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
pub(super) async fn latest_pdu_in_room(
&self,
room_id: Box<RoomId>,
) -> Result<RoomMessageEventContent> {
if !self
.services
.rooms
@ -525,7 +572,9 @@ pub(super) async fn latest_pdu_in_room(&self, room_id: Box<RoomId>) -> Result<Ro
#[admin_command]
#[tracing::instrument(skip(self))]
pub(super) async fn force_set_room_state_from_server(
&self, room_id: Box<RoomId>, server_name: Box<ServerName>,
&self,
room_id: Box<RoomId>,
server_name: Box<ServerName>,
) -> Result<RoomMessageEventContent> {
if !self
.services
@ -554,13 +603,10 @@ pub(super) async fn force_set_room_state_from_server(
let remote_state_response = self
.services
.sending
.send_federation_request(
&server_name,
get_room_state::v1::Request {
.send_federation_request(&server_name, get_room_state::v1::Request {
room_id: room_id.clone().into(),
event_id: first_pdu.event_id.clone().into(),
},
)
})
.await?;
for pdu in remote_state_response.pdus.clone() {
@ -571,8 +617,8 @@ pub(super) async fn force_set_room_state_from_server(
.parse_incoming_pdu(&pdu)
.await
{
Ok(t) => t,
Err(e) => {
| Ok(t) => t,
| Err(e) => {
warn!("Could not parse PDU, ignoring: {e}");
continue;
},
@ -654,8 +700,8 @@ pub(super) async fn force_set_room_state_from_server(
.await?;
info!(
"Updating joined counts for room just in case (e.g. we may have found a difference in the room's \
m.room.member state"
"Updating joined counts for room just in case (e.g. we may have found a difference in \
the room's m.room.member state"
);
self.services
.rooms
@ -672,9 +718,13 @@ pub(super) async fn force_set_room_state_from_server(
#[admin_command]
pub(super) async fn get_signing_keys(
&self, server_name: Option<Box<ServerName>>, notary: Option<Box<ServerName>>, query: bool,
&self,
server_name: Option<Box<ServerName>>,
notary: Option<Box<ServerName>>,
query: bool,
) -> Result<RoomMessageEventContent> {
let server_name = server_name.unwrap_or_else(|| self.services.server.config.server_name.clone().into());
let server_name =
server_name.unwrap_or_else(|| self.services.server.config.server_name.clone().into());
if let Some(notary) = notary {
let signing_keys = self
@ -706,8 +756,12 @@ pub(super) async fn get_signing_keys(
}
#[admin_command]
pub(super) async fn get_verify_keys(&self, server_name: Option<Box<ServerName>>) -> Result<RoomMessageEventContent> {
let server_name = server_name.unwrap_or_else(|| self.services.server.config.server_name.clone().into());
pub(super) async fn get_verify_keys(
&self,
server_name: Option<Box<ServerName>>,
) -> Result<RoomMessageEventContent> {
let server_name =
server_name.unwrap_or_else(|| self.services.server.config.server_name.clone().into());
let keys = self
.services
@ -727,7 +781,9 @@ pub(super) async fn get_verify_keys(&self, server_name: Option<Box<ServerName>>)
#[admin_command]
pub(super) async fn resolve_true_destination(
&self, server_name: Box<ServerName>, no_cache: bool,
&self,
server_name: Box<ServerName>,
no_cache: bool,
) -> Result<RoomMessageEventContent> {
if !self.services.globals.config.allow_federation {
return Ok(RoomMessageEventContent::text_plain(
@ -737,7 +793,8 @@ pub(super) async fn resolve_true_destination(
if server_name == self.services.globals.config.server_name {
return Ok(RoomMessageEventContent::text_plain(
"Not allowed to send federation requests to ourselves. Please use `get-pdu` for fetching local PDUs.",
"Not allowed to send federation requests to ourselves. Please use `get-pdu` for \
fetching local PDUs.",
));
}
@ -846,7 +903,9 @@ pub(super) async fn list_dependencies(&self, names: bool) -> Result<RoomMessageE
#[admin_command]
pub(super) async fn database_stats(
&self, property: Option<String>, map: Option<String>,
&self,
property: Option<String>,
map: Option<String>,
) -> Result<RoomMessageEventContent> {
let property = property.unwrap_or_else(|| "rocksdb.stats".to_owned());
let map_name = map.as_ref().map_or(EMPTY, String::as_str);

View file

@ -2,7 +2,9 @@ use std::fmt::Write;
use conduwuit::Result;
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, RoomId, ServerName, UserId};
use ruma::{
events::room::message::RoomMessageEventContent, OwnedRoomId, RoomId, ServerName, UserId,
};
use crate::{admin_command, get_room_info};
@ -38,7 +40,10 @@ pub(super) async fn incoming_federation(&self) -> Result<RoomMessageEventContent
}
#[admin_command]
pub(super) async fn fetch_support_well_known(&self, server_name: Box<ServerName>) -> Result<RoomMessageEventContent> {
pub(super) async fn fetch_support_well_known(
&self,
server_name: Box<ServerName>,
) -> Result<RoomMessageEventContent> {
let response = self
.services
.client
@ -60,16 +65,20 @@ pub(super) async fn fetch_support_well_known(&self, server_name: Box<ServerName>
}
let json: serde_json::Value = match serde_json::from_str(&text) {
Ok(json) => json,
Err(_) => {
return Ok(RoomMessageEventContent::text_plain("Response text/body is not valid JSON."));
| Ok(json) => json,
| Err(_) => {
return Ok(RoomMessageEventContent::text_plain(
"Response text/body is not valid JSON.",
));
},
};
let pretty_json: String = match serde_json::to_string_pretty(&json) {
Ok(json) => json,
Err(_) => {
return Ok(RoomMessageEventContent::text_plain("Response text/body is not valid JSON."));
| Ok(json) => json,
| Err(_) => {
return Ok(RoomMessageEventContent::text_plain(
"Response text/body is not valid JSON.",
));
},
};
@ -79,10 +88,14 @@ pub(super) async fn fetch_support_well_known(&self, server_name: Box<ServerName>
}
#[admin_command]
pub(super) async fn remote_user_in_rooms(&self, user_id: Box<UserId>) -> Result<RoomMessageEventContent> {
pub(super) async fn remote_user_in_rooms(
&self,
user_id: Box<UserId>,
) -> Result<RoomMessageEventContent> {
if user_id.server_name() == self.services.globals.config.server_name {
return Ok(RoomMessageEventContent::text_plain(
"User belongs to our server, please use `list-joined-rooms` user admin command instead.",
"User belongs to our server, please use `list-joined-rooms` user admin command \
instead.",
));
}

View file

@ -1,16 +1,21 @@
use std::time::Duration;
use conduwuit::{debug, debug_info, debug_warn, error, info, trace, utils::time::parse_timepoint_ago, Result};
use conduwuit::{
debug, debug_info, debug_warn, error, info, trace, utils::time::parse_timepoint_ago, Result,
};
use conduwuit_service::media::Dim;
use ruma::{
events::room::message::RoomMessageEventContent, EventId, Mxc, MxcUri, OwnedMxcUri, OwnedServerName, ServerName,
events::room::message::RoomMessageEventContent, EventId, Mxc, MxcUri, OwnedMxcUri,
OwnedServerName, ServerName,
};
use crate::{admin_command, utils::parse_local_user_id};
#[admin_command]
pub(super) async fn delete(
&self, mxc: Option<Box<MxcUri>>, event_id: Option<Box<EventId>>,
&self,
mxc: Option<Box<MxcUri>>,
event_id: Option<Box<EventId>>,
) -> Result<RoomMessageEventContent> {
if event_id.is_some() && mxc.is_some() {
return Ok(RoomMessageEventContent::text_plain(
@ -52,7 +57,10 @@ pub(super) async fn delete(
let final_url = url.to_string().replace('"', "");
mxc_urls.push(final_url);
} else {
info!("Found a URL in the event ID {event_id} but did not start with mxc://, ignoring");
info!(
"Found a URL in the event ID {event_id} but did not start with \
mxc://, ignoring"
);
}
}
@ -67,17 +75,24 @@ pub(super) async fn delete(
debug!("Found a thumbnail_url in info key: {thumbnail_url}");
if thumbnail_url.to_string().starts_with("\"mxc://") {
debug!("Pushing thumbnail URL {thumbnail_url} to list of MXCs to delete");
let final_thumbnail_url = thumbnail_url.to_string().replace('"', "");
debug!(
"Pushing thumbnail URL {thumbnail_url} to list of MXCs \
to delete"
);
let final_thumbnail_url =
thumbnail_url.to_string().replace('"', "");
mxc_urls.push(final_thumbnail_url);
} else {
info!(
"Found a thumbnail URL in the event ID {event_id} but did not start with \
mxc://, ignoring"
"Found a thumbnail URL in the event ID {event_id} but \
did not start with mxc://, ignoring"
);
}
} else {
info!("No \"thumbnail_url\" key in \"info\" key, assuming no thumbnails.");
info!(
"No \"thumbnail_url\" key in \"info\" key, assuming no \
thumbnails."
);
}
}
}
@ -98,8 +113,8 @@ pub(super) async fn delete(
mxc_urls.push(final_url);
} else {
info!(
"Found a URL in the event ID {event_id} but did not start with mxc://, \
ignoring"
"Found a URL in the event ID {event_id} but did not \
start with mxc://, ignoring"
);
}
} else {
@ -109,13 +124,14 @@ pub(super) async fn delete(
}
} else {
return Ok(RoomMessageEventContent::text_plain(
"Event ID does not have a \"content\" key or failed parsing the event ID JSON.",
"Event ID does not have a \"content\" key or failed parsing the event \
ID JSON.",
));
}
} else {
return Ok(RoomMessageEventContent::text_plain(
"Event ID does not have a \"content\" key, this is not a message or an event type that contains \
media.",
"Event ID does not have a \"content\" key, this is not a message or an \
event type that contains media.",
));
}
} else {
@ -126,7 +142,9 @@ pub(super) async fn delete(
if mxc_urls.is_empty() {
info!("Parsed event ID {event_id} but did not contain any MXC URLs.");
return Ok(RoomMessageEventContent::text_plain("Parsed event ID but found no MXC URLs."));
return Ok(RoomMessageEventContent::text_plain(
"Parsed event ID but found no MXC URLs.",
));
}
let mut mxc_deletion_count: usize = 0;
@ -138,11 +156,11 @@ pub(super) async fn delete(
.delete(&mxc_url.as_str().try_into()?)
.await
{
Ok(()) => {
| Ok(()) => {
debug_info!("Successfully deleted {mxc_url} from filesystem and database");
mxc_deletion_count = mxc_deletion_count.saturating_add(1);
},
Err(e) => {
| Err(e) => {
debug_warn!("Failed to delete {mxc_url}, ignoring error and skipping: {e}");
continue;
},
@ -150,19 +168,22 @@ pub(super) async fn delete(
}
return Ok(RoomMessageEventContent::text_plain(format!(
"Deleted {mxc_deletion_count} total MXCs from our database and the filesystem from event ID {event_id}."
"Deleted {mxc_deletion_count} total MXCs from our database and the filesystem from \
event ID {event_id}."
)));
}
Ok(RoomMessageEventContent::text_plain(
"Please specify either an MXC using --mxc or an event ID using --event-id of the message containing an image. \
See --help for details.",
"Please specify either an MXC using --mxc or an event ID using --event-id of the \
message containing an image. See --help for details.",
))
}
#[admin_command]
pub(super) async fn delete_list(&self) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
@ -192,11 +213,11 @@ pub(super) async fn delete_list(&self) -> Result<RoomMessageEventContent> {
for mxc in &mxc_list {
trace!(%failed_parsed_mxcs, %mxc_deletion_count, "Deleting MXC {mxc} in bulk");
match self.services.media.delete(mxc).await {
Ok(()) => {
| Ok(()) => {
debug_info!("Successfully deleted {mxc} from filesystem and database");
mxc_deletion_count = mxc_deletion_count.saturating_add(1);
},
Err(e) => {
| Err(e) => {
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
continue;
},
@ -204,14 +225,18 @@ pub(super) async fn delete_list(&self) -> Result<RoomMessageEventContent> {
}
Ok(RoomMessageEventContent::text_plain(format!(
"Finished bulk MXC deletion, deleted {mxc_deletion_count} total MXCs from our database and the filesystem. \
{failed_parsed_mxcs} MXCs failed to be parsed from the database.",
"Finished bulk MXC deletion, deleted {mxc_deletion_count} total MXCs from our database \
and the filesystem. {failed_parsed_mxcs} MXCs failed to be parsed from the database.",
)))
}
#[admin_command]
pub(super) async fn delete_past_remote_media(
&self, duration: String, before: bool, after: bool, yes_i_want_to_delete_local_media: bool,
&self,
duration: String,
before: bool,
after: bool,
yes_i_want_to_delete_local_media: bool,
) -> Result<RoomMessageEventContent> {
if before && after {
return Ok(RoomMessageEventContent::text_plain(
@ -224,7 +249,12 @@ pub(super) async fn delete_past_remote_media(
let deleted_count = self
.services
.media
.delete_all_remote_media_at_after_time(duration, before, after, yes_i_want_to_delete_local_media)
.delete_all_remote_media_at_after_time(
duration,
before,
after,
yes_i_want_to_delete_local_media,
)
.await?;
Ok(RoomMessageEventContent::text_plain(format!(
@ -233,7 +263,10 @@ pub(super) async fn delete_past_remote_media(
}
#[admin_command]
pub(super) async fn delete_all_from_user(&self, username: String) -> Result<RoomMessageEventContent> {
pub(super) async fn delete_all_from_user(
&self,
username: String,
) -> Result<RoomMessageEventContent> {
let user_id = parse_local_user_id(self.services, &username)?;
let deleted_count = self.services.media.delete_from_user(&user_id).await?;
@ -245,7 +278,9 @@ pub(super) async fn delete_all_from_user(&self, username: String) -> Result<Room
#[admin_command]
pub(super) async fn delete_all_from_server(
&self, server_name: Box<ServerName>, yes_i_want_to_delete_local_media: bool,
&self,
server_name: Box<ServerName>,
yes_i_want_to_delete_local_media: bool,
) -> Result<RoomMessageEventContent> {
if server_name == self.services.globals.server_name() && !yes_i_want_to_delete_local_media {
return Ok(RoomMessageEventContent::text_plain(
@ -260,20 +295,26 @@ pub(super) async fn delete_all_from_server(
.await
.inspect_err(|e| error!("Failed to get MXC URIs from our database: {e}"))
else {
return Ok(RoomMessageEventContent::text_plain("Failed to get MXC URIs from our database"));
return Ok(RoomMessageEventContent::text_plain(
"Failed to get MXC URIs from our database",
));
};
let mut deleted_count: usize = 0;
for mxc in all_mxcs {
let Ok(mxc_server_name) = mxc.server_name().inspect_err(|e| {
debug_warn!("Failed to parse MXC {mxc} server name from database, ignoring error and skipping: {e}");
debug_warn!(
"Failed to parse MXC {mxc} server name from database, ignoring error and \
skipping: {e}"
);
}) else {
continue;
};
if mxc_server_name != server_name
|| (self.services.globals.server_is_ours(mxc_server_name) && !yes_i_want_to_delete_local_media)
|| (self.services.globals.server_is_ours(mxc_server_name)
&& !yes_i_want_to_delete_local_media)
{
trace!("skipping MXC URI {mxc}");
continue;
@ -282,10 +323,10 @@ pub(super) async fn delete_all_from_server(
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
match self.services.media.delete(&mxc).await {
Ok(()) => {
| Ok(()) => {
deleted_count = deleted_count.saturating_add(1);
},
Err(e) => {
| Err(e) => {
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
continue;
},
@ -307,7 +348,10 @@ pub(super) async fn get_file_info(&self, mxc: OwnedMxcUri) -> Result<RoomMessage
#[admin_command]
pub(super) async fn get_remote_file(
&self, mxc: OwnedMxcUri, server: Option<OwnedServerName>, timeout: u32,
&self,
mxc: OwnedMxcUri,
server: Option<OwnedServerName>,
timeout: u32,
) -> Result<RoomMessageEventContent> {
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
let timeout = Duration::from_millis(timeout.into());
@ -327,7 +371,12 @@ pub(super) async fn get_remote_file(
#[admin_command]
pub(super) async fn get_remote_thumbnail(
&self, mxc: OwnedMxcUri, server: Option<OwnedServerName>, timeout: u32, width: u32, height: u32,
&self,
mxc: OwnedMxcUri,
server: Option<OwnedServerName>,
timeout: u32,
width: u32,
height: u32,
) -> Result<RoomMessageEventContent> {
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
let timeout = Duration::from_millis(timeout.into());

View file

@ -53,8 +53,8 @@ async fn handle_command(services: Arc<Services>, command: CommandInput) -> Proce
async fn process_command(services: Arc<Services>, input: &CommandInput) -> ProcessorResult {
let (command, args, body) = match parse(&services, input) {
Err(error) => return Err(error),
Ok(parsed) => parsed,
| Err(error) => return Err(error),
| Ok(parsed) => parsed,
};
let context = Command {
@ -68,7 +68,8 @@ async fn process_command(services: Arc<Services>, input: &CommandInput) -> Proce
}
fn handle_panic(error: &Error, command: &CommandInput) -> ProcessorResult {
let link = "Please submit a [bug report](https://github.com/girlbossceo/conduwuit/issues/new). 🥺";
let link =
"Please submit a [bug report](https://github.com/girlbossceo/conduwuit/issues/new). 🥺";
let msg = format!("Panic occurred while processing command:\n```\n{error:#?}\n```\n{link}");
let content = RoomMessageEventContent::notice_markdown(msg);
error!("Panic while processing command: {error:?}");
@ -76,7 +77,11 @@ fn handle_panic(error: &Error, command: &CommandInput) -> ProcessorResult {
}
// Parse and process a message from the admin room
async fn process(context: &Command<'_>, command: AdminCommand, args: &[String]) -> ProcessorResult {
async fn process(
context: &Command<'_>,
command: AdminCommand,
args: &[String],
) -> ProcessorResult {
let (capture, logs) = capture_create(context);
let capture_scope = capture.start();
@ -100,11 +105,12 @@ async fn process(context: &Command<'_>, command: AdminCommand, args: &[String])
drop(logs);
match result {
Ok(content) => {
write!(&mut output, "{0}", content.body()).expect("failed to format command result to output buffer");
| Ok(content) => {
write!(&mut output, "{0}", content.body())
.expect("failed to format command result to output buffer");
Ok(Some(reply(RoomMessageEventContent::notice_markdown(output), context.reply_id)))
},
Err(error) => {
| Err(error) => {
write!(&mut output, "Command failed with error:\n```\n{error:#?}\n```")
.expect("failed to format command result to output");
Err(reply(RoomMessageEventContent::notice_markdown(output), context.reply_id))
@ -128,8 +134,9 @@ fn capture_create(context: &Command<'_>) -> (Arc<Capture>, Arc<Mutex<String>>) {
.and_then(LevelFilter::into_level)
.unwrap_or(Level::DEBUG);
let filter =
move |data: capture::Data<'_>| data.level() <= log_level && data.our_modules() && data.scope.contains(&"admin");
let filter = move |data: capture::Data<'_>| {
data.level() <= log_level && data.our_modules() && data.scope.contains(&"admin")
};
let logs = Arc::new(Mutex::new(
collect_stream(|s| markdown_table_head(s)).expect("markdown table header"),
@ -146,14 +153,15 @@ fn capture_create(context: &Command<'_>) -> (Arc<Capture>, Arc<Mutex<String>>) {
// Parse chat messages from the admin room into an AdminCommand object
fn parse<'a>(
services: &Arc<Services>, input: &'a CommandInput,
services: &Arc<Services>,
input: &'a CommandInput,
) -> Result<(AdminCommand, Vec<String>, Vec<&'a str>), CommandOutput> {
let lines = input.command.lines().filter(|line| !line.trim().is_empty());
let command_line = lines.clone().next().expect("command missing first line");
let body = lines.skip(1).collect();
match parse_command(command_line) {
Ok((command, args)) => Ok((command, args, body)),
Err(error) => {
| Ok((command, args)) => Ok((command, args, body)),
| Err(error) => {
let message = error
.to_string()
.replace("server.name", services.globals.server_name().as_str());
@ -255,11 +263,12 @@ fn parse_line(command_line: &str) -> Vec<String> {
argv
}
fn reply(mut content: RoomMessageEventContent, reply_id: Option<&EventId>) -> RoomMessageEventContent {
fn reply(
mut content: RoomMessageEventContent,
reply_id: Option<&EventId>,
) -> RoomMessageEventContent {
content.relates_to = reply_id.map(|event_id| Reply {
in_reply_to: InReplyTo {
event_id: event_id.to_owned(),
},
in_reply_to: InReplyTo { event_id: event_id.to_owned() },
});
content

View file

@ -30,15 +30,14 @@ pub(crate) enum AccountDataCommand {
}
/// All the getters and iterators from src/database/key_value/account_data.rs
pub(super) async fn process(subcommand: AccountDataCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
subcommand: AccountDataCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand {
AccountDataCommand::ChangesSince {
user_id,
since,
room_id,
} => {
| AccountDataCommand::ChangesSince { user_id, since, room_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.account_data
@ -51,11 +50,7 @@ pub(super) async fn process(subcommand: AccountDataCommand, context: &Command<'_
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
AccountDataCommand::Get {
user_id,
kind,
room_id,
} => {
| AccountDataCommand::Get { user_id, kind, room_id } => {
let timer = tokio::time::Instant::now();
let results = services
.account_data

View file

@ -18,13 +18,14 @@ pub(crate) enum AppserviceCommand {
}
/// All the getters and iterators from src/database/key_value/appservice.rs
pub(super) async fn process(subcommand: AppserviceCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
subcommand: AppserviceCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand {
AppserviceCommand::GetRegistration {
appservice_id,
} => {
| AppserviceCommand::GetRegistration { appservice_id } => {
let timer = tokio::time::Instant::now();
let results = services.appservice.get_registration(&appservice_id).await;
@ -34,7 +35,7 @@ pub(super) async fn process(subcommand: AppserviceCommand, context: &Command<'_>
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
AppserviceCommand::All => {
| AppserviceCommand::All => {
let timer = tokio::time::Instant::now();
let results = services.appservice.all().await;
let query_time = timer.elapsed();

View file

@ -21,11 +21,14 @@ pub(crate) enum GlobalsCommand {
}
/// All the getters and iterators from src/database/key_value/globals.rs
pub(super) async fn process(subcommand: GlobalsCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
subcommand: GlobalsCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand {
GlobalsCommand::DatabaseVersion => {
| GlobalsCommand::DatabaseVersion => {
let timer = tokio::time::Instant::now();
let results = services.globals.db.database_version().await;
let query_time = timer.elapsed();
@ -34,7 +37,7 @@ pub(super) async fn process(subcommand: GlobalsCommand, context: &Command<'_>) -
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
GlobalsCommand::CurrentCount => {
| GlobalsCommand::CurrentCount => {
let timer = tokio::time::Instant::now();
let results = services.globals.db.current_count();
let query_time = timer.elapsed();
@ -43,7 +46,7 @@ pub(super) async fn process(subcommand: GlobalsCommand, context: &Command<'_>) -
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
GlobalsCommand::LastCheckForUpdatesId => {
| GlobalsCommand::LastCheckForUpdatesId => {
let timer = tokio::time::Instant::now();
let results = services.updates.last_check_for_updates_id().await;
let query_time = timer.elapsed();
@ -52,9 +55,7 @@ pub(super) async fn process(subcommand: GlobalsCommand, context: &Command<'_>) -
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
GlobalsCommand::SigningKeysFor {
origin,
} => {
| GlobalsCommand::SigningKeysFor { origin } => {
let timer = tokio::time::Instant::now();
let results = services.server_keys.verify_keys_for(&origin).await;
let query_time = timer.elapsed();

View file

@ -14,8 +14,9 @@ use conduwuit::Result;
use self::{
account_data::AccountDataCommand, appservice::AppserviceCommand, globals::GlobalsCommand,
presence::PresenceCommand, pusher::PusherCommand, resolver::ResolverCommand, room_alias::RoomAliasCommand,
room_state_cache::RoomStateCacheCommand, sending::SendingCommand, users::UsersCommand,
presence::PresenceCommand, pusher::PusherCommand, resolver::ResolverCommand,
room_alias::RoomAliasCommand, room_state_cache::RoomStateCacheCommand,
sending::SendingCommand, users::UsersCommand,
};
use crate::admin_command_dispatch;

View file

@ -23,13 +23,14 @@ pub(crate) enum PresenceCommand {
}
/// All the getters and iterators in key_value/presence.rs
pub(super) async fn process(subcommand: PresenceCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
subcommand: PresenceCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand {
PresenceCommand::GetPresence {
user_id,
} => {
| PresenceCommand::GetPresence { user_id } => {
let timer = tokio::time::Instant::now();
let results = services.presence.db.get_presence(&user_id).await;
let query_time = timer.elapsed();
@ -38,9 +39,7 @@ pub(super) async fn process(subcommand: PresenceCommand, context: &Command<'_>)
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
PresenceCommand::PresenceSince {
since,
} => {
| PresenceCommand::PresenceSince { since } => {
let timer = tokio::time::Instant::now();
let results: Vec<(_, _, _)> = services
.presence

View file

@ -13,13 +13,14 @@ pub(crate) enum PusherCommand {
},
}
pub(super) async fn process(subcommand: PusherCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
subcommand: PusherCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand {
PusherCommand::GetPushers {
user_id,
} => {
| PusherCommand::GetPushers { user_id } => {
let timer = tokio::time::Instant::now();
let results = services.pusher.get_pushers(&user_id).await;
let query_time = timer.elapsed();

View file

@ -22,20 +22,16 @@ pub(crate) enum ResolverCommand {
}
#[admin_command]
async fn destinations_cache(&self, server_name: Option<OwnedServerName>) -> Result<RoomMessageEventContent> {
async fn destinations_cache(
&self,
server_name: Option<OwnedServerName>,
) -> Result<RoomMessageEventContent> {
use service::resolver::cache::CachedDest;
let mut out = String::new();
writeln!(out, "| Server Name | Destination | Hostname | Expires |")?;
writeln!(out, "| ----------- | ----------- | -------- | ------- |")?;
let row = |(
name,
&CachedDest {
ref dest,
ref host,
expire,
},
)| {
let row = |(name, &CachedDest { ref dest, ref host, expire })| {
let expire = time::format(expire, "%+");
writeln!(out, "| {name} | {dest} | {host} | {expire} |").expect("wrote line");
};
@ -64,14 +60,7 @@ async fn overrides_cache(&self, server_name: Option<String>) -> Result<RoomMessa
let mut out = String::new();
writeln!(out, "| Server Name | IP | Port | Expires |")?;
writeln!(out, "| ----------- | --- | ----:| ------- |")?;
let row = |(
name,
&CachedOverride {
ref ips,
port,
expire,
},
)| {
let row = |(name, &CachedOverride { ref ips, port, expire })| {
let expire = time::format(expire, "%+");
writeln!(out, "| {name} | {ips:?} | {port} | {expire} |").expect("wrote line");
};

View file

@ -24,13 +24,14 @@ pub(crate) enum RoomAliasCommand {
}
/// All the getters and iterators in src/database/key_value/rooms/alias.rs
pub(super) async fn process(subcommand: RoomAliasCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
subcommand: RoomAliasCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand {
RoomAliasCommand::ResolveLocalAlias {
alias,
} => {
| RoomAliasCommand::ResolveLocalAlias { alias } => {
let timer = tokio::time::Instant::now();
let results = services.rooms.alias.resolve_local_alias(&alias).await;
let query_time = timer.elapsed();
@ -39,9 +40,7 @@ pub(super) async fn process(subcommand: RoomAliasCommand, context: &Command<'_>)
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomAliasCommand::LocalAliasesForRoom {
room_id,
} => {
| RoomAliasCommand::LocalAliasesForRoom { room_id } => {
let timer = tokio::time::Instant::now();
let aliases: Vec<_> = services
.rooms
@ -56,7 +55,7 @@ pub(super) async fn process(subcommand: RoomAliasCommand, context: &Command<'_>)
"Query completed in {query_time:?}:\n\n```rs\n{aliases:#?}\n```"
)))
},
RoomAliasCommand::AllLocalAliases => {
| RoomAliasCommand::AllLocalAliases => {
let timer = tokio::time::Instant::now();
let aliases = services
.rooms

View file

@ -77,15 +77,13 @@ pub(crate) enum RoomStateCacheCommand {
}
pub(super) async fn process(
subcommand: RoomStateCacheCommand, context: &Command<'_>,
subcommand: RoomStateCacheCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand {
RoomStateCacheCommand::ServerInRoom {
server,
room_id,
} => {
| RoomStateCacheCommand::ServerInRoom { server, room_id } => {
let timer = tokio::time::Instant::now();
let result = services
.rooms
@ -98,9 +96,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
)))
},
RoomStateCacheCommand::RoomServers {
room_id,
} => {
| RoomStateCacheCommand::RoomServers { room_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -115,9 +111,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::ServerRooms {
server,
} => {
| RoomStateCacheCommand::ServerRooms { server } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -132,9 +126,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomMembers {
room_id,
} => {
| RoomStateCacheCommand::RoomMembers { room_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -149,9 +141,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::LocalUsersInRoom {
room_id,
} => {
| RoomStateCacheCommand::LocalUsersInRoom { room_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -166,9 +156,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::ActiveLocalUsersInRoom {
room_id,
} => {
| RoomStateCacheCommand::ActiveLocalUsersInRoom { room_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -183,9 +171,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomJoinedCount {
room_id,
} => {
| RoomStateCacheCommand::RoomJoinedCount { room_id } => {
let timer = tokio::time::Instant::now();
let results = services.rooms.state_cache.room_joined_count(&room_id).await;
let query_time = timer.elapsed();
@ -194,9 +180,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomInvitedCount {
room_id,
} => {
| RoomStateCacheCommand::RoomInvitedCount { room_id } => {
let timer = tokio::time::Instant::now();
let results = services
.rooms
@ -209,9 +193,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomUserOnceJoined {
room_id,
} => {
| RoomStateCacheCommand::RoomUserOnceJoined { room_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -226,9 +208,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomMembersInvited {
room_id,
} => {
| RoomStateCacheCommand::RoomMembersInvited { room_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -243,10 +223,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::GetInviteCount {
room_id,
user_id,
} => {
| RoomStateCacheCommand::GetInviteCount { room_id, user_id } => {
let timer = tokio::time::Instant::now();
let results = services
.rooms
@ -259,10 +236,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::GetLeftCount {
room_id,
user_id,
} => {
| RoomStateCacheCommand::GetLeftCount { room_id, user_id } => {
let timer = tokio::time::Instant::now();
let results = services
.rooms
@ -275,9 +249,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomsJoined {
user_id,
} => {
| RoomStateCacheCommand::RoomsJoined { user_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -292,9 +264,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomsInvited {
user_id,
} => {
| RoomStateCacheCommand::RoomsInvited { user_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -308,9 +278,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::RoomsLeft {
user_id,
} => {
| RoomStateCacheCommand::RoomsLeft { user_id } => {
let timer = tokio::time::Instant::now();
let results: Vec<_> = services
.rooms
@ -324,10 +292,7 @@ pub(super) async fn process(
"Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```"
)))
},
RoomStateCacheCommand::InviteState {
user_id,
room_id,
} => {
| RoomStateCacheCommand::InviteState { user_id, room_id } => {
let timer = tokio::time::Instant::now();
let results = services
.rooms

View file

@ -62,11 +62,14 @@ pub(crate) enum SendingCommand {
}
/// All the getters and iterators in key_value/sending.rs
pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
subcommand: SendingCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match subcommand {
SendingCommand::ActiveRequests => {
| SendingCommand::ActiveRequests => {
let timer = tokio::time::Instant::now();
let results = services.sending.db.active_requests();
let active_requests = results.collect::<Vec<_>>().await;
@ -76,25 +79,29 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
"Query completed in {query_time:?}:\n\n```rs\n{active_requests:#?}\n```"
)))
},
SendingCommand::QueuedRequests {
| SendingCommand::QueuedRequests {
appservice_id,
server_name,
user_id,
push_key,
} => {
if appservice_id.is_none() && server_name.is_none() && user_id.is_none() && push_key.is_none() {
if appservice_id.is_none()
&& server_name.is_none()
&& user_id.is_none()
&& push_key.is_none()
{
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. See \
--help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
let timer = tokio::time::Instant::now();
let results = match (appservice_id, server_name, user_id, push_key) {
(Some(appservice_id), None, None, None) => {
| (Some(appservice_id), None, None, None) => {
if appservice_id.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via \
arguments. See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
@ -103,15 +110,15 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
.db
.queued_requests(&Destination::Appservice(appservice_id))
},
(None, Some(server_name), None, None) => services
| (None, Some(server_name), None, None) => services
.sending
.db
.queued_requests(&Destination::Normal(server_name.into())),
(None, None, Some(user_id), Some(push_key)) => {
| (None, None, Some(user_id), Some(push_key)) => {
if push_key.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via \
arguments. See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
@ -120,16 +127,16 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
.db
.queued_requests(&Destination::Push(user_id.into(), push_key))
},
(Some(_), Some(_), Some(_), Some(_)) => {
| (Some(_), Some(_), Some(_), Some(_)) => {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. \
Not all of them See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. Not all of them See --help for more details.",
));
},
_ => {
| _ => {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. \
See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
},
};
@ -141,26 +148,30 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
"Query completed in {query_time:?}:\n\n```rs\n{queued_requests:#?}\n```"
)))
},
SendingCommand::ActiveRequestsFor {
| SendingCommand::ActiveRequestsFor {
appservice_id,
server_name,
user_id,
push_key,
} => {
if appservice_id.is_none() && server_name.is_none() && user_id.is_none() && push_key.is_none() {
if appservice_id.is_none()
&& server_name.is_none()
&& user_id.is_none()
&& push_key.is_none()
{
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. See \
--help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
let timer = tokio::time::Instant::now();
let results = match (appservice_id, server_name, user_id, push_key) {
(Some(appservice_id), None, None, None) => {
| (Some(appservice_id), None, None, None) => {
if appservice_id.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via \
arguments. See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
@ -169,15 +180,15 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
.db
.active_requests_for(&Destination::Appservice(appservice_id))
},
(None, Some(server_name), None, None) => services
| (None, Some(server_name), None, None) => services
.sending
.db
.active_requests_for(&Destination::Normal(server_name.into())),
(None, None, Some(user_id), Some(push_key)) => {
| (None, None, Some(user_id), Some(push_key)) => {
if push_key.is_empty() {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via \
arguments. See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
}
@ -186,16 +197,16 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
.db
.active_requests_for(&Destination::Push(user_id.into(), push_key))
},
(Some(_), Some(_), Some(_), Some(_)) => {
| (Some(_), Some(_), Some(_), Some(_)) => {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. \
Not all of them See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. Not all of them See --help for more details.",
));
},
_ => {
| _ => {
return Ok(RoomMessageEventContent::text_plain(
"An appservice ID, server name, or a user ID with push key must be specified via arguments. \
See --help for more details.",
"An appservice ID, server name, or a user ID with push key must be \
specified via arguments. See --help for more details.",
));
},
};
@ -207,9 +218,7 @@ pub(super) async fn process(subcommand: SendingCommand, context: &Command<'_>) -
"Query completed in {query_time:?}:\n\n```rs\n{active_requests:#?}\n```"
)))
},
SendingCommand::GetLatestEduCount {
server_name,
} => {
| SendingCommand::GetLatestEduCount { server_name } => {
let timer = tokio::time::Instant::now();
let results = services.sending.db.get_latest_educount(&server_name).await;
let query_time = timer.elapsed();

View file

@ -1,7 +1,9 @@
use clap::Subcommand;
use conduwuit::Result;
use futures::stream::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, OwnedDeviceId, OwnedRoomId, OwnedUserId};
use ruma::{
events::room::message::RoomMessageEventContent, OwnedDeviceId, OwnedRoomId, OwnedUserId,
};
use crate::{admin_command, admin_command_dispatch};
@ -91,7 +93,11 @@ pub(crate) enum UsersCommand {
#[admin_command]
async fn get_backup_session(
&self, user_id: OwnedUserId, version: String, room_id: OwnedRoomId, session_id: String,
&self,
user_id: OwnedUserId,
version: String,
room_id: OwnedRoomId,
session_id: String,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
@ -108,7 +114,10 @@ async fn get_backup_session(
#[admin_command]
async fn get_room_backups(
&self, user_id: OwnedUserId, version: String, room_id: OwnedRoomId,
&self,
user_id: OwnedUserId,
version: String,
room_id: OwnedRoomId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
@ -124,7 +133,11 @@ async fn get_room_backups(
}
#[admin_command]
async fn get_all_backups(&self, user_id: OwnedUserId, version: String) -> Result<RoomMessageEventContent> {
async fn get_all_backups(
&self,
user_id: OwnedUserId,
version: String,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self.services.key_backups.get_all(&user_id, &version).await;
let query_time = timer.elapsed();
@ -135,7 +148,11 @@ async fn get_all_backups(&self, user_id: OwnedUserId, version: String) -> Result
}
#[admin_command]
async fn get_backup_algorithm(&self, user_id: OwnedUserId, version: String) -> Result<RoomMessageEventContent> {
async fn get_backup_algorithm(
&self,
user_id: OwnedUserId,
version: String,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
@ -150,7 +167,10 @@ async fn get_backup_algorithm(&self, user_id: OwnedUserId, version: String) -> R
}
#[admin_command]
async fn get_latest_backup_version(&self, user_id: OwnedUserId) -> Result<RoomMessageEventContent> {
async fn get_latest_backup_version(
&self,
user_id: OwnedUserId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
@ -244,7 +264,11 @@ async fn list_devices_metadata(&self, user_id: OwnedUserId) -> Result<RoomMessag
}
#[admin_command]
async fn get_device_metadata(&self, user_id: OwnedUserId, device_id: OwnedDeviceId) -> Result<RoomMessageEventContent> {
async fn get_device_metadata(
&self,
user_id: OwnedUserId,
device_id: OwnedDeviceId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let device = self
.services
@ -270,7 +294,11 @@ async fn get_devices_version(&self, user_id: OwnedUserId) -> Result<RoomMessageE
}
#[admin_command]
async fn count_one_time_keys(&self, user_id: OwnedUserId, device_id: OwnedDeviceId) -> Result<RoomMessageEventContent> {
async fn count_one_time_keys(
&self,
user_id: OwnedUserId,
device_id: OwnedDeviceId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
@ -285,7 +313,11 @@ async fn count_one_time_keys(&self, user_id: OwnedUserId, device_id: OwnedDevice
}
#[admin_command]
async fn get_device_keys(&self, user_id: OwnedUserId, device_id: OwnedDeviceId) -> Result<RoomMessageEventContent> {
async fn get_device_keys(
&self,
user_id: OwnedUserId,
device_id: OwnedDeviceId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self
.services
@ -327,7 +359,9 @@ async fn get_master_key(&self, user_id: OwnedUserId) -> Result<RoomMessageEventC
#[admin_command]
async fn get_to_device_events(
&self, user_id: OwnedUserId, device_id: OwnedDeviceId,
&self,
user_id: OwnedUserId,
device_id: OwnedDeviceId,
) -> Result<RoomMessageEventContent> {
let timer = tokio::time::Instant::now();
let result = self

View file

@ -3,7 +3,10 @@ use std::fmt::Write;
use clap::Subcommand;
use conduwuit::Result;
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomAliasId, OwnedRoomId, RoomAliasId, RoomId};
use ruma::{
events::room::message::RoomMessageEventContent, OwnedRoomAliasId, OwnedRoomId, RoomAliasId,
RoomId,
};
use crate::{escape_html, Command};
@ -42,82 +45,92 @@ pub(crate) enum RoomAliasCommand {
},
}
pub(super) async fn process(command: RoomAliasCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
command: RoomAliasCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
let server_user = &services.globals.server_user;
match command {
RoomAliasCommand::Set {
ref room_alias_localpart,
..
}
| RoomAliasCommand::Remove {
ref room_alias_localpart,
}
| RoomAliasCommand::Which {
ref room_alias_localpart,
} => {
let room_alias_str = format!("#{}:{}", room_alias_localpart, services.globals.server_name());
| RoomAliasCommand::Set { ref room_alias_localpart, .. }
| RoomAliasCommand::Remove { ref room_alias_localpart }
| RoomAliasCommand::Which { ref room_alias_localpart } => {
let room_alias_str =
format!("#{}:{}", room_alias_localpart, services.globals.server_name());
let room_alias = match RoomAliasId::parse_box(room_alias_str) {
Ok(alias) => alias,
Err(err) => return Ok(RoomMessageEventContent::text_plain(format!("Failed to parse alias: {err}"))),
| Ok(alias) => alias,
| Err(err) =>
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to parse alias: {err}"
))),
};
match command {
RoomAliasCommand::Set {
force,
room_id,
..
} => match (force, services.rooms.alias.resolve_local_alias(&room_alias).await) {
(true, Ok(id)) => match services
.rooms
.alias
.set_alias(&room_alias, &room_id, server_user)
{
Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
| RoomAliasCommand::Set { force, room_id, .. } =>
match (force, services.rooms.alias.resolve_local_alias(&room_alias).await) {
| (true, Ok(id)) => {
match services.rooms.alias.set_alias(
&room_alias,
&room_id,
server_user,
) {
| Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
"Successfully overwrote alias (formerly {id})"
))),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {err}"))),
},
(false, Ok(id)) => Ok(RoomMessageEventContent::text_plain(format!(
"Refusing to overwrite in use alias for {id}, use -f or --force to overwrite"
| Err(err) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to remove alias: {err}"
))),
(_, Err(_)) => match services
.rooms
.alias
.set_alias(&room_alias, &room_id, server_user)
{
Ok(()) => Ok(RoomMessageEventContent::text_plain("Successfully set alias")),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {err}"))),
}
},
| (false, Ok(id)) => Ok(RoomMessageEventContent::text_plain(format!(
"Refusing to overwrite in use alias for {id}, use -f or --force to \
overwrite"
))),
| (_, Err(_)) => {
match services.rooms.alias.set_alias(
&room_alias,
&room_id,
server_user,
) {
| Ok(()) => Ok(RoomMessageEventContent::text_plain(
"Successfully set alias",
)),
| Err(err) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to remove alias: {err}"
))),
}
},
},
RoomAliasCommand::Remove {
..
} => match services.rooms.alias.resolve_local_alias(&room_alias).await {
Ok(id) => match services
| RoomAliasCommand::Remove { .. } =>
match services.rooms.alias.resolve_local_alias(&room_alias).await {
| Ok(id) => match services
.rooms
.alias
.remove_alias(&room_alias, server_user)
.await
{
Ok(()) => Ok(RoomMessageEventContent::text_plain(format!("Removed alias from {id}"))),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {err}"))),
| Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
"Removed alias from {id}"
))),
| Err(err) => Ok(RoomMessageEventContent::text_plain(format!(
"Failed to remove alias: {err}"
))),
},
Err(_) => Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")),
| Err(_) =>
Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")),
},
RoomAliasCommand::Which {
..
} => match services.rooms.alias.resolve_local_alias(&room_alias).await {
Ok(id) => Ok(RoomMessageEventContent::text_plain(format!("Alias resolves to {id}"))),
Err(_) => Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")),
| RoomAliasCommand::Which { .. } =>
match services.rooms.alias.resolve_local_alias(&room_alias).await {
| Ok(id) => Ok(RoomMessageEventContent::text_plain(format!(
"Alias resolves to {id}"
))),
| Err(_) =>
Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")),
},
RoomAliasCommand::List {
..
} => unreachable!(),
| RoomAliasCommand::List { .. } => unreachable!(),
}
},
RoomAliasCommand::List {
room_id,
} => {
| RoomAliasCommand::List { room_id } =>
if let Some(room_id) = room_id {
let aliases: Vec<OwnedRoomAliasId> = services
.rooms
@ -128,7 +141,8 @@ pub(super) async fn process(command: RoomAliasCommand, context: &Command<'_>) ->
.await;
let plain_list = aliases.iter().fold(String::new(), |mut output, alias| {
writeln!(output, "- {alias}").expect("should be able to write to string buffer");
writeln!(output, "- {alias}")
.expect("should be able to write to string buffer");
output
});
@ -176,7 +190,6 @@ pub(super) async fn process(command: RoomAliasCommand, context: &Command<'_>) ->
let plain = format!("Aliases:\n{plain_list}");
let html = format!("Aliases:\n<ul>{html_list}</ul>");
Ok(RoomMessageEventContent::text_html(plain, html))
}
},
}
}

View file

@ -6,7 +6,11 @@ use crate::{admin_command, get_room_info, PAGE_SIZE};
#[admin_command]
pub(super) async fn list_rooms(
&self, page: Option<usize>, exclude_disabled: bool, exclude_banned: bool, no_details: bool,
&self,
page: Option<usize>,
exclude_disabled: bool,
exclude_banned: bool,
no_details: bool,
) -> Result<RoomMessageEventContent> {
// TODO: i know there's a way to do this with clap, but i can't seem to find it
let page = page.unwrap_or(1);
@ -16,10 +20,12 @@ pub(super) async fn list_rooms(
.metadata
.iter_ids()
.filter_map(|room_id| async move {
(!exclude_disabled || !self.services.rooms.metadata.is_disabled(room_id).await).then_some(room_id)
(!exclude_disabled || !self.services.rooms.metadata.is_disabled(room_id).await)
.then_some(room_id)
})
.filter_map(|room_id| async move {
(!exclude_banned || !self.services.rooms.metadata.is_banned(room_id).await).then_some(room_id)
(!exclude_banned || !self.services.rooms.metadata.is_banned(room_id).await)
.then_some(room_id)
})
.then(|room_id| get_room_info(self.services, room_id))
.collect::<Vec<_>>()

View file

@ -25,24 +25,21 @@ pub(crate) enum RoomDirectoryCommand {
},
}
pub(super) async fn process(command: RoomDirectoryCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
pub(super) async fn process(
command: RoomDirectoryCommand,
context: &Command<'_>,
) -> Result<RoomMessageEventContent> {
let services = context.services;
match command {
RoomDirectoryCommand::Publish {
room_id,
} => {
| RoomDirectoryCommand::Publish { room_id } => {
services.rooms.directory.set_public(&room_id);
Ok(RoomMessageEventContent::notice_plain("Room published"))
},
RoomDirectoryCommand::Unpublish {
room_id,
} => {
| RoomDirectoryCommand::Unpublish { room_id } => {
services.rooms.directory.set_not_public(&room_id);
Ok(RoomMessageEventContent::notice_plain("Room unpublished"))
},
RoomDirectoryCommand::List {
page,
} => {
| RoomDirectoryCommand::List { page } => {
// TODO: i know there's a way to do this with clap, but i can't seem to find it
let page = page.unwrap_or(1);
let mut rooms: Vec<_> = services
@ -70,7 +67,9 @@ pub(super) async fn process(command: RoomDirectoryCommand, context: &Command<'_>
"Rooms (page {page}):\n```\n{}\n```",
rooms
.iter()
.map(|(id, members, name)| format!("{id} | Members: {members} | Name: {name}"))
.map(|(id, members, name)| format!(
"{id} | Members: {members} | Name: {name}"
))
.collect::<Vec<_>>()
.join("\n")
);

View file

@ -27,7 +27,11 @@ pub(crate) enum RoomInfoCommand {
}
#[admin_command]
async fn list_joined_members(&self, room_id: Box<RoomId>, local_only: bool) -> Result<RoomMessageEventContent> {
async fn list_joined_members(
&self,
room_id: Box<RoomId>,
local_only: bool,
) -> Result<RoomMessageEventContent> {
let room_name = self
.services
.rooms

View file

@ -9,7 +9,8 @@ use conduwuit::Result;
use ruma::OwnedRoomId;
use self::{
alias::RoomAliasCommand, directory::RoomDirectoryCommand, info::RoomInfoCommand, moderation::RoomModerationCommand,
alias::RoomAliasCommand, directory::RoomDirectoryCommand, info::RoomInfoCommand,
moderation::RoomModerationCommand,
};
use crate::admin_command_dispatch;

View file

@ -6,7 +6,10 @@ use conduwuit::{
warn, Result,
};
use futures::StreamExt;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, RoomAliasId, RoomId, RoomOrAliasId};
use ruma::{
events::room::message::RoomMessageEventContent, OwnedRoomId, RoomAliasId, RoomId,
RoomOrAliasId,
};
use crate::{admin_command, admin_command_dispatch, get_room_info};
@ -75,7 +78,10 @@ pub(crate) enum RoomModerationCommand {
#[admin_command]
async fn ban_room(
&self, force: bool, disable_federation: bool, room: Box<RoomOrAliasId>,
&self,
force: bool,
disable_federation: bool,
room: Box<RoomOrAliasId>,
) -> Result<RoomMessageEventContent> {
debug!("Got room alias or ID: {}", room);
@ -89,13 +95,13 @@ async fn ban_room(
let room_id = if room.is_room_id() {
let room_id = match RoomId::parse(&room) {
Ok(room_id) => room_id,
Err(e) => {
| 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}"
)))
},
"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");
@ -105,18 +111,18 @@ async fn ban_room(
room_id
} else if room.is_room_alias_id() {
let room_alias = match RoomAliasId::parse(&room) {
Ok(room_alias) => room_alias,
Err(e) => {
| 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}"
)))
},
"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"
"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 Ok(room_id) = self
@ -128,7 +134,10 @@ async fn ban_room(
{
room_id
} else {
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
debug!(
"We don't have this room alias to a room ID locally, attempting to fetch room \
ID over federation"
);
match self
.services
@ -137,11 +146,15 @@ async fn ban_room(
.resolve_alias(&room_alias, None)
.await
{
Ok((room_id, servers)) => {
debug!(?room_id, ?servers, "Got federation response fetching room ID for {room}");
| Ok((room_id, servers)) => {
debug!(
?room_id,
?servers,
"Got federation response fetching room ID for {room}"
);
room_id
},
Err(e) => {
| Err(e) => {
return Ok(RoomMessageEventContent::notice_plain(format!(
"Failed to resolve room alias {room} to a room ID: {e}"
)));
@ -154,8 +167,9 @@ async fn ban_room(
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`)",
"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`)",
));
};
@ -171,8 +185,8 @@ async fn ban_room(
while let Some(local_user) = users.next().await {
debug!(
"Attempting leave for user {local_user} in room {room_id} (forced, ignoring all errors, evicting \
admins too)",
"Attempting leave for user {local_user} in room {room_id} (forced, ignoring all \
errors, evicting admins too)",
);
if let Err(e) = leave_room(self.services, local_user, &room_id, None).await {
@ -196,12 +210,14 @@ async fn ban_room(
debug!("Attempting leave for user {} in room {}", &local_user, &room_id);
if let Err(e) = leave_room(self.services, local_user, &room_id, None).await {
error!(
"Error attempting to make local user {} leave room {} during room banning: {}",
"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",
"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
)));
}
@ -232,19 +248,26 @@ async fn ban_room(
if disable_federation {
self.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.",
"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.",
"Room banned and removed all our local users, use `!admin federation disable-room` to \
stop receiving new inbound federation events as well if needed.",
))
}
#[admin_command]
async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
async fn ban_list_of_rooms(
&self,
force: bool,
disable_federation: bool,
) -> Result<RoomMessageEventContent> {
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
@ -264,9 +287,10 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
for &room in &rooms_s {
match <&RoomOrAliasId>::try_from(room) {
Ok(room_alias_or_id) => {
| Ok(room_alias_or_id) => {
if let Ok(admin_room_id) = self.services.admin.get_admin_room().await {
if room.to_owned().eq(&admin_room_id) || room.to_owned().eq(admin_room_alias) {
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;
}
@ -274,19 +298,20 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
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) => {
| 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}"
"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} is not a valid room ID or room alias, please fix the \
list and try again: {e}"
)));
},
};
@ -296,7 +321,7 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
if room_alias_or_id.is_room_alias_id() {
match RoomAliasId::parse(room_alias_or_id) {
Ok(room_alias) => {
| Ok(room_alias) => {
let room_id = if let Ok(room_id) = self
.services
.rooms
@ -307,8 +332,8 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
room_id
} else {
debug!(
"We don't have this room alias to a room ID locally, attempting to fetch room ID \
over federation"
"We don't have this room alias to a room ID locally, \
attempting to fetch room ID over federation"
);
match self
@ -318,7 +343,7 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
.resolve_alias(&room_alias, None)
.await
{
Ok((room_id, servers)) => {
| Ok((room_id, servers)) => {
debug!(
?room_id,
?servers,
@ -326,15 +351,19 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
);
room_id
},
Err(e) => {
| Err(e) => {
// don't fail if force blocking
if force {
warn!("Failed to resolve room alias {room} to a room ID: {e}");
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}"
"Failed to resolve room alias {room} to a room ID: \
{e}"
)));
},
}
@ -342,34 +371,37 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
room_ids.push(room_id);
},
Err(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}"
"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} is not a valid room ID or room alias, please fix the \
list and try again: {e}"
)));
},
}
}
},
Err(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}"
"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} is not a valid room ID or room alias, please fix the list and try \
again: {e}"
)));
},
}
@ -393,8 +425,8 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
while let Some(local_user) = users.next().await {
debug!(
"Attempting leave for user {local_user} in room {room_id} (forced, ignoring all errors, evicting \
admins too)",
"Attempting leave for user {local_user} in room {room_id} (forced, ignoring \
all errors, evicting admins too)",
);
if let Err(e) = leave_room(self.services, local_user, &room_id, None).await {
@ -418,14 +450,15 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
debug!("Attempting leave for user {local_user} in room {room_id}");
if let Err(e) = leave_room(self.services, local_user, &room_id, None).await {
error!(
"Error attempting to make local user {local_user} leave room {room_id} during bulk room \
banning: {e}",
"Error attempting to make local user {local_user} leave room {room_id} \
during bulk room banning: {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",
"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
)));
}
@ -458,8 +491,8 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
if disable_federation {
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."
"Finished bulk room ban, banned {room_ban_count} total rooms, evicted all users, \
and disabled incoming federation with the room."
)))
} else {
Ok(RoomMessageEventContent::text_plain(format!(
@ -469,16 +502,20 @@ async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Resu
}
#[admin_command]
async fn unban_room(&self, enable_federation: bool, room: Box<RoomOrAliasId>) -> Result<RoomMessageEventContent> {
async fn unban_room(
&self,
enable_federation: bool,
room: Box<RoomOrAliasId>,
) -> Result<RoomMessageEventContent> {
let room_id = if room.is_room_id() {
let room_id = match RoomId::parse(&room) {
Ok(room_id) => room_id,
Err(e) => {
| 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}"
)))
},
"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");
@ -488,18 +525,18 @@ async fn unban_room(&self, enable_federation: bool, room: Box<RoomOrAliasId>) ->
room_id
} else if room.is_room_alias_id() {
let room_alias = match RoomAliasId::parse(&room) {
Ok(room_alias) => room_alias,
Err(e) => {
| 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}"
)))
},
"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"
"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 Ok(room_id) = self
@ -511,7 +548,10 @@ async fn unban_room(&self, enable_federation: bool, room: Box<RoomOrAliasId>) ->
{
room_id
} else {
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
debug!(
"We don't have this room alias to a room ID locally, attempting to fetch room \
ID over federation"
);
match self
.services
@ -520,11 +560,15 @@ async fn unban_room(&self, enable_federation: bool, room: Box<RoomOrAliasId>) ->
.resolve_alias(&room_alias, None)
.await
{
Ok((room_id, servers)) => {
debug!(?room_id, ?servers, "Got federation response fetching room ID for room {room}");
| Ok((room_id, servers)) => {
debug!(
?room_id,
?servers,
"Got federation response fetching room ID for room {room}"
);
room_id
},
Err(e) => {
| Err(e) => {
return Ok(RoomMessageEventContent::text_plain(format!(
"Failed to resolve room alias {room} to a room ID: {e}"
)));
@ -537,8 +581,9 @@ async fn unban_room(&self, enable_federation: bool, room: Box<RoomOrAliasId>) ->
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`)",
"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`)",
));
};
@ -548,8 +593,8 @@ async fn unban_room(&self, enable_federation: bool, room: Box<RoomOrAliasId>) ->
}
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.",
"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.",
))
}

View file

@ -29,13 +29,12 @@ pub(super) async fn show_config(&self) -> Result<RoomMessageEventContent> {
#[admin_command]
pub(super) async fn list_features(
&self, available: bool, enabled: bool, comma: bool,
&self,
available: bool,
enabled: bool,
comma: bool,
) -> Result<RoomMessageEventContent> {
let delim = if comma {
","
} else {
" "
};
let delim = if comma { "," } else { " " };
if enabled && !available {
let features = info::rustc::features().join(delim);
let out = format!("`\n{features}\n`");
@ -53,16 +52,8 @@ pub(super) async fn list_features(
let available = info::cargo::features();
for feature in available {
let active = enabled.contains(&feature.as_str());
let emoji = if active {
""
} else {
""
};
let remark = if active {
"[enabled]"
} else {
""
};
let emoji = if active { "" } else { "" };
let remark = if active { "[enabled]" } else { "" };
writeln!(features, "{emoji} {feature} {remark}")?;
}
@ -73,7 +64,8 @@ pub(super) async fn list_features(
pub(super) async fn memory_usage(&self) -> Result<RoomMessageEventContent> {
let services_usage = self.services.memory_usage().await?;
let database_usage = self.services.db.db.memory_usage()?;
let allocator_usage = conduwuit::alloc::memory_usage().map_or(String::new(), |s| format!("\nAllocator:\n{s}"));
let allocator_usage =
conduwuit::alloc::memory_usage().map_or(String::new(), |s| format!("\nAllocator:\n{s}"));
Ok(RoomMessageEventContent::text_plain(format!(
"Services:\n{services_usage}\nDatabase:\n{database_usage}{allocator_usage}",
@ -106,8 +98,8 @@ pub(super) async fn backup_database(&self) -> Result<RoomMessageEventContent> {
.server
.runtime()
.spawn_blocking(move || match globals.db.backup() {
Ok(()) => String::new(),
Err(e) => e.to_string(),
| Ok(()) => String::new(),
| Err(e) => e.to_string(),
})
.await?;
@ -147,8 +139,8 @@ pub(super) async fn restart(&self, force: bool) -> Result<RoomMessageEventConten
if !force && current_exe_deleted() {
return Err!(
"The server cannot be restarted because the executable changed. If this is expected use --force to \
override."
"The server cannot be restarted because the executable changed. If this is expected \
use --force to override."
);
}

View file

@ -47,12 +47,18 @@ pub(super) async fn list_users(&self) -> Result<RoomMessageEventContent> {
}
#[admin_command]
pub(super) async fn create_user(&self, username: String, password: Option<String>) -> Result<RoomMessageEventContent> {
pub(super) async fn create_user(
&self,
username: String,
password: Option<String>,
) -> Result<RoomMessageEventContent> {
// Validate user id
let user_id = parse_local_user_id(self.services, &username)?;
if self.services.users.exists(&user_id).await {
return Ok(RoomMessageEventContent::text_plain(format!("Userid {user_id} already exists")));
return Ok(RoomMessageEventContent::text_plain(format!(
"Userid {user_id} already exists"
)));
}
if user_id.is_historical() {
@ -120,7 +126,9 @@ pub(super) async fn create_user(&self, username: String, password: Option<String
.server_in_room(self.services.globals.server_name(), &room_id)
.await
{
warn!("Skipping room {room} to automatically join as we have never joined before.");
warn!(
"Skipping room {room} to automatically join as we have never joined before."
);
continue;
}
@ -130,25 +138,31 @@ pub(super) async fn create_user(&self, username: String, password: Option<String
&user_id,
&room_id,
Some("Automatically joining this room upon registration".to_owned()),
&[self.services.globals.server_name().to_owned(), room_server_name.to_owned()],
&[
self.services.globals.server_name().to_owned(),
room_server_name.to_owned(),
],
None,
&None,
)
.await
{
Ok(_response) => {
| Ok(_response) => {
info!("Automatically joined room {room} for user {user_id}");
},
Err(e) => {
| Err(e) => {
self.services
.admin
.send_message(RoomMessageEventContent::text_plain(format!(
"Failed to automatically join room {room} for user {user_id}: {e}"
"Failed to automatically join room {room} for user {user_id}: \
{e}"
)))
.await
.ok();
// don't return this error so we don't fail registrations
error!("Failed to automatically join room {room} for user {user_id}: {e}");
error!(
"Failed to automatically join room {room} for user {user_id}: {e}"
);
},
};
}
@ -181,7 +195,11 @@ pub(super) async fn create_user(&self, username: String, password: Option<String
}
#[admin_command]
pub(super) async fn deactivate(&self, no_leave_rooms: bool, user_id: String) -> Result<RoomMessageEventContent> {
pub(super) async fn deactivate(
&self,
no_leave_rooms: bool,
user_id: String,
) -> Result<RoomMessageEventContent> {
// Validate user id
let user_id = parse_local_user_id(self.services, &user_id)?;
@ -229,7 +247,8 @@ pub(super) async fn reset_password(&self, username: String) -> Result<RoomMessag
if user_id == self.services.globals.server_user {
return Ok(RoomMessageEventContent::text_plain(
"Not allowed to set the password for the server account. Please use the emergency password config option.",
"Not allowed to set the password for the server account. Please use the emergency \
password config option.",
));
}
@ -240,18 +259,24 @@ pub(super) async fn reset_password(&self, username: String) -> Result<RoomMessag
.users
.set_password(&user_id, Some(new_password.as_str()))
{
Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
| Ok(()) => Ok(RoomMessageEventContent::text_plain(format!(
"Successfully reset the password for user {user_id}: `{new_password}`"
))),
Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
| Err(e) => Ok(RoomMessageEventContent::text_plain(format!(
"Couldn't reset the password for user {user_id}: {e}"
))),
}
}
#[admin_command]
pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
pub(super) async fn deactivate_all(
&self,
no_leave_rooms: bool,
force: bool,
) -> Result<RoomMessageEventContent> {
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
@ -269,7 +294,7 @@ pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) ->
for username in usernames {
match parse_active_local_user_id(self.services, username).await {
Ok(user_id) => {
| Ok(user_id) => {
if self.services.users.is_admin(&user_id).await && !force {
self.services
.admin
@ -296,7 +321,7 @@ pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) ->
user_ids.push(user_id);
},
Err(e) => {
| Err(e) => {
self.services
.admin
.send_message(RoomMessageEventContent::text_plain(format!(
@ -313,7 +338,7 @@ pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) ->
for user_id in user_ids {
match self.services.users.deactivate_account(&user_id).await {
Ok(()) => {
| Ok(()) => {
deactivation_count = deactivation_count.saturating_add(1);
if !no_leave_rooms {
info!("Forcing user {user_id} to leave all rooms apart of deactivate-all");
@ -328,14 +353,17 @@ pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) ->
full_user_deactivate(self.services, &user_id, &all_joined_rooms).await?;
update_displayname(self.services, &user_id, None, &all_joined_rooms).await;
update_avatar_url(self.services, &user_id, None, None, &all_joined_rooms).await;
update_avatar_url(self.services, &user_id, None, None, &all_joined_rooms)
.await;
leave_all_rooms(self.services, &user_id).await;
}
},
Err(e) => {
| Err(e) => {
self.services
.admin
.send_message(RoomMessageEventContent::text_plain(format!("Failed deactivating user: {e}")))
.send_message(RoomMessageEventContent::text_plain(format!(
"Failed deactivating user: {e}"
)))
.await
.ok();
},
@ -348,8 +376,8 @@ pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) ->
)))
} else {
Ok(RoomMessageEventContent::text_plain(format!(
"Deactivated {deactivation_count} accounts.\nSkipped admin accounts: {}. Use --force to deactivate admin \
accounts",
"Deactivated {deactivation_count} accounts.\nSkipped admin accounts: {}. Use \
--force to deactivate admin accounts",
admins.join(", ")
)))
}
@ -391,9 +419,13 @@ pub(super) async fn list_joined_rooms(&self, user_id: String) -> Result<RoomMess
#[admin_command]
pub(super) async fn force_join_list_of_local_users(
&self, room_id: OwnedRoomOrAliasId, yes_i_want_to_do_this: bool,
&self,
room_id: OwnedRoomOrAliasId,
yes_i_want_to_do_this: bool,
) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
if self.body.len() < 2
|| !self.body[0].trim().starts_with("```")
|| self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
@ -402,8 +434,8 @@ pub(super) async fn force_join_list_of_local_users(
if !yes_i_want_to_do_this {
return Ok(RoomMessageEventContent::notice_markdown(
"You must pass the --yes-i-want-to-do-this-flag to ensure you really want to force bulk join all \
specified local users.",
"You must pass the --yes-i-want-to-do-this-flag to ensure you really want to force \
bulk join all specified local users.",
));
}
@ -462,7 +494,7 @@ pub(super) async fn force_join_list_of_local_users(
for username in usernames {
match parse_active_local_user_id(self.services, username).await {
Ok(user_id) => {
| Ok(user_id) => {
// don't make the server service account join
if user_id == self.services.globals.server_user {
self.services
@ -477,7 +509,7 @@ pub(super) async fn force_join_list_of_local_users(
user_ids.push(user_id);
},
Err(e) => {
| Err(e) => {
self.services
.admin
.send_message(RoomMessageEventContent::text_plain(format!(
@ -505,10 +537,10 @@ pub(super) async fn force_join_list_of_local_users(
)
.await
{
Ok(_res) => {
| Ok(_res) => {
successful_joins = successful_joins.saturating_add(1);
},
Err(e) => {
| Err(e) => {
debug_warn!("Failed force joining {user_id} to {room_id} during bulk join: {e}");
failed_joins = failed_joins.saturating_add(1);
},
@ -516,18 +548,21 @@ pub(super) async fn force_join_list_of_local_users(
}
Ok(RoomMessageEventContent::notice_markdown(format!(
"{successful_joins} local users have been joined to {room_id}. {failed_joins} joins failed.",
"{successful_joins} local users have been joined to {room_id}. {failed_joins} joins \
failed.",
)))
}
#[admin_command]
pub(super) async fn force_join_all_local_users(
&self, room_id: OwnedRoomOrAliasId, yes_i_want_to_do_this: bool,
&self,
room_id: OwnedRoomOrAliasId,
yes_i_want_to_do_this: bool,
) -> Result<RoomMessageEventContent> {
if !yes_i_want_to_do_this {
return Ok(RoomMessageEventContent::notice_markdown(
"You must pass the --yes-i-want-to-do-this-flag to ensure you really want to force bulk join all local \
users.",
"You must pass the --yes-i-want-to-do-this-flag to ensure you really want to force \
bulk join all local users.",
));
}
@ -598,10 +633,10 @@ pub(super) async fn force_join_all_local_users(
)
.await
{
Ok(_res) => {
| Ok(_res) => {
successful_joins = successful_joins.saturating_add(1);
},
Err(e) => {
| Err(e) => {
debug_warn!("Failed force joining {user_id} to {room_id} during bulk join: {e}");
failed_joins = failed_joins.saturating_add(1);
},
@ -609,13 +644,16 @@ pub(super) async fn force_join_all_local_users(
}
Ok(RoomMessageEventContent::notice_markdown(format!(
"{successful_joins} local users have been joined to {room_id}. {failed_joins} joins failed.",
"{successful_joins} local users have been joined to {room_id}. {failed_joins} joins \
failed.",
)))
}
#[admin_command]
pub(super) async fn force_join_room(
&self, user_id: String, room_id: OwnedRoomOrAliasId,
&self,
user_id: String,
room_id: OwnedRoomOrAliasId,
) -> Result<RoomMessageEventContent> {
let user_id = parse_local_user_id(self.services, &user_id)?;
let (room_id, servers) = self
@ -629,7 +667,8 @@ pub(super) async fn force_join_room(
self.services.globals.user_is_local(&user_id),
"Parsed user_id must be a local user"
);
join_room_by_id_helper(self.services, &user_id, &room_id, None, &servers, None, &None).await?;
join_room_by_id_helper(self.services, &user_id, &room_id, None, &servers, None, &None)
.await?;
Ok(RoomMessageEventContent::notice_markdown(format!(
"{user_id} has been joined to {room_id}.",
@ -638,7 +677,9 @@ pub(super) async fn force_join_room(
#[admin_command]
pub(super) async fn force_leave_room(
&self, user_id: String, room_id: OwnedRoomOrAliasId,
&self,
user_id: String,
room_id: OwnedRoomOrAliasId,
) -> Result<RoomMessageEventContent> {
let user_id = parse_local_user_id(self.services, &user_id)?;
let room_id = self.services.rooms.alias.resolve(&room_id).await?;
@ -656,7 +697,9 @@ pub(super) async fn force_leave_room(
#[admin_command]
pub(super) async fn force_demote(
&self, user_id: String, room_id: OwnedRoomOrAliasId,
&self,
user_id: String,
room_id: OwnedRoomOrAliasId,
) -> Result<RoomMessageEventContent> {
let user_id = parse_local_user_id(self.services, &user_id)?;
let room_id = self.services.rooms.alias.resolve(&room_id).await?;
@ -672,14 +715,19 @@ pub(super) async fn force_demote(
.services
.rooms
.state_accessor
.room_state_get_content::<RoomPowerLevelsEventContent>(&room_id, &StateEventType::RoomPowerLevels, "")
.room_state_get_content::<RoomPowerLevelsEventContent>(
&room_id,
&StateEventType::RoomPowerLevels,
"",
)
.await
.ok();
let user_can_demote_self = room_power_levels
.as_ref()
.is_some_and(|power_levels_content| {
RoomPowerLevels::from(power_levels_content.clone()).user_can_change_user_power_level(&user_id, &user_id)
RoomPowerLevels::from(power_levels_content.clone())
.user_can_change_user_power_level(&user_id, &user_id)
}) || self
.services
.rooms
@ -710,7 +758,8 @@ pub(super) async fn force_demote(
.await?;
Ok(RoomMessageEventContent::notice_markdown(format!(
"User {user_id} demoted themselves to the room default power level in {room_id} - {event_id}"
"User {user_id} demoted themselves to the room default power level in {room_id} - \
{event_id}"
)))
}
@ -731,7 +780,10 @@ pub(super) async fn make_user_admin(&self, user_id: String) -> Result<RoomMessag
#[admin_command]
pub(super) async fn put_room_tag(
&self, user_id: String, room_id: Box<RoomId>, tag: String,
&self,
user_id: String,
room_id: Box<RoomId>,
tag: String,
) -> Result<RoomMessageEventContent> {
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
@ -741,9 +793,7 @@ pub(super) async fn put_room_tag(
.get_room(&room_id, &user_id, RoomAccountDataEventType::Tag)
.await
.unwrap_or(TagEvent {
content: TagEventContent {
tags: BTreeMap::new(),
},
content: TagEventContent { tags: BTreeMap::new() },
});
tags_event
@ -768,7 +818,10 @@ pub(super) async fn put_room_tag(
#[admin_command]
pub(super) async fn delete_room_tag(
&self, user_id: String, room_id: Box<RoomId>, tag: String,
&self,
user_id: String,
room_id: Box<RoomId>,
tag: String,
) -> Result<RoomMessageEventContent> {
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
@ -778,9 +831,7 @@ pub(super) async fn delete_room_tag(
.get_room(&room_id, &user_id, RoomAccountDataEventType::Tag)
.await
.unwrap_or(TagEvent {
content: TagEventContent {
tags: BTreeMap::new(),
},
content: TagEventContent { tags: BTreeMap::new() },
});
tags_event.content.tags.remove(&tag.clone().into());
@ -796,12 +847,17 @@ pub(super) async fn delete_room_tag(
.await?;
Ok(RoomMessageEventContent::text_plain(format!(
"Successfully updated room account data for {user_id} and room {room_id}, deleting room tag {tag}"
"Successfully updated room account data for {user_id} and room {room_id}, deleting room \
tag {tag}"
)))
}
#[admin_command]
pub(super) async fn get_room_tags(&self, user_id: String, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
pub(super) async fn get_room_tags(
&self,
user_id: String,
room_id: Box<RoomId>,
) -> Result<RoomMessageEventContent> {
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
let tags_event = self
@ -810,9 +866,7 @@ pub(super) async fn get_room_tags(&self, user_id: String, room_id: Box<RoomId>)
.get_room(&room_id, &user_id, RoomAccountDataEventType::Tag)
.await
.unwrap_or(TagEvent {
content: TagEventContent {
tags: BTreeMap::new(),
},
content: TagEventContent { tags: BTreeMap::new() },
});
Ok(RoomMessageEventContent::notice_markdown(format!(
@ -822,7 +876,10 @@ pub(super) async fn get_room_tags(&self, user_id: String, room_id: Box<RoomId>)
}
#[admin_command]
pub(super) async fn redact_event(&self, event_id: Box<EventId>) -> Result<RoomMessageEventContent> {
pub(super) async fn redact_event(
&self,
event_id: Box<EventId>,
) -> Result<RoomMessageEventContent> {
let Ok(event) = self
.services
.rooms
@ -841,7 +898,9 @@ pub(super) async fn redact_event(&self, event_id: Box<EventId>) -> Result<RoomMe
let sender_user = event.sender;
if !self.services.globals.user_is_local(&sender_user) {
return Ok(RoomMessageEventContent::text_plain("This command only works on local users."));
return Ok(RoomMessageEventContent::text_plain(
"This command only works on local users.",
));
}
let reason = format!(

View file

@ -8,7 +8,10 @@ pub(crate) fn escape_html(s: &str) -> String {
.replace('>', "&gt;")
}
pub(crate) async fn get_room_info(services: &Services, room_id: &RoomId) -> (OwnedRoomId, u64, String) {
pub(crate) async fn get_room_info(
services: &Services,
room_id: &RoomId,
) -> (OwnedRoomId, u64, String) {
(
room_id.into(),
services
@ -44,7 +47,10 @@ pub(crate) fn parse_local_user_id(services: &Services, user_id: &str) -> Result<
}
/// Parses user ID that is an active (not guest or deactivated) local user
pub(crate) async fn parse_active_local_user_id(services: &Services, user_id: &str) -> Result<OwnedUserId> {
pub(crate) async fn parse_active_local_user_id(
services: &Services,
user_id: &str,
) -> Result<OwnedUserId> {
let user_id = parse_local_user_id(services, user_id)?;
if !services.users.exists(&user_id).await {

View file

@ -2,16 +2,19 @@ use std::fmt::Write;
use axum::extract::State;
use axum_client_ip::InsecureClientIp;
use conduwuit::{debug_info, error, info, is_equal_to, utils, utils::ReadyExt, warn, Error, PduBuilder, Result};
use conduwuit::{
debug_info, error, info, is_equal_to, utils, utils::ReadyExt, warn, Error, PduBuilder, Result,
};
use futures::{FutureExt, StreamExt};
use register::RegistrationKind;
use ruma::{
api::client::{
account::{
change_password, check_registration_token_validity, deactivate, get_3pids, get_username_availability,
change_password, check_registration_token_validity, deactivate, get_3pids,
get_username_availability,
register::{self, LoginType},
request_3pid_management_token_via_email, request_3pid_management_token_via_msisdn, whoami,
ThirdPartyIdRemovalStatus,
request_3pid_management_token_via_email, request_3pid_management_token_via_msisdn,
whoami, ThirdPartyIdRemovalStatus,
},
error::ErrorKind,
uiaa::{AuthFlow, AuthType, UiaaInfo},
@ -45,7 +48,8 @@ const RANDOM_USER_ID_LENGTH: usize = 10;
/// invalid when trying to register
#[tracing::instrument(skip_all, fields(%client), name = "register_available")]
pub(crate) async fn get_register_available_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_username_availability::v3::Request>,
) -> Result<get_username_availability::v3::Response> {
// workaround for https://github.com/matrix-org/matrix-appservice-irc/issues/1780 due to inactivity of fixing the issue
@ -66,7 +70,8 @@ pub(crate) async fn get_register_available_route(
let user_id = UserId::parse_with_server_name(body_username, services.globals.server_name())
.ok()
.filter(|user_id| {
(!user_id.is_historical() || is_matrix_appservice_irc) && services.globals.user_is_local(user_id)
(!user_id.is_historical() || is_matrix_appservice_irc)
&& services.globals.user_is_local(user_id)
})
.ok_or(Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
@ -86,9 +91,7 @@ pub(crate) async fn get_register_available_route(
// TODO add check for appservice namespaces
// If no if check is true we have an username that's available to be used.
Ok(get_username_availability::v3::Response {
available: true,
})
Ok(get_username_availability::v3::Response { available: true })
}
/// # `POST /_matrix/client/v3/register`
@ -111,12 +114,14 @@ pub(crate) async fn get_register_available_route(
#[allow(clippy::doc_markdown)]
#[tracing::instrument(skip_all, fields(%client), name = "register")]
pub(crate) async fn register_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp, body: Ruma<register::v3::Request>,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<register::v3::Request>,
) -> Result<register::v3::Response> {
if !services.globals.allow_registration() && body.appservice_info.is_none() {
info!(
"Registration disabled and request not from known appservice, rejecting registration attempt for username \
\"{}\"",
"Registration disabled and request not from known appservice, rejecting \
registration attempt for username \"{}\"",
body.username.as_deref().unwrap_or("")
);
return Err(Error::BadRequest(ErrorKind::forbidden(), "Registration has been disabled."));
@ -126,11 +131,12 @@ pub(crate) async fn register_route(
if is_guest
&& (!services.globals.allow_guest_registration()
|| (services.globals.allow_registration() && services.globals.registration_token.is_some()))
|| (services.globals.allow_registration()
&& services.globals.registration_token.is_some()))
{
info!(
"Guest registration disabled / registration enabled with token configured, rejecting guest registration \
attempt, initial device name: \"{}\"",
"Guest registration disabled / registration enabled with token configured, \
rejecting guest registration attempt, initial device name: \"{}\"",
body.initial_device_display_name.as_deref().unwrap_or("")
);
return Err(Error::BadRequest(
@ -143,17 +149,21 @@ pub(crate) async fn register_route(
// generic user error.
if is_guest && services.users.count().await < 2 {
warn!(
"Guest account attempted to register before a real admin user has been registered, rejecting \
registration. Guest's initial device name: \"{}\"",
"Guest account attempted to register before a real admin user has been registered, \
rejecting registration. Guest's initial device name: \"{}\"",
body.initial_device_display_name.as_deref().unwrap_or("")
);
return Err(Error::BadRequest(ErrorKind::forbidden(), "Registration temporarily disabled."));
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Registration temporarily disabled.",
));
}
let user_id = match (&body.username, is_guest) {
(Some(username), false) => {
| (Some(username), false) => {
// workaround for https://github.com/matrix-org/matrix-appservice-irc/issues/1780 due to inactivity of fixing the issue
let is_matrix_appservice_irc = body.appservice_info.as_ref().is_some_and(|appservice| {
let is_matrix_appservice_irc =
body.appservice_info.as_ref().is_some_and(|appservice| {
appservice.registration.id == "irc"
|| appservice.registration.id.contains("matrix-appservice-irc")
|| appservice.registration.id.contains("matrix_appservice_irc")
@ -166,15 +176,23 @@ pub(crate) async fn register_route(
username.to_lowercase()
};
let proposed_user_id = UserId::parse_with_server_name(body_username, services.globals.server_name())
let proposed_user_id =
UserId::parse_with_server_name(body_username, services.globals.server_name())
.ok()
.filter(|user_id| {
(!user_id.is_historical() || is_matrix_appservice_irc) && services.globals.user_is_local(user_id)
(!user_id.is_historical() || is_matrix_appservice_irc)
&& services.globals.user_is_local(user_id)
})
.ok_or(Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
.ok_or(Error::BadRequest(
ErrorKind::InvalidUsername,
"Username is invalid.",
))?;
if services.users.exists(&proposed_user_id).await {
return Err(Error::BadRequest(ErrorKind::UserInUse, "Desired user ID is already taken."));
return Err(Error::BadRequest(
ErrorKind::UserInUse,
"Desired user ID is already taken.",
));
}
if services
@ -187,7 +205,7 @@ pub(crate) async fn register_route(
proposed_user_id
},
_ => loop {
| _ => loop {
let proposed_user_id = UserId::parse_with_server_name(
utils::random_string(RANDOM_USER_ID_LENGTH).to_lowercase(),
services.globals.server_name(),
@ -228,9 +246,7 @@ pub(crate) async fn register_route(
} else {
// No registration token necessary, but clients must still go through the flow
uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Dummy],
}],
flows: vec![AuthFlow { stages: vec![AuthType::Dummy] }],
completed: Vec::new(),
params: Box::default(),
session: None,
@ -244,7 +260,8 @@ pub(crate) async fn register_route(
let (worked, uiaainfo) = services
.uiaa
.try_auth(
&UserId::parse_with_server_name("", services.globals.server_name()).expect("we know this is valid"),
&UserId::parse_with_server_name("", services.globals.server_name())
.expect("we know this is valid"),
"".into(),
auth,
&uiaainfo,
@ -257,7 +274,8 @@ pub(crate) async fn register_route(
} else if let Some(json) = body.json_body {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services.uiaa.create(
&UserId::parse_with_server_name("", services.globals.server_name()).expect("we know this is valid"),
&UserId::parse_with_server_name("", services.globals.server_name())
.expect("we know this is valid"),
"".into(),
&uiaainfo,
&json,
@ -268,11 +286,7 @@ pub(crate) async fn register_route(
}
}
let password = if is_guest {
None
} else {
body.password.as_deref()
};
let password = if is_guest { None } else { body.password.as_deref() };
// Create user
services.users.create(&user_id, password)?;
@ -282,7 +296,9 @@ pub(crate) async fn register_route(
// If `new_user_displayname_suffix` is set, registration will push whatever
// content is set to the user's display name with a space before it
if !services.globals.new_user_displayname_suffix().is_empty() && body.appservice_info.is_none() {
if !services.globals.new_user_displayname_suffix().is_empty()
&& body.appservice_info.is_none()
{
write!(displayname, " {}", services.globals.config.new_user_displayname_suffix)
.expect("should be able to write to string buffer");
}
@ -319,11 +335,7 @@ pub(crate) async fn register_route(
}
// Generate new device id if the user didn't specify one
let device_id = if is_guest {
None
} else {
body.device_id.clone()
}
let device_id = if is_guest { None } else { body.device_id.clone() }
.unwrap_or_else(|| utils::random_string(DEVICE_ID_LENGTH).into());
// Generate new token for the device
@ -349,15 +361,16 @@ pub(crate) async fn register_route(
if body.appservice_info.is_none() && !is_guest {
if !device_display_name.is_empty() {
info!(
"New user \"{user_id}\" registered on this server with device display name: \"{device_display_name}\""
"New user \"{user_id}\" registered on this server with device display name: \
\"{device_display_name}\""
);
if services.globals.config.admin_room_notices {
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"New user \"{user_id}\" registered on this server from IP {client} and device display name \
\"{device_display_name}\""
"New user \"{user_id}\" registered on this server from IP {client} and \
device display name \"{device_display_name}\""
)))
.await
.ok();
@ -386,8 +399,8 @@ pub(crate) async fn register_route(
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"Guest user \"{user_id}\" with device display name \"{device_display_name}\" registered on \
this server from IP {client}"
"Guest user \"{user_id}\" with device display name \
\"{device_display_name}\" registered on this server from IP {client}"
)))
.await
.ok();
@ -398,8 +411,8 @@ pub(crate) async fn register_route(
services
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"Guest user \"{user_id}\" with no device display name registered on this server from IP \
{client}",
"Guest user \"{user_id}\" with no device display name registered on \
this server from IP {client}",
)))
.await
.ok();
@ -430,7 +443,10 @@ pub(crate) async fn register_route(
{
for room in &services.globals.config.auto_join_rooms {
let Ok(room_id) = services.rooms.alias.resolve(room).await else {
error!("Failed to resolve room alias to room ID when attempting to auto join {room}, skipping");
error!(
"Failed to resolve room alias to room ID when attempting to auto join \
{room}, skipping"
);
continue;
};
@ -440,7 +456,9 @@ pub(crate) async fn register_route(
.server_in_room(services.globals.server_name(), &room_id)
.await
{
warn!("Skipping room {room} to automatically join as we have never joined before.");
warn!(
"Skipping room {room} to automatically join as we have never joined before."
);
continue;
}
@ -494,7 +512,8 @@ pub(crate) async fn register_route(
/// - Triggers device list updates
#[tracing::instrument(skip_all, fields(%client), name = "change_password")]
pub(crate) async fn change_password_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<change_password::v3::Request>,
) -> Result<change_password::v3::Response> {
// Authentication for this endpoint was made optional, but we need
@ -506,9 +525,7 @@ pub(crate) async fn change_password_route(
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Password],
}],
flows: vec![AuthFlow { stages: vec![AuthType::Password] }],
completed: Vec::new(),
params: Box::default(),
session: None,
@ -572,7 +589,8 @@ pub(crate) async fn change_password_route(
///
/// Note: Also works for Application Services
pub(crate) async fn whoami_route(
State(services): State<crate::State>, body: Ruma<whoami::v3::Request>,
State(services): State<crate::State>,
body: Ruma<whoami::v3::Request>,
) -> Result<whoami::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let device_id = body.sender_device.clone();
@ -580,7 +598,8 @@ pub(crate) async fn whoami_route(
Ok(whoami::v3::Response {
user_id: sender_user.clone(),
device_id,
is_guest: services.users.is_deactivated(sender_user).await? && body.appservice_info.is_none(),
is_guest: services.users.is_deactivated(sender_user).await?
&& body.appservice_info.is_none(),
})
}
@ -597,7 +616,8 @@ pub(crate) async fn whoami_route(
/// - Removes ability to log in again
#[tracing::instrument(skip_all, fields(%client), name = "deactivate")]
pub(crate) async fn deactivate_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<deactivate::v3::Request>,
) -> Result<deactivate::v3::Response> {
// Authentication for this endpoint was made optional, but we need
@ -609,9 +629,7 @@ pub(crate) async fn deactivate_route(
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Password],
}],
flows: vec![AuthFlow { stages: vec![AuthType::Password] }],
completed: Vec::new(),
params: Box::default(),
session: None,
@ -675,7 +693,9 @@ pub(crate) async fn deactivate_route(
/// Get a list of third party identifiers associated with this account.
///
/// - Currently always returns empty list
pub(crate) async fn third_party_route(body: Ruma<get_3pids::v3::Request>) -> Result<get_3pids::v3::Response> {
pub(crate) async fn third_party_route(
body: Ruma<get_3pids::v3::Request>,
) -> Result<get_3pids::v3::Response> {
let _sender_user = body.sender_user.as_ref().expect("user is authenticated");
Ok(get_3pids::v3::Response::new(Vec::new()))
@ -720,7 +740,8 @@ pub(crate) async fn request_3pid_management_token_via_msisdn_route(
/// Currently does not have any ratelimiting, and this isn't very practical as
/// there is only one registration token allowed.
pub(crate) async fn check_registration_token_validity(
State(services): State<crate::State>, body: Ruma<check_registration_token_validity::v1::Request>,
State(services): State<crate::State>,
body: Ruma<check_registration_token_validity::v1::Request>,
) -> Result<check_registration_token_validity::v1::Response> {
let Some(reg_token) = services.globals.registration_token.clone() else {
return Err(Error::BadRequest(
@ -729,9 +750,7 @@ pub(crate) async fn check_registration_token_validity(
));
};
Ok(check_registration_token_validity::v1::Response {
valid: reg_token == body.token,
})
Ok(check_registration_token_validity::v1::Response { valid: reg_token == body.token })
}
/// Runs through all the deactivation steps:
@ -742,7 +761,9 @@ pub(crate) async fn check_registration_token_validity(
/// - Removing all profile data
/// - Leaving all rooms (and forgets all of them)
pub async fn full_user_deactivate(
services: &Services, user_id: &UserId, all_joined_rooms: &[OwnedRoomId],
services: &Services,
user_id: &UserId,
all_joined_rooms: &[OwnedRoomId],
) -> Result<()> {
services.users.deactivate_account(user_id).await.ok();
super::update_displayname(services, user_id, None, all_joined_rooms).await;
@ -751,7 +772,9 @@ pub async fn full_user_deactivate(
services
.users
.all_profile_keys(user_id)
.ready_for_each(|(profile_key, _)| services.users.set_profile_key(user_id, &profile_key, None))
.ready_for_each(|(profile_key, _)| {
services.users.set_profile_key(user_id, &profile_key, None);
})
.await;
for room_id in all_joined_rooms {
@ -760,14 +783,20 @@ pub async fn full_user_deactivate(
let room_power_levels = services
.rooms
.state_accessor
.room_state_get_content::<RoomPowerLevelsEventContent>(room_id, &StateEventType::RoomPowerLevels, "")
.room_state_get_content::<RoomPowerLevelsEventContent>(
room_id,
&StateEventType::RoomPowerLevels,
"",
)
.await
.ok();
let user_can_demote_self = room_power_levels
let user_can_demote_self =
room_power_levels
.as_ref()
.is_some_and(|power_levels_content| {
RoomPowerLevels::from(power_levels_content.clone()).user_can_change_user_power_level(user_id, user_id)
RoomPowerLevels::from(power_levels_content.clone())
.user_can_change_user_power_level(user_id, user_id)
}) || services
.rooms
.state_accessor

View file

@ -2,11 +2,12 @@ use axum::extract::State;
use conduwuit::{err, Err};
use ruma::{
api::client::config::{
get_global_account_data, get_room_account_data, set_global_account_data, set_room_account_data,
get_global_account_data, get_room_account_data, set_global_account_data,
set_room_account_data,
},
events::{
AnyGlobalAccountDataEventContent, AnyRoomAccountDataEventContent, GlobalAccountDataEventType,
RoomAccountDataEventType,
AnyGlobalAccountDataEventContent, AnyRoomAccountDataEventContent,
GlobalAccountDataEventType, RoomAccountDataEventType,
},
serde::Raw,
RoomId, UserId,
@ -20,7 +21,8 @@ use crate::{service::Services, Result, Ruma};
///
/// Sets some account data for the sender user.
pub(crate) async fn set_global_account_data_route(
State(services): State<crate::State>, body: Ruma<set_global_account_data::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_global_account_data::v3::Request>,
) -> Result<set_global_account_data::v3::Response> {
let sender_user = body.sender_user();
@ -28,7 +30,14 @@ pub(crate) async fn set_global_account_data_route(
return Err!(Request(Forbidden("You cannot set account data for other users.")));
}
set_account_data(&services, None, &body.user_id, &body.event_type.to_string(), body.data.json()).await?;
set_account_data(
&services,
None,
&body.user_id,
&body.event_type.to_string(),
body.data.json(),
)
.await?;
Ok(set_global_account_data::v3::Response {})
}
@ -37,7 +46,8 @@ pub(crate) async fn set_global_account_data_route(
///
/// Sets some room account data for the sender user.
pub(crate) async fn set_room_account_data_route(
State(services): State<crate::State>, body: Ruma<set_room_account_data::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_room_account_data::v3::Request>,
) -> Result<set_room_account_data::v3::Response> {
let sender_user = body.sender_user();
@ -61,7 +71,8 @@ pub(crate) async fn set_room_account_data_route(
///
/// Gets some account data for the sender user.
pub(crate) async fn get_global_account_data_route(
State(services): State<crate::State>, body: Ruma<get_global_account_data::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_global_account_data::v3::Request>,
) -> Result<get_global_account_data::v3::Response> {
let sender_user = body.sender_user();
@ -75,16 +86,15 @@ pub(crate) async fn get_global_account_data_route(
.await
.map_err(|_| err!(Request(NotFound("Data not found."))))?;
Ok(get_global_account_data::v3::Response {
account_data: account_data.content,
})
Ok(get_global_account_data::v3::Response { account_data: account_data.content })
}
/// # `GET /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}`
///
/// Gets some room account data for the sender user.
pub(crate) async fn get_room_account_data_route(
State(services): State<crate::State>, body: Ruma<get_room_account_data::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_room_account_data::v3::Request>,
) -> Result<get_room_account_data::v3::Response> {
let sender_user = body.sender_user();
@ -98,17 +108,20 @@ pub(crate) async fn get_room_account_data_route(
.await
.map_err(|_| err!(Request(NotFound("Data not found."))))?;
Ok(get_room_account_data::v3::Response {
account_data: account_data.content,
})
Ok(get_room_account_data::v3::Response { account_data: account_data.content })
}
async fn set_account_data(
services: &Services, room_id: Option<&RoomId>, sender_user: &UserId, event_type_s: &str, data: &RawJsonValue,
services: &Services,
room_id: Option<&RoomId>,
sender_user: &UserId,
event_type_s: &str,
data: &RawJsonValue,
) -> Result {
if event_type_s == RoomAccountDataEventType::FullyRead.to_cow_str() {
return Err!(Request(BadJson(
"This endpoint cannot be used for marking a room as fully read (setting m.fully_read)"
"This endpoint cannot be used for marking a room as fully read (setting \
m.fully_read)"
)));
}
@ -118,8 +131,8 @@ async fn set_account_data(
)));
}
let data: serde_json::Value =
serde_json::from_str(data.get()).map_err(|e| err!(Request(BadJson(warn!("Invalid JSON provided: {e}")))))?;
let data: serde_json::Value = serde_json::from_str(data.get())
.map_err(|e| err!(Request(BadJson(warn!("Invalid JSON provided: {e}")))))?;
services
.account_data

View file

@ -14,7 +14,8 @@ use crate::Ruma;
///
/// Creates a new room alias on this server.
pub(crate) async fn create_alias_route(
State(services): State<crate::State>, body: Ruma<create_alias::v3::Request>,
State(services): State<crate::State>,
body: Ruma<create_alias::v3::Request>,
) -> Result<create_alias::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -58,7 +59,8 @@ pub(crate) async fn create_alias_route(
///
/// - TODO: Update canonical alias event
pub(crate) async fn delete_alias_route(
State(services): State<crate::State>, body: Ruma<delete_alias::v3::Request>,
State(services): State<crate::State>,
body: Ruma<delete_alias::v3::Request>,
) -> Result<delete_alias::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -83,11 +85,13 @@ pub(crate) async fn delete_alias_route(
///
/// Resolve an alias locally or over federation.
pub(crate) async fn get_alias_route(
State(services): State<crate::State>, body: Ruma<get_alias::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_alias::v3::Request>,
) -> Result<get_alias::v3::Response> {
let room_alias = body.body.room_alias;
let Ok((room_id, servers)) = services.rooms.alias.resolve_alias(&room_alias, None).await else {
let Ok((room_id, servers)) = services.rooms.alias.resolve_alias(&room_alias, None).await
else {
return Err!(Request(NotFound("Room with alias not found.")));
};
@ -98,7 +102,10 @@ pub(crate) async fn get_alias_route(
}
async fn room_available_servers(
services: &Services, room_id: &RoomId, room_alias: &RoomAliasId, pre_servers: Vec<OwnedServerName>,
services: &Services,
room_id: &RoomId,
room_alias: &RoomAliasId,
pre_servers: Vec<OwnedServerName>,
) -> Vec<OwnedServerName> {
// find active servers in room state cache to suggest
let mut servers: Vec<OwnedServerName> = services

View file

@ -9,12 +9,12 @@ use crate::Ruma;
/// Ask the homeserver to ping the application service to ensure the connection
/// works.
pub(crate) async fn appservice_ping(
State(services): State<crate::State>, body: Ruma<request_ping::v1::Request>,
State(services): State<crate::State>,
body: Ruma<request_ping::v1::Request>,
) -> Result<request_ping::v1::Response> {
let appservice_info = body
.appservice_info
.as_ref()
.ok_or_else(|| err!(Request(Forbidden("This endpoint can only be called by appservices."))))?;
let appservice_info = body.appservice_info.as_ref().ok_or_else(|| {
err!(Request(Forbidden("This endpoint can only be called by appservices.")))
})?;
if body.appservice_id != appservice_info.registration.id {
return Err!(Request(Forbidden(
@ -41,7 +41,5 @@ pub(crate) async fn appservice_ping(
.await?
.expect("We already validated if an appservice URL exists above");
Ok(request_ping::v1::Response {
duration: timer.elapsed(),
})
Ok(request_ping::v1::Response { duration: timer.elapsed() })
}

View file

@ -2,10 +2,11 @@ use axum::extract::State;
use conduwuit::{err, Err};
use ruma::{
api::client::backup::{
add_backup_keys, add_backup_keys_for_room, add_backup_keys_for_session, create_backup_version,
delete_backup_keys, delete_backup_keys_for_room, delete_backup_keys_for_session, delete_backup_version,
get_backup_info, get_backup_keys, get_backup_keys_for_room, get_backup_keys_for_session,
get_latest_backup_info, update_backup_version,
add_backup_keys, add_backup_keys_for_room, add_backup_keys_for_session,
create_backup_version, delete_backup_keys, delete_backup_keys_for_room,
delete_backup_keys_for_session, delete_backup_version, get_backup_info, get_backup_keys,
get_backup_keys_for_room, get_backup_keys_for_session, get_latest_backup_info,
update_backup_version,
},
UInt,
};
@ -16,15 +17,14 @@ use crate::{Result, Ruma};
///
/// Creates a new backup.
pub(crate) async fn create_backup_version_route(
State(services): State<crate::State>, body: Ruma<create_backup_version::v3::Request>,
State(services): State<crate::State>,
body: Ruma<create_backup_version::v3::Request>,
) -> Result<create_backup_version::v3::Response> {
let version = services
.key_backups
.create_backup(body.sender_user(), &body.algorithm)?;
Ok(create_backup_version::v3::Response {
version,
})
Ok(create_backup_version::v3::Response { version })
}
/// # `PUT /_matrix/client/r0/room_keys/version/{version}`
@ -32,7 +32,8 @@ pub(crate) async fn create_backup_version_route(
/// Update information about an existing backup. Only `auth_data` can be
/// modified.
pub(crate) async fn update_backup_version_route(
State(services): State<crate::State>, body: Ruma<update_backup_version::v3::Request>,
State(services): State<crate::State>,
body: Ruma<update_backup_version::v3::Request>,
) -> Result<update_backup_version::v3::Response> {
services
.key_backups
@ -46,7 +47,8 @@ pub(crate) async fn update_backup_version_route(
///
/// Get information about the latest backup version.
pub(crate) async fn get_latest_backup_info_route(
State(services): State<crate::State>, body: Ruma<get_latest_backup_info::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_latest_backup_info::v3::Request>,
) -> Result<get_latest_backup_info::v3::Response> {
let (version, algorithm) = services
.key_backups
@ -75,13 +77,16 @@ pub(crate) async fn get_latest_backup_info_route(
///
/// Get information about an existing backup.
pub(crate) async fn get_backup_info_route(
State(services): State<crate::State>, body: Ruma<get_backup_info::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_backup_info::v3::Request>,
) -> Result<get_backup_info::v3::Response> {
let algorithm = services
.key_backups
.get_backup(body.sender_user(), &body.version)
.await
.map_err(|_| err!(Request(NotFound("Key backup does not exist at version {:?}", body.version))))?;
.map_err(|_| {
err!(Request(NotFound("Key backup does not exist at version {:?}", body.version)))
})?;
Ok(get_backup_info::v3::Response {
algorithm,
@ -105,7 +110,8 @@ pub(crate) async fn get_backup_info_route(
/// - Deletes both information about the backup, as well as all key data related
/// to the backup
pub(crate) async fn delete_backup_version_route(
State(services): State<crate::State>, body: Ruma<delete_backup_version::v3::Request>,
State(services): State<crate::State>,
body: Ruma<delete_backup_version::v3::Request>,
) -> Result<delete_backup_version::v3::Response> {
services
.key_backups
@ -124,7 +130,8 @@ pub(crate) async fn delete_backup_version_route(
/// - Adds the keys to the backup
/// - Returns the new number of keys in this backup and the etag
pub(crate) async fn add_backup_keys_route(
State(services): State<crate::State>, body: Ruma<add_backup_keys::v3::Request>,
State(services): State<crate::State>,
body: Ruma<add_backup_keys::v3::Request>,
) -> Result<add_backup_keys::v3::Response> {
if services
.key_backups
@ -168,7 +175,8 @@ pub(crate) async fn add_backup_keys_route(
/// - Adds the keys to the backup
/// - Returns the new number of keys in this backup and the etag
pub(crate) async fn add_backup_keys_for_room_route(
State(services): State<crate::State>, body: Ruma<add_backup_keys_for_room::v3::Request>,
State(services): State<crate::State>,
body: Ruma<add_backup_keys_for_room::v3::Request>,
) -> Result<add_backup_keys_for_room::v3::Response> {
if services
.key_backups
@ -210,7 +218,8 @@ pub(crate) async fn add_backup_keys_for_room_route(
/// - Adds the keys to the backup
/// - Returns the new number of keys in this backup and the etag
pub(crate) async fn add_backup_keys_for_session_route(
State(services): State<crate::State>, body: Ruma<add_backup_keys_for_session::v3::Request>,
State(services): State<crate::State>,
body: Ruma<add_backup_keys_for_session::v3::Request>,
) -> Result<add_backup_keys_for_session::v3::Response> {
if services
.key_backups
@ -251,56 +260,56 @@ pub(crate) async fn add_backup_keys_for_session_route(
///
/// Retrieves all keys from the backup.
pub(crate) async fn get_backup_keys_route(
State(services): State<crate::State>, body: Ruma<get_backup_keys::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_backup_keys::v3::Request>,
) -> Result<get_backup_keys::v3::Response> {
let rooms = services
.key_backups
.get_all(body.sender_user(), &body.version)
.await;
Ok(get_backup_keys::v3::Response {
rooms,
})
Ok(get_backup_keys::v3::Response { rooms })
}
/// # `GET /_matrix/client/r0/room_keys/keys/{roomId}`
///
/// Retrieves all keys from the backup for a given room.
pub(crate) async fn get_backup_keys_for_room_route(
State(services): State<crate::State>, body: Ruma<get_backup_keys_for_room::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_backup_keys_for_room::v3::Request>,
) -> Result<get_backup_keys_for_room::v3::Response> {
let sessions = services
.key_backups
.get_room(body.sender_user(), &body.version, &body.room_id)
.await;
Ok(get_backup_keys_for_room::v3::Response {
sessions,
})
Ok(get_backup_keys_for_room::v3::Response { sessions })
}
/// # `GET /_matrix/client/r0/room_keys/keys/{roomId}/{sessionId}`
///
/// Retrieves a key from the backup.
pub(crate) async fn get_backup_keys_for_session_route(
State(services): State<crate::State>, body: Ruma<get_backup_keys_for_session::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_backup_keys_for_session::v3::Request>,
) -> Result<get_backup_keys_for_session::v3::Response> {
let key_data = services
.key_backups
.get_session(body.sender_user(), &body.version, &body.room_id, &body.session_id)
.await
.map_err(|_| err!(Request(NotFound(debug_error!("Backup key not found for this user's session.")))))?;
.map_err(|_| {
err!(Request(NotFound(debug_error!("Backup key not found for this user's session."))))
})?;
Ok(get_backup_keys_for_session::v3::Response {
key_data,
})
Ok(get_backup_keys_for_session::v3::Response { key_data })
}
/// # `DELETE /_matrix/client/r0/room_keys/keys`
///
/// Delete the keys from the backup.
pub(crate) async fn delete_backup_keys_route(
State(services): State<crate::State>, body: Ruma<delete_backup_keys::v3::Request>,
State(services): State<crate::State>,
body: Ruma<delete_backup_keys::v3::Request>,
) -> Result<delete_backup_keys::v3::Response> {
services
.key_backups
@ -324,7 +333,8 @@ pub(crate) async fn delete_backup_keys_route(
///
/// Delete the keys from the backup for a given room.
pub(crate) async fn delete_backup_keys_for_room_route(
State(services): State<crate::State>, body: Ruma<delete_backup_keys_for_room::v3::Request>,
State(services): State<crate::State>,
body: Ruma<delete_backup_keys_for_room::v3::Request>,
) -> Result<delete_backup_keys_for_room::v3::Response> {
services
.key_backups
@ -348,7 +358,8 @@ pub(crate) async fn delete_backup_keys_for_room_route(
///
/// Delete a key from the backup.
pub(crate) async fn delete_backup_keys_for_session_route(
State(services): State<crate::State>, body: Ruma<delete_backup_keys_for_session::v3::Request>,
State(services): State<crate::State>,
body: Ruma<delete_backup_keys_for_session::v3::Request>,
) -> Result<delete_backup_keys_for_session::v3::Response> {
services
.key_backups

View file

@ -3,8 +3,8 @@ use std::collections::BTreeMap;
use axum::extract::State;
use ruma::{
api::client::discovery::get_capabilities::{
self, Capabilities, GetLoginTokenCapability, RoomVersionStability, RoomVersionsCapability,
ThirdPartyIdChangesCapability,
self, Capabilities, GetLoginTokenCapability, RoomVersionStability,
RoomVersionsCapability, ThirdPartyIdChangesCapability,
},
RoomVersionId,
};
@ -17,9 +17,11 @@ use crate::{Result, Ruma};
/// Get information on the supported feature set and other relevent capabilities
/// of this server.
pub(crate) async fn get_capabilities_route(
State(services): State<crate::State>, _body: Ruma<get_capabilities::v3::Request>,
State(services): State<crate::State>,
_body: Ruma<get_capabilities::v3::Request>,
) -> Result<get_capabilities::v3::Response> {
let available: BTreeMap<RoomVersionId, RoomVersionStability> = services.server.available_room_versions().collect();
let available: BTreeMap<RoomVersionId, RoomVersionStability> =
services.server.available_room_versions().collect();
let mut capabilities = Capabilities::default();
capabilities.room_versions = RoomVersionsCapability {
@ -28,21 +30,15 @@ pub(crate) async fn get_capabilities_route(
};
// we do not implement 3PID stuff
capabilities.thirdparty_id_changes = ThirdPartyIdChangesCapability {
enabled: false,
};
capabilities.thirdparty_id_changes = ThirdPartyIdChangesCapability { enabled: false };
// we dont support generating tokens yet
capabilities.get_login_token = GetLoginTokenCapability {
enabled: false,
};
capabilities.get_login_token = GetLoginTokenCapability { enabled: false };
// MSC4133 capability
capabilities
.set("uk.tcpip.msc4133.profile_fields", json!({"enabled": true}))
.expect("this is valid JSON we created");
Ok(get_capabilities::v3::Response {
capabilities,
})
Ok(get_capabilities::v3::Response { capabilities })
}

View file

@ -32,7 +32,8 @@ const LIMIT_DEFAULT: usize = 10;
/// - Only works if the user is joined (TODO: always allow, but only show events
/// if the user was joined, depending on history_visibility)
pub(crate) async fn get_context_route(
State(services): State<crate::State>, body: Ruma<get_context::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_context::v3::Request>,
) -> Result<get_context::v3::Response> {
let filter = &body.filter;
let sender = body.sender();
@ -50,9 +51,8 @@ pub(crate) async fn get_context_route(
// members for "inline" profiles on the timeline to work properly
let lazy_load_enabled = matches!(filter.lazy_load_options, LazyLoadOptions::Enabled { .. });
let lazy_load_redundant = if let LazyLoadOptions::Enabled {
include_redundant_members,
} = filter.lazy_load_options
let lazy_load_redundant = if let LazyLoadOptions::Enabled { include_redundant_members } =
filter.lazy_load_options
{
include_redundant_members
} else {
@ -91,7 +91,8 @@ pub(crate) async fn get_context_route(
return Err!(Request(Forbidden("You don't have permission to view this event.")));
}
let events_before = services
let events_before =
services
.rooms
.timeline
.pdus_rev(Some(sender_user), room_id, Some(base_token));
@ -166,7 +167,9 @@ pub(crate) async fn get_context_route(
.filter(|&user_id: &&UserId| lazy.contains(user_id))
.map(|_| event_id)
})
.broad_filter_map(|event_id: &OwnedEventId| services.rooms.timeline.get_pdu(event_id).ok())
.broad_filter_map(|event_id: &OwnedEventId| {
services.rooms.timeline.get_pdu(event_id).ok()
})
.map(|pdu| pdu.to_state_event())
.collect()
.await;

View file

@ -18,7 +18,8 @@ use crate::{utils, Error, Result, Ruma};
///
/// Get metadata on all devices of the sender user.
pub(crate) async fn get_devices_route(
State(services): State<crate::State>, body: Ruma<get_devices::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_devices::v3::Request>,
) -> Result<get_devices::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -28,16 +29,15 @@ pub(crate) async fn get_devices_route(
.collect()
.await;
Ok(get_devices::v3::Response {
devices,
})
Ok(get_devices::v3::Response { devices })
}
/// # `GET /_matrix/client/r0/devices/{deviceId}`
///
/// Get metadata on a single device of the sender user.
pub(crate) async fn get_device_route(
State(services): State<crate::State>, body: Ruma<get_device::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_device::v3::Request>,
) -> Result<get_device::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -47,9 +47,7 @@ pub(crate) async fn get_device_route(
.await
.map_err(|_| err!(Request(NotFound("Device not found."))))?;
Ok(get_device::v3::Response {
device,
})
Ok(get_device::v3::Response { device })
}
/// # `PUT /_matrix/client/r0/devices/{deviceId}`
@ -57,7 +55,8 @@ pub(crate) async fn get_device_route(
/// Updates the metadata on a given device of the sender user.
#[tracing::instrument(skip_all, fields(%client), name = "update_device")]
pub(crate) async fn update_device_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<update_device::v3::Request>,
) -> Result<update_device::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -93,16 +92,15 @@ pub(crate) async fn update_device_route(
/// - Forgets to-device events
/// - Triggers device list updates
pub(crate) async fn delete_device_route(
State(services): State<crate::State>, body: Ruma<delete_device::v3::Request>,
State(services): State<crate::State>,
body: Ruma<delete_device::v3::Request>,
) -> Result<delete_device::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
// UIAA
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Password],
}],
flows: vec![AuthFlow { stages: vec![AuthType::Password] }],
completed: Vec::new(),
params: Box::default(),
session: None,
@ -151,16 +149,15 @@ pub(crate) async fn delete_device_route(
/// - Forgets to-device events
/// - Triggers device list updates
pub(crate) async fn delete_devices_route(
State(services): State<crate::State>, body: Ruma<delete_devices::v3::Request>,
State(services): State<crate::State>,
body: Ruma<delete_devices::v3::Request>,
) -> Result<delete_devices::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
// UIAA
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Password],
}],
flows: vec![AuthFlow { stages: vec![AuthType::Password] }],
completed: Vec::new(),
params: Box::default(),
session: None,

View file

@ -5,7 +5,10 @@ use futures::{StreamExt, TryFutureExt};
use ruma::{
api::{
client::{
directory::{get_public_rooms, get_public_rooms_filtered, get_room_visibility, set_room_visibility},
directory::{
get_public_rooms, get_public_rooms_filtered, get_room_visibility,
set_room_visibility,
},
error::ErrorKind,
room,
},
@ -32,7 +35,8 @@ use crate::Ruma;
/// - Rooms are ordered by the number of joined members
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms")]
pub(crate) async fn get_public_rooms_filtered_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_public_rooms_filtered::v3::Request>,
) -> Result<get_public_rooms_filtered::v3::Response> {
if let Some(server) = &body.server {
@ -57,7 +61,10 @@ pub(crate) async fn get_public_rooms_filtered_route(
.await
.map_err(|e| {
warn!(?body.server, "Failed to return /publicRooms: {e}");
Error::BadRequest(ErrorKind::Unknown, "Failed to return the requested server's public room list.")
Error::BadRequest(
ErrorKind::Unknown,
"Failed to return the requested server's public room list.",
)
})?;
Ok(response)
@ -70,7 +77,8 @@ pub(crate) async fn get_public_rooms_filtered_route(
/// - Rooms are ordered by the number of joined members
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms")]
pub(crate) async fn get_public_rooms_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_public_rooms::v3::Request>,
) -> Result<get_public_rooms::v3::Response> {
if let Some(server) = &body.server {
@ -95,7 +103,10 @@ pub(crate) async fn get_public_rooms_route(
.await
.map_err(|e| {
warn!(?body.server, "Failed to return /publicRooms: {e}");
Error::BadRequest(ErrorKind::Unknown, "Failed to return the requested server's public room list.")
Error::BadRequest(
ErrorKind::Unknown,
"Failed to return the requested server's public room list.",
)
})?;
Ok(get_public_rooms::v3::Response {
@ -111,7 +122,8 @@ pub(crate) async fn get_public_rooms_route(
/// Sets the visibility of a given room in the room directory.
#[tracing::instrument(skip_all, fields(%client), name = "room_directory")]
pub(crate) async fn set_room_visibility_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<set_room_visibility::v3::Request>,
) -> Result<set_room_visibility::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -139,14 +151,14 @@ pub(crate) async fn set_room_visibility_route(
}
match &body.visibility {
room::Visibility::Public => {
| room::Visibility::Public => {
if services.globals.config.lockdown_public_room_directory
&& !services.users.is_admin(sender_user).await
&& body.appservice_info.is_none()
{
info!(
"Non-admin user {sender_user} tried to publish {0} to the room directory while \
\"lockdown_public_room_directory\" is enabled",
"Non-admin user {sender_user} tried to publish {0} to the room directory \
while \"lockdown_public_room_directory\" is enabled",
body.room_id
);
@ -154,8 +166,8 @@ pub(crate) async fn set_room_visibility_route(
services
.admin
.send_text(&format!(
"Non-admin user {sender_user} tried to publish {0} to the room directory while \
\"lockdown_public_room_directory\" is enabled",
"Non-admin user {sender_user} tried to publish {0} to the room \
directory while \"lockdown_public_room_directory\" is enabled",
body.room_id
))
.await;
@ -172,13 +184,16 @@ pub(crate) async fn set_room_visibility_route(
if services.globals.config.admin_room_notices {
services
.admin
.send_text(&format!("{sender_user} made {} public to the room directory", body.room_id))
.send_text(&format!(
"{sender_user} made {} public to the room directory",
body.room_id
))
.await;
}
info!("{sender_user} made {0} public to the room directory", body.room_id);
},
room::Visibility::Private => services.rooms.directory.set_not_public(&body.room_id),
_ => {
| room::Visibility::Private => services.rooms.directory.set_not_public(&body.room_id),
| _ => {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Room visibility type is not supported.",
@ -193,7 +208,8 @@ pub(crate) async fn set_room_visibility_route(
///
/// Gets the visibility of a given room in the room directory.
pub(crate) async fn get_room_visibility_route(
State(services): State<crate::State>, body: Ruma<get_room_visibility::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_room_visibility::v3::Request>,
) -> Result<get_room_visibility::v3::Response> {
if !services.rooms.metadata.exists(&body.room_id).await {
// Return 404 if the room doesn't exist
@ -210,10 +226,16 @@ pub(crate) async fn get_room_visibility_route(
}
pub(crate) async fn get_public_rooms_filtered_helper(
services: &Services, server: Option<&ServerName>, limit: Option<UInt>, since: Option<&str>, filter: &Filter,
services: &Services,
server: Option<&ServerName>,
limit: Option<UInt>,
since: Option<&str>,
filter: &Filter,
_network: &RoomNetwork,
) -> Result<get_public_rooms_filtered::v3::Response> {
if let Some(other_server) = server.filter(|server_name| !services.globals.server_is_ours(server_name)) {
if let Some(other_server) =
server.filter(|server_name| !services.globals.server_is_ours(server_name))
{
let response = services
.sending
.send_federation_request(
@ -245,9 +267,10 @@ pub(crate) async fn get_public_rooms_filtered_helper(
if let Some(s) = &since {
let mut characters = s.chars();
let backwards = match characters.next() {
Some('n') => false,
Some('p') => true,
_ => return Err(Error::BadRequest(ErrorKind::InvalidParam, "Invalid `since` token")),
| Some('n') => false,
| Some('p') => true,
| _ =>
return Err(Error::BadRequest(ErrorKind::InvalidParam, "Invalid `since` token")),
};
num_since = characters
@ -337,7 +360,11 @@ pub(crate) async fn get_public_rooms_filtered_helper(
/// Check whether the user can publish to the room directory via power levels of
/// room history visibility event or room creator
async fn user_can_publish_room(services: &Services, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
async fn user_can_publish_room(
services: &Services,
user_id: &UserId,
room_id: &RoomId,
) -> Result<bool> {
if let Ok(event) = services
.rooms
.state_accessor
@ -347,7 +374,8 @@ async fn user_can_publish_room(services: &Services, user_id: &UserId, room_id: &
serde_json::from_str(event.content.get())
.map_err(|_| Error::bad_database("Invalid event content for m.room.power_levels"))
.map(|content: RoomPowerLevelsEventContent| {
RoomPowerLevels::from(content).user_can_send_state(user_id, StateEventType::RoomHistoryVisibility)
RoomPowerLevels::from(content)
.user_can_send_state(user_id, StateEventType::RoomHistoryVisibility)
})
} else if let Ok(event) = services
.rooms
@ -406,10 +434,10 @@ async fn public_rooms_chunk(services: &Services, room_id: OwnedRoomId) -> Public
.state_accessor
.room_state_get_content(&room_id, &StateEventType::RoomJoinRules, "")
.map_ok(|c: RoomJoinRulesEventContent| match c.join_rule {
JoinRule::Public => PublicRoomJoinRule::Public,
JoinRule::Knock => "knock".into(),
JoinRule::KnockRestricted(_) => "knock_restricted".into(),
_ => "invite".into(),
| JoinRule::Public => PublicRoomJoinRule::Public,
| JoinRule::Knock => "knock".into(),
| JoinRule::KnockRestricted(_) => "knock_restricted".into(),
| _ => "invite".into(),
})
.await
.unwrap_or_default(),

View file

@ -10,7 +10,8 @@ use crate::{Result, Ruma};
///
/// - A user can only access their own filters
pub(crate) async fn get_filter_route(
State(services): State<crate::State>, body: Ruma<get_filter::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_filter::v3::Request>,
) -> Result<get_filter::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -26,7 +27,8 @@ pub(crate) async fn get_filter_route(
///
/// Creates a new filter to be used by other endpoints.
pub(crate) async fn create_filter_route(
State(services): State<crate::State>, body: Ruma<create_filter::v3::Request>,
State(services): State<crate::State>,
body: Ruma<create_filter::v3::Request>,
) -> Result<create_filter::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");

View file

@ -7,7 +7,10 @@ use ruma::{
api::{
client::{
error::ErrorKind,
keys::{claim_keys, get_key_changes, get_keys, upload_keys, upload_signatures, upload_signing_keys},
keys::{
claim_keys, get_key_changes, get_keys, upload_keys, upload_signatures,
upload_signing_keys,
},
uiaa::{AuthFlow, AuthType, UiaaInfo},
},
federation,
@ -31,7 +34,8 @@ use crate::{
/// - If there are no device keys yet: Adds device keys (TODO: merge with
/// existing keys?)
pub(crate) async fn upload_keys_route(
State(services): State<crate::State>, body: Ruma<upload_keys::v3::Request>,
State(services): State<crate::State>,
body: Ruma<upload_keys::v3::Request>,
) -> Result<upload_keys::v3::Response> {
let (sender_user, sender_device) = body.sender();
@ -75,7 +79,8 @@ pub(crate) async fn upload_keys_route(
/// - The master and self-signing keys contain signatures that the user is
/// allowed to see
pub(crate) async fn get_keys_route(
State(services): State<crate::State>, body: Ruma<get_keys::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_keys::v3::Request>,
) -> Result<get_keys::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -93,7 +98,8 @@ pub(crate) async fn get_keys_route(
///
/// Claims one-time keys
pub(crate) async fn claim_keys_route(
State(services): State<crate::State>, body: Ruma<claim_keys::v3::Request>,
State(services): State<crate::State>,
body: Ruma<claim_keys::v3::Request>,
) -> Result<claim_keys::v3::Response> {
claim_keys_helper(&services, &body.one_time_keys).await
}
@ -104,16 +110,15 @@ pub(crate) async fn claim_keys_route(
///
/// - Requires UIAA to verify password
pub(crate) async fn upload_signing_keys_route(
State(services): State<crate::State>, body: Ruma<upload_signing_keys::v3::Request>,
State(services): State<crate::State>,
body: Ruma<upload_signing_keys::v3::Request>,
) -> Result<upload_signing_keys::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
// UIAA
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Password],
}],
flows: vec![AuthFlow { stages: vec![AuthType::Password] }],
completed: Vec::new(),
params: Box::default(),
session: None,
@ -161,7 +166,8 @@ pub(crate) async fn upload_signing_keys_route(
///
/// Uploads end-to-end key signatures from the sender user.
pub(crate) async fn upload_signatures_route(
State(services): State<crate::State>, body: Ruma<upload_signatures::v3::Request>,
State(services): State<crate::State>,
body: Ruma<upload_signatures::v3::Request>,
) -> Result<upload_signatures::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -174,7 +180,10 @@ pub(crate) async fn upload_signatures_route(
.get("signatures")
.ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Missing signatures field."))?
.get(sender_user.to_string())
.ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Invalid user in signatures field."))?
.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid user in signatures field.",
))?
.as_object()
.ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Invalid signature."))?
.clone()
@ -185,7 +194,10 @@ pub(crate) async fn upload_signatures_route(
signature
.1
.as_str()
.ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Invalid signature value."))?
.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid signature value.",
))?
.to_owned(),
);
@ -209,7 +221,8 @@ pub(crate) async fn upload_signatures_route(
///
/// - TODO: left users
pub(crate) async fn get_key_changes_route(
State(services): State<crate::State>, body: Ruma<get_key_changes::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_key_changes::v3::Request>,
) -> Result<get_key_changes::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -255,8 +268,11 @@ pub(crate) async fn get_key_changes_route(
}
pub(crate) async fn get_keys_helper<F>(
services: &Services, sender_user: Option<&UserId>, device_keys_input: &BTreeMap<OwnedUserId, Vec<OwnedDeviceId>>,
allowed_signatures: F, include_display_names: bool,
services: &Services,
sender_user: Option<&UserId>,
device_keys_input: &BTreeMap<OwnedUserId, Vec<OwnedDeviceId>>,
allowed_signatures: F,
include_display_names: bool,
) -> Result<get_keys::v3::Response>
where
F: Fn(&UserId) -> bool + Send + Sync,
@ -289,7 +305,9 @@ where
.users
.get_device_metadata(user_id, device_id)
.await
.map_err(|_| err!(Database("all_device_keys contained nonexistent device.")))?;
.map_err(|_| {
err!(Database("all_device_keys contained nonexistent device."))
})?;
add_unsigned_device_display_name(&mut keys, metadata, include_display_names)
.map_err(|_| err!(Database("invalid device keys in database")))?;
@ -307,7 +325,11 @@ where
.users
.get_device_metadata(user_id, device_id)
.await
.map_err(|_| err!(Request(InvalidParam("Tried to get keys for nonexistent device."))))?;
.map_err(|_| {
err!(Request(InvalidParam(
"Tried to get keys for nonexistent device."
)))
})?;
add_unsigned_device_display_name(&mut keys, metadata, include_display_names)
.map_err(|_| err!(Database("invalid device keys in database")))?;
@ -350,9 +372,8 @@ where
device_keys_input_fed.insert(user_id.to_owned(), keys.clone());
}
let request = federation::keys::get_keys::v1::Request {
device_keys: device_keys_input_fed,
};
let request =
federation::keys::get_keys::v1::Request { device_keys: device_keys_input_fed };
let response = services
.sending
@ -382,8 +403,8 @@ where
.users
.add_cross_signing_keys(
&user, &raw, &None, &None,
false, /* Dont notify. A notification would trigger another key request resulting in an
* endless loop */
false, /* Dont notify. A notification would trigger another key request
* resulting in an endless loop */
)
.await?;
master_keys.insert(user.clone(), raw);
@ -406,7 +427,8 @@ where
}
fn add_unsigned_device_display_name(
keys: &mut Raw<ruma::encryption::DeviceKeys>, metadata: ruma::api::client::device::Device,
keys: &mut Raw<ruma::encryption::DeviceKeys>,
metadata: ruma::api::client::device::Device,
include_display_names: bool,
) -> serde_json::Result<()> {
if let Some(display_name) = metadata.display_name {
@ -431,7 +453,8 @@ fn add_unsigned_device_display_name(
}
pub(crate) async fn claim_keys_helper(
services: &Services, one_time_keys_input: &BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, OneTimeKeyAlgorithm>>,
services: &Services,
one_time_keys_input: &BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, OneTimeKeyAlgorithm>>,
) -> Result<claim_keys::v3::Response> {
let mut one_time_keys = BTreeMap::new();
@ -473,12 +496,9 @@ pub(crate) async fn claim_keys_helper(
server,
services
.sending
.send_federation_request(
server,
federation::keys::claim_keys::v1::Request {
.send_federation_request(server, federation::keys::claim_keys::v1::Request {
one_time_keys: one_time_keys_input_fed,
},
)
})
.await,
)
})
@ -486,17 +506,14 @@ pub(crate) async fn claim_keys_helper(
while let Some((server, response)) = futures.next().await {
match response {
Ok(keys) => {
| Ok(keys) => {
one_time_keys.extend(keys.one_time_keys);
},
Err(_e) => {
| Err(_e) => {
failures.insert(server.to_string(), json!({}));
},
}
}
Ok(claim_keys::v3::Response {
failures,
one_time_keys,
})
Ok(claim_keys::v3::Response { failures, one_time_keys })
}

View file

@ -15,7 +15,8 @@ use reqwest::Url;
use ruma::{
api::client::{
authenticated_media::{
get_content, get_content_as_filename, get_content_thumbnail, get_media_config, get_media_preview,
get_content, get_content_as_filename, get_content_thumbnail, get_media_config,
get_media_preview,
},
media::create_content,
},
@ -26,7 +27,8 @@ use crate::Ruma;
/// # `GET /_matrix/client/v1/media/config`
pub(crate) async fn get_media_config_route(
State(services): State<crate::State>, _body: Ruma<get_media_config::v1::Request>,
State(services): State<crate::State>,
_body: Ruma<get_media_config::v1::Request>,
) -> Result<get_media_config::v1::Response> {
Ok(get_media_config::v1::Response {
upload_size: ruma_from_usize(services.globals.config.max_request_size),
@ -46,7 +48,8 @@ pub(crate) async fn get_media_config_route(
fields(%client),
)]
pub(crate) async fn create_content_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<create_content::v3::Request>,
) -> Result<create_content::v3::Response> {
let user = body.sender_user.as_ref().expect("user is authenticated");
@ -79,7 +82,8 @@ pub(crate) async fn create_content_route(
fields(%client),
)]
pub(crate) async fn get_content_thumbnail_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content_thumbnail::v1::Request>,
) -> Result<get_content_thumbnail::v1::Response> {
let user = body.sender_user.as_ref().expect("user is authenticated");
@ -115,7 +119,8 @@ pub(crate) async fn get_content_thumbnail_route(
fields(%client),
)]
pub(crate) async fn get_content_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content::v1::Request>,
) -> Result<get_content::v1::Response> {
let user = body.sender_user.as_ref().expect("user is authenticated");
@ -150,7 +155,8 @@ pub(crate) async fn get_content_route(
fields(%client),
)]
pub(crate) async fn get_content_as_filename_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content_as_filename::v1::Request>,
) -> Result<get_content_as_filename::v1::Response> {
let user = body.sender_user.as_ref().expect("user is authenticated");
@ -185,7 +191,8 @@ pub(crate) async fn get_content_as_filename_route(
fields(%client),
)]
pub(crate) async fn get_media_preview_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_media_preview::v1::Request>,
) -> Result<get_media_preview::v1::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -223,7 +230,11 @@ pub(crate) async fn get_media_preview_route(
}
async fn fetch_thumbnail(
services: &Services, mxc: &Mxc<'_>, user: &UserId, timeout_ms: Duration, dim: &Dim,
services: &Services,
mxc: &Mxc<'_>,
user: &UserId,
timeout_ms: Duration,
dim: &Dim,
) -> Result<FileMeta> {
let FileMeta {
content,
@ -245,7 +256,11 @@ async fn fetch_thumbnail(
}
async fn fetch_file(
services: &Services, mxc: &Mxc<'_>, user: &UserId, timeout_ms: Duration, filename: Option<&str>,
services: &Services,
mxc: &Mxc<'_>,
user: &UserId,
timeout_ms: Duration,
filename: Option<&str>,
) -> Result<FileMeta> {
let FileMeta {
content,
@ -267,7 +282,11 @@ async fn fetch_file(
}
async fn fetch_thumbnail_meta(
services: &Services, mxc: &Mxc<'_>, user: &UserId, timeout_ms: Duration, dim: &Dim,
services: &Services,
mxc: &Mxc<'_>,
user: &UserId,
timeout_ms: Duration,
dim: &Dim,
) -> Result<FileMeta> {
if let Some(filemeta) = services.media.get_thumbnail(mxc, dim).await? {
return Ok(filemeta);
@ -283,7 +302,12 @@ async fn fetch_thumbnail_meta(
.await
}
async fn fetch_file_meta(services: &Services, mxc: &Mxc<'_>, user: &UserId, timeout_ms: Duration) -> Result<FileMeta> {
async fn fetch_file_meta(
services: &Services,
mxc: &Mxc<'_>,
user: &UserId,
timeout_ms: Duration,
) -> Result<FileMeta> {
if let Some(filemeta) = services.media.get(mxc).await? {
return Ok(filemeta);
}

View file

@ -11,8 +11,8 @@ use conduwuit_service::media::{Dim, FileMeta, CACHE_CONTROL_IMMUTABLE, CORP_CROS
use reqwest::Url;
use ruma::{
api::client::media::{
create_content, get_content, get_content_as_filename, get_content_thumbnail, get_media_config,
get_media_preview,
create_content, get_content, get_content_as_filename, get_content_thumbnail,
get_media_config, get_media_preview,
},
Mxc,
};
@ -23,7 +23,8 @@ use crate::{client::create_content_route, Ruma, RumaResponse};
///
/// Returns max upload size.
pub(crate) async fn get_media_config_legacy_route(
State(services): State<crate::State>, _body: Ruma<get_media_config::v3::Request>,
State(services): State<crate::State>,
_body: Ruma<get_media_config::v3::Request>,
) -> Result<get_media_config::v3::Response> {
Ok(get_media_config::v3::Response {
upload_size: ruma_from_usize(services.globals.config.max_request_size),
@ -38,7 +39,8 @@ pub(crate) async fn get_media_config_legacy_route(
///
/// Returns max upload size.
pub(crate) async fn get_media_config_legacy_legacy_route(
State(services): State<crate::State>, body: Ruma<get_media_config::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_media_config::v3::Request>,
) -> Result<RumaResponse<get_media_config::v3::Response>> {
get_media_config_legacy_route(State(services), body)
.await
@ -50,7 +52,8 @@ pub(crate) async fn get_media_config_legacy_legacy_route(
/// Returns URL preview.
#[tracing::instrument(skip_all, fields(%client), name = "url_preview_legacy")]
pub(crate) async fn get_media_preview_legacy_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_media_preview::v3::Request>,
) -> Result<get_media_preview::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -91,7 +94,8 @@ pub(crate) async fn get_media_preview_legacy_route(
///
/// Returns URL preview.
pub(crate) async fn get_media_preview_legacy_legacy_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_media_preview::v3::Request>,
) -> Result<RumaResponse<get_media_preview::v3::Response>> {
get_media_preview_legacy_route(State(services), InsecureClientIp(client), body)
@ -110,7 +114,8 @@ pub(crate) async fn get_media_preview_legacy_legacy_route(
/// - Some metadata will be saved in the database
/// - Media will be saved in the media/ directory
pub(crate) async fn create_content_legacy_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<create_content::v3::Request>,
) -> Result<RumaResponse<create_content::v3::Response>> {
create_content_route(State(services), InsecureClientIp(client), body)
@ -128,7 +133,8 @@ pub(crate) async fn create_content_legacy_route(
/// seconds
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy")]
pub(crate) async fn get_content_legacy_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content::v3::Request>,
) -> Result<get_content::v3::Response> {
let mxc = Mxc {
@ -142,7 +148,8 @@ pub(crate) async fn get_content_legacy_route(
content_disposition,
}) = services.media.get(&mxc).await?
{
let content_disposition = make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
let content_disposition =
make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
Ok(get_content::v3::Response {
file: content.expect("entire file contents"),
@ -156,10 +163,15 @@ pub(crate) async fn get_content_legacy_route(
.media
.fetch_remote_content_legacy(&mxc, body.allow_redirect, body.timeout_ms)
.await
.map_err(|e| err!(Request(NotFound(debug_warn!(%mxc, "Fetching media failed: {e:?}")))))?;
.map_err(|e| {
err!(Request(NotFound(debug_warn!(%mxc, "Fetching media failed: {e:?}"))))
})?;
let content_disposition =
make_content_disposition(response.content_disposition.as_ref(), response.content_type.as_deref(), None);
let content_disposition = make_content_disposition(
response.content_disposition.as_ref(),
response.content_type.as_deref(),
None,
);
Ok(get_content::v3::Response {
file: response.file,
@ -187,7 +199,8 @@ pub(crate) async fn get_content_legacy_route(
/// seconds
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy")]
pub(crate) async fn get_content_legacy_legacy_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content::v3::Request>,
) -> Result<RumaResponse<get_content::v3::Response>> {
get_content_legacy_route(State(services), InsecureClientIp(client), body)
@ -205,7 +218,8 @@ pub(crate) async fn get_content_legacy_legacy_route(
/// seconds
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy")]
pub(crate) async fn get_content_as_filename_legacy_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content_as_filename::v3::Request>,
) -> Result<get_content_as_filename::v3::Response> {
let mxc = Mxc {
@ -219,8 +233,11 @@ pub(crate) async fn get_content_as_filename_legacy_route(
content_disposition,
}) = services.media.get(&mxc).await?
{
let content_disposition =
make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), Some(&body.filename));
let content_disposition = make_content_disposition(
content_disposition.as_ref(),
content_type.as_deref(),
Some(&body.filename),
);
Ok(get_content_as_filename::v3::Response {
file: content.expect("entire file contents"),
@ -234,10 +251,15 @@ pub(crate) async fn get_content_as_filename_legacy_route(
.media
.fetch_remote_content_legacy(&mxc, body.allow_redirect, body.timeout_ms)
.await
.map_err(|e| err!(Request(NotFound(debug_warn!(%mxc, "Fetching media failed: {e:?}")))))?;
.map_err(|e| {
err!(Request(NotFound(debug_warn!(%mxc, "Fetching media failed: {e:?}"))))
})?;
let content_disposition =
make_content_disposition(response.content_disposition.as_ref(), response.content_type.as_deref(), None);
let content_disposition = make_content_disposition(
response.content_disposition.as_ref(),
response.content_type.as_deref(),
None,
);
Ok(get_content_as_filename::v3::Response {
content_disposition: Some(content_disposition),
@ -264,7 +286,8 @@ pub(crate) async fn get_content_as_filename_legacy_route(
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
/// seconds
pub(crate) async fn get_content_as_filename_legacy_legacy_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content_as_filename::v3::Request>,
) -> Result<RumaResponse<get_content_as_filename::v3::Response>> {
get_content_as_filename_legacy_route(State(services), InsecureClientIp(client), body)
@ -282,7 +305,8 @@ pub(crate) async fn get_content_as_filename_legacy_legacy_route(
/// seconds
#[tracing::instrument(skip_all, fields(%client), name = "media_thumbnail_get_legacy")]
pub(crate) async fn get_content_thumbnail_legacy_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content_thumbnail::v3::Request>,
) -> Result<get_content_thumbnail::v3::Response> {
let mxc = Mxc {
@ -297,7 +321,8 @@ pub(crate) async fn get_content_thumbnail_legacy_route(
content_disposition,
}) = services.media.get_thumbnail(&mxc, &dim).await?
{
let content_disposition = make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
let content_disposition =
make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
Ok(get_content_thumbnail::v3::Response {
file: content.expect("entire file contents"),
@ -311,10 +336,15 @@ pub(crate) async fn get_content_thumbnail_legacy_route(
.media
.fetch_remote_thumbnail_legacy(&body)
.await
.map_err(|e| err!(Request(NotFound(debug_warn!(%mxc, "Fetching media failed: {e:?}")))))?;
.map_err(|e| {
err!(Request(NotFound(debug_warn!(%mxc, "Fetching media failed: {e:?}"))))
})?;
let content_disposition =
make_content_disposition(response.content_disposition.as_ref(), response.content_type.as_deref(), None);
let content_disposition = make_content_disposition(
response.content_disposition.as_ref(),
response.content_type.as_deref(),
None,
);
Ok(get_content_thumbnail::v3::Response {
file: response.file,
@ -341,7 +371,8 @@ pub(crate) async fn get_content_thumbnail_legacy_route(
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
/// seconds
pub(crate) async fn get_content_thumbnail_legacy_legacy_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content_thumbnail::v3::Request>,
) -> Result<RumaResponse<get_content_thumbnail::v3::Response>> {
get_content_thumbnail_legacy_route(State(services), InsecureClientIp(client), body)

View file

@ -20,7 +20,8 @@ use ruma::{
client::{
error::ErrorKind,
membership::{
ban_user, forget_room, get_member_events, invite_user, join_room_by_id, join_room_by_id_or_alias,
ban_user, forget_room, get_member_events, invite_user, join_room_by_id,
join_room_by_id_or_alias,
joined_members::{self, v3::RoomMember},
joined_rooms, kick_user, leave_room, unban_user, ThirdPartySigned,
},
@ -36,8 +37,8 @@ use ruma::{
},
StateEventType,
},
state_res, CanonicalJsonObject, CanonicalJsonValue, OwnedRoomId, OwnedServerName, OwnedUserId, RoomId,
RoomVersionId, ServerName, UserId,
state_res, CanonicalJsonObject, CanonicalJsonValue, OwnedRoomId, OwnedServerName,
OwnedUserId, RoomId, RoomVersionId, ServerName, UserId,
};
use service::{
appservice::RegistrationInfo,
@ -54,7 +55,10 @@ use crate::{client::full_user_deactivate, Ruma};
/// enabled
#[tracing::instrument(skip(services))]
async fn banned_room_check(
services: &Services, user_id: &UserId, room_id: Option<&RoomId>, server_name: Option<&ServerName>,
services: &Services,
user_id: &UserId,
room_id: Option<&RoomId>,
server_name: Option<&ServerName>,
client_ip: IpAddr,
) -> Result {
if services.users.is_admin(user_id).await {
@ -70,19 +74,21 @@ async fn banned_room_check(
.contains(&room_id.server_name().unwrap().to_owned())
{
warn!(
"User {user_id} who is not an admin attempted to send an invite for or attempted to join a banned \
room or banned room server name: {room_id}"
"User {user_id} who is not an admin attempted to send an invite for or \
attempted to join a banned room or banned room server name: {room_id}"
);
if services.globals.config.auto_deactivate_banned_room_attempts {
warn!("Automatically deactivating user {user_id} due to attempted banned room join");
warn!(
"Automatically deactivating user {user_id} due to attempted banned room join"
);
if services.globals.config.admin_room_notices {
services
.admin
.send_message(RoomMessageEventContent::text_plain(format!(
"Automatically deactivating user {user_id} due to attempted banned room join from IP \
{client_ip}"
"Automatically deactivating user {user_id} due to attempted banned \
room join from IP {client_ip}"
)))
.await
.ok();
@ -109,19 +115,21 @@ async fn banned_room_check(
.contains(&server_name.to_owned())
{
warn!(
"User {user_id} who is not an admin tried joining a room which has the server name {server_name} that \
is globally forbidden. Rejecting.",
"User {user_id} who is not an admin tried joining a room which has the server \
name {server_name} that is globally forbidden. Rejecting.",
);
if services.globals.config.auto_deactivate_banned_room_attempts {
warn!("Automatically deactivating user {user_id} due to attempted banned room join");
warn!(
"Automatically deactivating user {user_id} due to attempted banned room join"
);
if services.globals.config.admin_room_notices {
services
.admin
.send_message(RoomMessageEventContent::text_plain(format!(
"Automatically deactivating user {user_id} due to attempted banned room join from IP \
{client_ip}"
"Automatically deactivating user {user_id} due to attempted banned \
room join from IP {client_ip}"
)))
.await
.ok();
@ -155,12 +163,20 @@ async fn banned_room_check(
/// federation
#[tracing::instrument(skip_all, fields(%client), name = "join")]
pub(crate) async fn join_room_by_id_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<join_room_by_id::v3::Request>,
) -> Result<join_room_by_id::v3::Response> {
let sender_user = body.sender_user();
banned_room_check(&services, sender_user, Some(&body.room_id), body.room_id.server_name(), client).await?;
banned_room_check(
&services,
sender_user,
Some(&body.room_id),
body.room_id.server_name(),
client,
)
.await?;
// There is no body.server_name for /roomId/join
let mut servers: Vec<_> = services
@ -216,7 +232,8 @@ pub(crate) async fn join_room_by_id_route(
/// via room alias server name and room ID server name
#[tracing::instrument(skip_all, fields(%client), name = "join")]
pub(crate) async fn join_room_by_id_or_alias_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<join_room_by_id_or_alias::v3::Request>,
) -> Result<join_room_by_id_or_alias::v3::Response> {
let sender_user = body.sender_user.as_deref().expect("user is authenticated");
@ -224,8 +241,15 @@ pub(crate) async fn join_room_by_id_or_alias_route(
let body = body.body;
let (servers, room_id) = match OwnedRoomId::try_from(body.room_id_or_alias) {
Ok(room_id) => {
banned_room_check(&services, sender_user, Some(&room_id), room_id.server_name(), client).await?;
| Ok(room_id) => {
banned_room_check(
&services,
sender_user,
Some(&room_id),
room_id.server_name(),
client,
)
.await?;
let mut servers = body.via.clone();
servers.extend(
@ -261,14 +285,21 @@ pub(crate) async fn join_room_by_id_or_alias_route(
(servers, room_id)
},
Err(room_alias) => {
| Err(room_alias) => {
let (room_id, mut servers) = services
.rooms
.alias
.resolve_alias(&room_alias, Some(body.via.clone()))
.await?;
banned_room_check(&services, sender_user, Some(&room_id), Some(room_alias.server_name()), client).await?;
banned_room_check(
&services,
sender_user,
Some(&room_id),
Some(room_alias.server_name()),
client,
)
.await?;
let addl_via_servers = services
.rooms
@ -314,9 +345,7 @@ pub(crate) async fn join_room_by_id_or_alias_route(
.boxed()
.await?;
Ok(join_room_by_id_or_alias::v3::Response {
room_id: join_room_response.room_id,
})
Ok(join_room_by_id_or_alias::v3::Response { room_id: join_room_response.room_id })
}
/// # `POST /_matrix/client/v3/rooms/{roomId}/leave`
@ -325,7 +354,8 @@ pub(crate) async fn join_room_by_id_or_alias_route(
///
/// - This should always work if the user is currently joined.
pub(crate) async fn leave_room_route(
State(services): State<crate::State>, body: Ruma<leave_room::v3::Request>,
State(services): State<crate::State>,
body: Ruma<leave_room::v3::Request>,
) -> Result<leave_room::v3::Response> {
leave_room(&services, body.sender_user(), &body.room_id, body.reason.clone()).await?;
@ -337,7 +367,8 @@ pub(crate) async fn leave_room_route(
/// Tries to send an invite event into the room.
#[tracing::instrument(skip_all, fields(%client), name = "invite")]
pub(crate) async fn invite_user_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<invite_user::v3::Request>,
) -> Result<invite_user::v3::Response> {
let sender_user = body.sender_user();
@ -350,12 +381,16 @@ pub(crate) async fn invite_user_route(
return Err!(Request(Forbidden("Invites are not allowed on this server.")));
}
banned_room_check(&services, sender_user, Some(&body.room_id), body.room_id.server_name(), client).await?;
banned_room_check(
&services,
sender_user,
Some(&body.room_id),
body.room_id.server_name(),
client,
)
.await?;
if let invite_user::v3::InvitationRecipient::UserId {
user_id,
} = &body.recipient
{
if let invite_user::v3::InvitationRecipient::UserId { user_id } = &body.recipient {
let sender_ignored_recipient = services.users.user_is_ignored(sender_user, user_id);
let recipient_ignored_by_sender = services.users.user_is_ignored(user_id, sender_user);
@ -363,7 +398,9 @@ pub(crate) async fn invite_user_route(
join!(sender_ignored_recipient, recipient_ignored_by_sender);
if sender_ignored_recipient {
return Err!(Request(Forbidden("You cannot invite users you have ignored to rooms.")));
return Err!(Request(Forbidden(
"You cannot invite users you have ignored to rooms."
)));
}
if recipient_ignored_by_sender {
@ -386,7 +423,8 @@ pub(crate) async fn invite_user_route(
///
/// Tries to send a kick event into the room.
pub(crate) async fn kick_user_route(
State(services): State<crate::State>, body: Ruma<kick_user::v3::Request>,
State(services): State<crate::State>,
body: Ruma<kick_user::v3::Request>,
) -> Result<kick_user::v3::Response> {
let state_lock = services.rooms.state.mutex.lock(&body.room_id).await;
@ -405,17 +443,14 @@ pub(crate) async fn kick_user_route(
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(
body.user_id.to_string(),
&RoomMemberEventContent {
PduBuilder::state(body.user_id.to_string(), &RoomMemberEventContent {
membership: MembershipState::Leave,
reason: body.reason.clone(),
is_direct: None,
join_authorized_via_users_server: None,
third_party_invite: None,
..event
},
),
}),
body.sender_user(),
&body.room_id,
&state_lock,
@ -431,7 +466,8 @@ pub(crate) async fn kick_user_route(
///
/// Tries to send a ban event into the room.
pub(crate) async fn ban_user_route(
State(services): State<crate::State>, body: Ruma<ban_user::v3::Request>,
State(services): State<crate::State>,
body: Ruma<ban_user::v3::Request>,
) -> Result<ban_user::v3::Response> {
let sender_user = body.sender_user();
@ -452,9 +488,7 @@ pub(crate) async fn ban_user_route(
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(
body.user_id.to_string(),
&RoomMemberEventContent {
PduBuilder::state(body.user_id.to_string(), &RoomMemberEventContent {
membership: MembershipState::Ban,
reason: body.reason.clone(),
displayname: None, // display name may be offensive
@ -463,8 +497,7 @@ pub(crate) async fn ban_user_route(
join_authorized_via_users_server: None,
third_party_invite: None,
..current_member_content
},
),
}),
sender_user,
&body.room_id,
&state_lock,
@ -480,7 +513,8 @@ pub(crate) async fn ban_user_route(
///
/// Tries to send an unban event into the room.
pub(crate) async fn unban_user_route(
State(services): State<crate::State>, body: Ruma<unban_user::v3::Request>,
State(services): State<crate::State>,
body: Ruma<unban_user::v3::Request>,
) -> Result<unban_user::v3::Response> {
let state_lock = services.rooms.state.mutex.lock(&body.room_id).await;
@ -502,17 +536,14 @@ pub(crate) async fn unban_user_route(
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(
body.user_id.to_string(),
&RoomMemberEventContent {
PduBuilder::state(body.user_id.to_string(), &RoomMemberEventContent {
membership: MembershipState::Leave,
reason: body.reason.clone(),
join_authorized_via_users_server: None,
third_party_invite: None,
is_direct: None,
..current_member_content
},
),
}),
body.sender_user(),
&body.room_id,
&state_lock,
@ -534,7 +565,8 @@ pub(crate) async fn unban_user_route(
/// Note: Other devices of the user have no way of knowing the room was
/// forgotten, so this has to be called from every device
pub(crate) async fn forget_room_route(
State(services): State<crate::State>, body: Ruma<forget_room::v3::Request>,
State(services): State<crate::State>,
body: Ruma<forget_room::v3::Request>,
) -> Result<forget_room::v3::Response> {
let sender_user = body.sender_user();
@ -559,7 +591,8 @@ pub(crate) async fn forget_room_route(
///
/// Lists all rooms the user has joined.
pub(crate) async fn joined_rooms_route(
State(services): State<crate::State>, body: Ruma<joined_rooms::v3::Request>,
State(services): State<crate::State>,
body: Ruma<joined_rooms::v3::Request>,
) -> Result<joined_rooms::v3::Response> {
Ok(joined_rooms::v3::Response {
joined_rooms: services
@ -579,7 +612,8 @@ pub(crate) async fn joined_rooms_route(
///
/// - Only works if the user is currently joined
pub(crate) async fn get_member_events_route(
State(services): State<crate::State>, body: Ruma<get_member_events::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_member_events::v3::Request>,
) -> Result<get_member_events::v3::Response> {
let sender_user = body.sender_user();
@ -612,7 +646,8 @@ pub(crate) async fn get_member_events_route(
/// - The sender user must be in the room
/// - TODO: An appservice just needs a puppet joined
pub(crate) async fn joined_members_route(
State(services): State<crate::State>, body: Ruma<joined_members::v3::Request>,
State(services): State<crate::State>,
body: Ruma<joined_members::v3::Request>,
) -> Result<joined_members::v3::Response> {
let sender_user = body.sender_user();
@ -631,25 +666,25 @@ pub(crate) async fn joined_members_route(
.room_members(&body.room_id)
.map(ToOwned::to_owned)
.then(|user| async move {
(
user.clone(),
RoomMember {
(user.clone(), RoomMember {
display_name: services.users.displayname(&user).await.ok(),
avatar_url: services.users.avatar_url(&user).await.ok(),
},
)
})
})
.collect()
.await;
Ok(joined_members::v3::Response {
joined,
})
Ok(joined_members::v3::Response { joined })
}
pub async fn join_room_by_id_helper(
services: &Services, sender_user: &UserId, room_id: &RoomId, reason: Option<String>, servers: &[OwnedServerName],
third_party_signed: Option<&ThirdPartySigned>, appservice_info: &Option<RegistrationInfo>,
services: &Services,
sender_user: &UserId,
room_id: &RoomId,
reason: Option<String>,
servers: &[OwnedServerName],
third_party_signed: Option<&ThirdPartySigned>,
appservice_info: &Option<RegistrationInfo>,
) -> Result<join_room_by_id::v3::Response> {
let state_lock = services.rooms.state.mutex.lock(room_id).await;
@ -671,9 +706,7 @@ pub async fn join_room_by_id_helper(
.await
{
debug_warn!("{sender_user} is already joined in {room_id}");
return Ok(join_room_by_id::v3::Response {
room_id: room_id.into(),
});
return Ok(join_room_by_id::v3::Response { room_id: room_id.into() });
}
if let Ok(membership) = services
@ -694,16 +727,33 @@ pub async fn join_room_by_id_helper(
.server_in_room(services.globals.server_name(), room_id)
.await;
let local_join =
server_in_room || servers.is_empty() || (servers.len() == 1 && services.globals.server_is_ours(&servers[0]));
let local_join = server_in_room
|| servers.is_empty()
|| (servers.len() == 1 && services.globals.server_is_ours(&servers[0]));
if local_join {
join_room_by_id_helper_local(services, sender_user, room_id, reason, servers, third_party_signed, state_lock)
join_room_by_id_helper_local(
services,
sender_user,
room_id,
reason,
servers,
third_party_signed,
state_lock,
)
.boxed()
.await?;
} else {
// Ask a remote server if we are not participating in this room
join_room_by_id_helper_remote(services, sender_user, room_id, reason, servers, third_party_signed, state_lock)
join_room_by_id_helper_remote(
services,
sender_user,
room_id,
reason,
servers,
third_party_signed,
state_lock,
)
.boxed()
.await?;
}
@ -713,12 +763,18 @@ pub async fn join_room_by_id_helper(
#[tracing::instrument(skip_all, fields(%sender_user, %room_id), name = "join_remote")]
async fn join_room_by_id_helper_remote(
services: &Services, sender_user: &UserId, room_id: &RoomId, reason: Option<String>, servers: &[OwnedServerName],
_third_party_signed: Option<&ThirdPartySigned>, state_lock: RoomMutexGuard,
services: &Services,
sender_user: &UserId,
room_id: &RoomId,
reason: Option<String>,
servers: &[OwnedServerName],
_third_party_signed: Option<&ThirdPartySigned>,
state_lock: RoomMutexGuard,
) -> Result {
info!("Joining {room_id} over federation.");
let (make_join_response, remote_server) = make_join_request(services, sender_user, room_id, servers).await?;
let (make_join_response, remote_server) =
make_join_request(services, sender_user, room_id, servers).await?;
info!("make_join finished");
@ -783,8 +839,8 @@ async fn join_room_by_id_helper_remote(
// We keep the "event_id" in the pdu only in v1 or
// v2 rooms
match room_version_id {
RoomVersionId::V1 | RoomVersionId::V2 => {},
_ => {
| RoomVersionId::V1 | RoomVersionId::V2 => {},
| _ => {
join_event_stub.remove("event_id");
},
};
@ -799,7 +855,8 @@ async fn join_room_by_id_helper_remote(
let event_id = pdu::gen_event_id(&join_event_stub, &room_version_id)?;
// Add event_id back
join_event_stub.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.clone().into()));
join_event_stub
.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.clone().into()));
// It has enough fields to be called a proper event now
let mut join_event = join_event_stub;
@ -825,12 +882,16 @@ async fn join_room_by_id_helper_remote(
if join_authorized_via_users_server.is_some() {
if let Some(signed_raw) = &send_join_response.room_state.event {
debug_info!(
"There is a signed event with join_authorized_via_users_server. This room is probably using \
restricted joins. Adding signature to our event"
"There is a signed event with join_authorized_via_users_server. This room is \
probably using restricted joins. Adding signature to our event"
);
let (signed_event_id, signed_value) = gen_event_id_canonical_json(signed_raw, &room_version_id)
.map_err(|e| err!(Request(BadJson(warn!("Could not convert event to canonical JSON: {e}")))))?;
let (signed_event_id, signed_value) =
gen_event_id_canonical_json(signed_raw, &room_version_id).map_err(|e| {
err!(Request(BadJson(warn!(
"Could not convert event to canonical JSON: {e}"
))))
})?;
if signed_event_id != event_id {
return Err!(Request(BadJson(
@ -840,15 +901,20 @@ async fn join_room_by_id_helper_remote(
match signed_value["signatures"]
.as_object()
.ok_or_else(|| err!(BadServerResponse(warn!("Server {remote_server} sent invalid signatures type"))))
.ok_or_else(|| {
err!(BadServerResponse(warn!(
"Server {remote_server} sent invalid signatures type"
)))
})
.and_then(|e| {
e.get(remote_server.as_str()).ok_or_else(|| {
err!(BadServerResponse(warn!(
"Server {remote_server} did not send its signature for a restricted room"
"Server {remote_server} did not send its signature for a restricted \
room"
)))
})
}) {
Ok(signature) => {
| Ok(signature) => {
join_event
.get_mut("signatures")
.expect("we created a valid pdu")
@ -856,10 +922,10 @@ async fn join_room_by_id_helper_remote(
.expect("we created a valid pdu")
.insert(remote_server.to_string(), signature.clone());
},
Err(e) => {
| Err(e) => {
warn!(
"Server {remote_server} sent invalid signature in send_join signatures for event \
{signed_value:?}: {e:?}",
"Server {remote_server} sent invalid signature in send_join signatures \
for event {signed_value:?}: {e:?}",
);
},
}
@ -900,8 +966,8 @@ async fn join_room_by_id_helper_remote(
.ready_filter_map(Result::ok)
.fold(HashMap::new(), |mut state, (event_id, value)| async move {
let pdu = match PduEvent::from_id_val(&event_id, value.clone()) {
Ok(pdu) => pdu,
Err(e) => {
| Ok(pdu) => pdu,
| Err(e) => {
debug_warn!("Invalid PDU in send_join response: {e:?}: {value:#?}");
return state;
},
@ -937,7 +1003,9 @@ async fn join_room_by_id_helper_remote(
.validate_and_add_event_id_no_fetch(pdu, &room_version_id)
})
.ready_filter_map(Result::ok)
.ready_for_each(|(event_id, value)| services.rooms.outlier.add_pdu_outlier(&event_id, &value))
.ready_for_each(|(event_id, value)| {
services.rooms.outlier.add_pdu_outlier(&event_id, &value);
})
.await;
drop(cork);
@ -1031,29 +1099,38 @@ async fn join_room_by_id_helper_remote(
#[tracing::instrument(skip_all, fields(%sender_user, %room_id), name = "join_local")]
async fn join_room_by_id_helper_local(
services: &Services, sender_user: &UserId, room_id: &RoomId, reason: Option<String>, servers: &[OwnedServerName],
_third_party_signed: Option<&ThirdPartySigned>, state_lock: RoomMutexGuard,
services: &Services,
sender_user: &UserId,
room_id: &RoomId,
reason: Option<String>,
servers: &[OwnedServerName],
_third_party_signed: Option<&ThirdPartySigned>,
state_lock: RoomMutexGuard,
) -> Result {
debug_info!("We can join locally");
let join_rules_event_content = services
.rooms
.state_accessor
.room_state_get_content::<RoomJoinRulesEventContent>(room_id, &StateEventType::RoomJoinRules, "")
.room_state_get_content::<RoomJoinRulesEventContent>(
room_id,
&StateEventType::RoomJoinRules,
"",
)
.await;
let restriction_rooms = match join_rules_event_content {
Ok(RoomJoinRulesEventContent {
| Ok(RoomJoinRulesEventContent {
join_rule: JoinRule::Restricted(restricted) | JoinRule::KnockRestricted(restricted),
}) => restricted
.allow
.into_iter()
.filter_map(|a| match a {
AllowRule::RoomMembership(r) => Some(r.room_id),
_ => None,
| AllowRule::RoomMembership(r) => Some(r.room_id),
| _ => None,
})
.collect(),
_ => Vec::new(),
| _ => Vec::new(),
};
let join_authorized_via_users_server: Option<OwnedUserId> = {
@ -1073,10 +1150,12 @@ async fn join_room_by_id_helper_local(
.state_cache
.local_users_in_room(room_id)
.filter(|user| {
services
.rooms
.state_accessor
.user_can_invite(room_id, user, sender_user, &state_lock)
services.rooms.state_accessor.user_can_invite(
room_id,
user,
sender_user,
&state_lock,
)
})
.boxed()
.next()
@ -1112,13 +1191,18 @@ async fn join_room_by_id_helper_local(
};
if restriction_rooms.is_empty()
&& (servers.is_empty() || servers.len() == 1 && services.globals.server_is_ours(&servers[0]))
&& (servers.is_empty()
|| servers.len() == 1 && services.globals.server_is_ours(&servers[0]))
{
return Err(error);
}
warn!("We couldn't do the join locally, maybe federation can help to satisfy the restricted join requirements");
let Ok((make_join_response, remote_server)) = make_join_request(services, sender_user, room_id, servers).await
warn!(
"We couldn't do the join locally, maybe federation can help to satisfy the restricted \
join requirements"
);
let Ok((make_join_response, remote_server)) =
make_join_request(services, sender_user, room_id, servers).await
else {
return Err(error);
};
@ -1133,8 +1217,10 @@ async fn join_room_by_id_helper_local(
));
}
let mut join_event_stub: CanonicalJsonObject = serde_json::from_str(make_join_response.event.get())
.map_err(|e| err!(BadServerResponse("Invalid make_join event json received from server: {e:?}")))?;
let mut join_event_stub: CanonicalJsonObject =
serde_json::from_str(make_join_response.event.get()).map_err(|e| {
err!(BadServerResponse("Invalid make_join event json received from server: {e:?}"))
})?;
let join_authorized_via_users_server = join_event_stub
.get("content")
@ -1173,8 +1259,8 @@ async fn join_room_by_id_helper_local(
// We keep the "event_id" in the pdu only in v1 or
// v2 rooms
match room_version_id {
RoomVersionId::V1 | RoomVersionId::V2 => {},
_ => {
| RoomVersionId::V1 | RoomVersionId::V2 => {},
| _ => {
join_event_stub.remove("event_id");
},
};
@ -1189,7 +1275,8 @@ async fn join_room_by_id_helper_local(
let event_id = pdu::gen_event_id(&join_event_stub, &room_version_id)?;
// Add event_id back
join_event_stub.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.clone().into()));
join_event_stub
.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.clone().into()));
// It has enough fields to be called a proper event now
let join_event = join_event_stub;
@ -1211,8 +1298,10 @@ async fn join_room_by_id_helper_local(
.await?;
if let Some(signed_raw) = send_join_response.room_state.event {
let (signed_event_id, signed_value) = gen_event_id_canonical_json(&signed_raw, &room_version_id)
.map_err(|e| err!(Request(BadJson(warn!("Could not convert event to canonical JSON: {e}")))))?;
let (signed_event_id, signed_value) =
gen_event_id_canonical_json(&signed_raw, &room_version_id).map_err(|e| {
err!(Request(BadJson(warn!("Could not convert event to canonical JSON: {e}"))))
})?;
if signed_event_id != event_id {
return Err!(Request(BadJson(
@ -1234,9 +1323,13 @@ async fn join_room_by_id_helper_local(
}
async fn make_join_request(
services: &Services, sender_user: &UserId, room_id: &RoomId, servers: &[OwnedServerName],
services: &Services,
sender_user: &UserId,
room_id: &RoomId,
servers: &[OwnedServerName],
) -> Result<(federation::membership::prepare_join_event::v1::Response, OwnedServerName)> {
let mut make_join_response_and_server = Err!(BadServerResponse("No server available to assist in joining."));
let mut make_join_response_and_server =
Err!(BadServerResponse("No server available to assist in joining."));
let mut make_join_counter: usize = 0;
let mut incompatible_room_version_count: usize = 0;
@ -1266,23 +1359,28 @@ async fn make_join_request(
e.kind(),
ErrorKind::IncompatibleRoomVersion { .. } | ErrorKind::UnsupportedRoomVersion
) {
incompatible_room_version_count = incompatible_room_version_count.saturating_add(1);
incompatible_room_version_count =
incompatible_room_version_count.saturating_add(1);
}
if incompatible_room_version_count > 15 {
info!(
"15 servers have responded with M_INCOMPATIBLE_ROOM_VERSION or M_UNSUPPORTED_ROOM_VERSION, \
assuming that conduwuit does not support the room version {room_id}: {e}"
"15 servers have responded with M_INCOMPATIBLE_ROOM_VERSION or \
M_UNSUPPORTED_ROOM_VERSION, assuming that conduwuit does not support the \
room version {room_id}: {e}"
);
make_join_response_and_server = Err!(BadServerResponse("Room version is not supported by Conduwuit"));
make_join_response_and_server =
Err!(BadServerResponse("Room version is not supported by Conduwuit"));
return make_join_response_and_server;
}
if make_join_counter > 40 {
warn!(
"40 servers failed to provide valid make_join response, assuming no server can assist in joining."
"40 servers failed to provide valid make_join response, assuming no server \
can assist in joining."
);
make_join_response_and_server = Err!(BadServerResponse("No server available to assist in joining."));
make_join_response_and_server =
Err!(BadServerResponse("No server available to assist in joining."));
return make_join_response_and_server;
}
}
@ -1298,11 +1396,18 @@ async fn make_join_request(
}
pub(crate) async fn invite_helper(
services: &Services, sender_user: &UserId, user_id: &UserId, room_id: &RoomId, reason: Option<String>,
services: &Services,
sender_user: &UserId,
user_id: &UserId,
room_id: &RoomId,
reason: Option<String>,
is_direct: bool,
) -> Result {
if !services.users.is_admin(sender_user).await && services.globals.block_non_admin_invites() {
info!("User {sender_user} is not an admin and attempted to send an invite to room {room_id}");
info!(
"User {sender_user} is not an admin and attempted to send an invite to room \
{room_id}"
);
return Err!(Request(Forbidden("Invites are not allowed on this server.")));
}
@ -1339,9 +1444,7 @@ pub(crate) async fn invite_helper(
let response = services
.sending
.send_federation_request(
user_id.server_name(),
create_invite::v2::Request {
.send_federation_request(user_id.server_name(), create_invite::v2::Request {
room_id: room_id.to_owned(),
event_id: (*pdu.event_id).to_owned(),
room_version: room_version_id.clone(),
@ -1356,14 +1459,15 @@ pub(crate) async fn invite_helper(
.servers_route_via(room_id)
.await
.ok(),
},
)
})
.await?;
// We do not add the event_id field to the pdu here because of signature and
// hashes checks
let (event_id, value) = gen_event_id_canonical_json(&response.event, &room_version_id)
.map_err(|e| err!(Request(BadJson(warn!("Could not convert event to canonical JSON: {e}")))))?;
.map_err(|e| {
err!(Request(BadJson(warn!("Could not convert event to canonical JSON: {e}"))))
})?;
if pdu.event_id != event_id {
return Err!(Request(BadJson(
@ -1379,14 +1483,18 @@ pub(crate) async fn invite_helper(
)
.expect("CanonicalJson is valid json value"),
)
.map_err(|e| err!(Request(BadJson(warn!("Origin field in event is not a valid server name: {e}")))))?;
.map_err(|e| {
err!(Request(BadJson(warn!("Origin field in event is not a valid server name: {e}"))))
})?;
let pdu_id = services
.rooms
.event_handler
.handle_incoming_pdu(&origin, room_id, &event_id, value, true)
.await?
.ok_or_else(|| err!(Request(InvalidParam("Could not accept incoming PDU as timeline event."))))?;
.ok_or_else(|| {
err!(Request(InvalidParam("Could not accept incoming PDU as timeline event.")))
})?;
return services.sending.send_pdu_room(room_id, &pdu_id).await;
}
@ -1456,7 +1564,12 @@ pub async fn leave_all_rooms(services: &Services, user_id: &UserId) {
}
}
pub async fn leave_room(services: &Services, user_id: &UserId, room_id: &RoomId, reason: Option<String>) -> Result<()> {
pub async fn leave_room(
services: &Services,
user_id: &UserId,
room_id: &RoomId,
reason: Option<String>,
) -> Result<()> {
//use conduwuit::utils::stream::OptionStream;
use futures::TryFutureExt;
@ -1500,7 +1613,11 @@ pub async fn leave_room(services: &Services, user_id: &UserId, room_id: &RoomId,
let Ok(event) = services
.rooms
.state_accessor
.room_state_get_content::<RoomMemberEventContent>(room_id, &StateEventType::RoomMember, user_id.as_str())
.room_state_get_content::<RoomMemberEventContent>(
room_id,
&StateEventType::RoomMember,
user_id.as_str(),
)
.await
else {
// Fix for broken rooms
@ -1527,14 +1644,11 @@ pub async fn leave_room(services: &Services, user_id: &UserId, room_id: &RoomId,
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(
user_id.to_string(),
&RoomMemberEventContent {
PduBuilder::state(user_id.to_string(), &RoomMemberEventContent {
membership: MembershipState::Leave,
reason,
..event
},
),
}),
user_id,
room_id,
&state_lock,
@ -1545,8 +1659,13 @@ pub async fn leave_room(services: &Services, user_id: &UserId, room_id: &RoomId,
Ok(())
}
async fn remote_leave_room(services: &Services, user_id: &UserId, room_id: &RoomId) -> Result<()> {
let mut make_leave_response_and_server = Err!(BadServerResponse("No server available to assist in leaving."));
async fn remote_leave_room(
services: &Services,
user_id: &UserId,
room_id: &RoomId,
) -> Result<()> {
let mut make_leave_response_and_server =
Err!(BadServerResponse("No server available to assist in leaving."));
let invite_state = services
.rooms
@ -1608,8 +1727,12 @@ async fn remote_leave_room(services: &Services, user_id: &UserId, room_id: &Room
));
}
let mut leave_event_stub = serde_json::from_str::<CanonicalJsonObject>(make_leave_response.event.get())
.map_err(|e| err!(BadServerResponse("Invalid make_leave event json received from server: {e:?}")))?;
let mut leave_event_stub = serde_json::from_str::<CanonicalJsonObject>(
make_leave_response.event.get(),
)
.map_err(|e| {
err!(BadServerResponse("Invalid make_leave event json received from server: {e:?}"))
})?;
// TODO: Is origin needed?
leave_event_stub.insert(
@ -1627,8 +1750,8 @@ async fn remote_leave_room(services: &Services, user_id: &UserId, room_id: &Room
// room v3 and above removed the "event_id" field from remote PDU format
match room_version_id {
RoomVersionId::V1 | RoomVersionId::V2 => {},
_ => {
| RoomVersionId::V1 | RoomVersionId::V2 => {},
| _ => {
leave_event_stub.remove("event_id");
},
};
@ -1643,7 +1766,8 @@ async fn remote_leave_room(services: &Services, user_id: &UserId, room_id: &Room
let event_id = pdu::gen_event_id(&leave_event_stub, &room_version_id)?;
// Add event_id back
leave_event_stub.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.clone().into()));
leave_event_stub
.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.clone().into()));
// It has enough fields to be called a proper event now
let leave_event = leave_event_stub;

View file

@ -56,7 +56,8 @@ const LIMIT_DEFAULT: usize = 10;
/// - Only works if the user is joined (TODO: always allow, but only show events
/// where the user was joined, depending on `history_visibility`)
pub(crate) async fn get_message_events_route(
State(services): State<crate::State>, body: Ruma<get_message_events::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_message_events::v3::Request>,
) -> Result<get_message_events::v3::Response> {
let sender = body.sender();
let (sender_user, sender_device) = sender;
@ -69,8 +70,8 @@ pub(crate) async fn get_message_events_route(
.map(str::parse)
.transpose()?
.unwrap_or_else(|| match body.dir {
Direction::Forward => PduCount::min(),
Direction::Backward => PduCount::max(),
| Direction::Forward => PduCount::min(),
| Direction::Backward => PduCount::max(),
});
let to: Option<PduCount> = body.to.as_deref().map(str::parse).flat_ok();
@ -81,10 +82,12 @@ pub(crate) async fn get_message_events_route(
.unwrap_or(LIMIT_DEFAULT)
.min(LIMIT_MAX);
services
.rooms
.lazy_loading
.lazy_load_confirm_delivery(sender_user, sender_device, room_id, from);
services.rooms.lazy_loading.lazy_load_confirm_delivery(
sender_user,
sender_device,
room_id,
from,
);
if matches!(body.dir, Direction::Backward) {
services
@ -98,14 +101,14 @@ pub(crate) async fn get_message_events_route(
}
let it = match body.dir {
Direction::Forward => services
| Direction::Forward => services
.rooms
.timeline
.pdus(Some(sender_user), room_id, Some(from))
.await?
.boxed(),
Direction::Backward => services
| Direction::Backward => services
.rooms
.timeline
.pdus_rev(Some(sender_user), room_id, Some(from))
@ -141,10 +144,13 @@ pub(crate) async fn get_message_events_route(
if !cfg!(feature = "element_hacks") {
if let Some(next_token) = next_token {
services
.rooms
.lazy_loading
.lazy_load_mark_sent(sender_user, sender_device, room_id, lazy, next_token);
services.rooms.lazy_loading.lazy_load_mark_sent(
sender_user,
sender_device,
room_id,
lazy,
next_token,
);
}
}
@ -162,7 +168,11 @@ pub(crate) async fn get_message_events_route(
})
}
async fn get_member_event(services: &Services, room_id: &RoomId, user_id: &UserId) -> Option<Raw<AnyStateEvent>> {
async fn get_member_event(
services: &Services,
room_id: &RoomId,
user_id: &UserId,
) -> Option<Raw<AnyStateEvent>> {
services
.rooms
.state_accessor
@ -173,7 +183,11 @@ async fn get_member_event(services: &Services, room_id: &RoomId, user_id: &UserI
}
pub(crate) async fn update_lazy(
services: &Services, room_id: &RoomId, sender: (&UserId, &DeviceId), mut lazy: LazySet, item: &PdusIterItem,
services: &Services,
room_id: &RoomId,
sender: (&UserId, &DeviceId),
mut lazy: LazySet,
item: &PdusIterItem,
force: bool,
) -> LazySet {
let (_, event) = &item;
@ -204,7 +218,11 @@ pub(crate) async fn update_lazy(
lazy
}
pub(crate) async fn ignored_filter(services: &Services, item: PdusIterItem, user_id: &UserId) -> Option<PdusIterItem> {
pub(crate) async fn ignored_filter(
services: &Services,
item: PdusIterItem,
user_id: &UserId,
) -> Option<PdusIterItem> {
let (_, pdu) = &item;
// exclude Synapse's dummy events from bloating up response bodies. clients
@ -223,7 +241,9 @@ pub(crate) async fn ignored_filter(services: &Services, item: PdusIterItem, user
}
pub(crate) async fn visibility_filter(
services: &Services, item: PdusIterItem, user_id: &UserId,
services: &Services,
item: PdusIterItem,
user_id: &UserId,
) -> Option<PdusIterItem> {
let (_, pdu) = &item;

View file

@ -16,7 +16,8 @@ use crate::{Error, Result, Ruma};
///
/// - The token generated is only valid for the OpenID API
pub(crate) async fn create_openid_token_route(
State(services): State<crate::State>, body: Ruma<account::request_openid_token::v3::Request>,
State(services): State<crate::State>,
body: Ruma<account::request_openid_token::v3::Request>,
) -> Result<account::request_openid_token::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");

View file

@ -12,10 +12,14 @@ use crate::{Error, Result, Ruma};
///
/// Sets the presence state of the sender user.
pub(crate) async fn set_presence_route(
State(services): State<crate::State>, body: Ruma<set_presence::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_presence::v3::Request>,
) -> Result<set_presence::v3::Response> {
if !services.globals.allow_local_presence() {
return Err(Error::BadRequest(ErrorKind::forbidden(), "Presence is disabled on this server"));
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Presence is disabled on this server",
));
}
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -40,10 +44,14 @@ pub(crate) async fn set_presence_route(
///
/// - Only works if you share a room with the user
pub(crate) async fn get_presence_route(
State(services): State<crate::State>, body: Ruma<get_presence::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_presence::v3::Request>,
) -> Result<get_presence::v3::Response> {
if !services.globals.allow_local_presence() {
return Err(Error::BadRequest(ErrorKind::forbidden(), "Presence is disabled on this server"));
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Presence is disabled on this server",
));
}
let sender_user = body.sender_user.as_ref().expect("user is authenticated");

View file

@ -11,7 +11,9 @@ use ruma::{
api::{
client::{
error::ErrorKind,
profile::{get_avatar_url, get_display_name, get_profile, set_avatar_url, set_display_name},
profile::{
get_avatar_url, get_display_name, get_profile, set_avatar_url, set_display_name,
},
},
federation,
},
@ -29,7 +31,8 @@ use crate::Ruma;
///
/// - Also makes sure other users receive the update using presence EDUs
pub(crate) async fn set_displayname_route(
State(services): State<crate::State>, body: Ruma<set_display_name::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_display_name::v3::Request>,
) -> Result<set_display_name::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -45,7 +48,8 @@ pub(crate) async fn set_displayname_route(
.collect()
.await;
update_displayname(&services, &body.user_id, body.displayname.clone(), &all_joined_rooms).await;
update_displayname(&services, &body.user_id, body.displayname.clone(), &all_joined_rooms)
.await;
if services.globals.allow_local_presence() {
// Presence update
@ -65,7 +69,8 @@ pub(crate) async fn set_displayname_route(
/// - If user is on another server and we do not have a local copy already fetch
/// displayname over federation
pub(crate) async fn get_displayname_route(
State(services): State<crate::State>, body: Ruma<get_display_name::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_display_name::v3::Request>,
) -> Result<get_display_name::v3::Response> {
if !services.globals.user_is_local(&body.user_id) {
// Create and update our local copy of the user
@ -94,9 +99,7 @@ pub(crate) async fn get_displayname_route(
.users
.set_blurhash(&body.user_id, response.blurhash.clone());
return Ok(get_display_name::v3::Response {
displayname: response.displayname,
});
return Ok(get_display_name::v3::Response { displayname: response.displayname });
}
}
@ -117,7 +120,8 @@ pub(crate) async fn get_displayname_route(
///
/// - Also makes sure other users receive the update using presence EDUs
pub(crate) async fn set_avatar_url_route(
State(services): State<crate::State>, body: Ruma<set_avatar_url::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_avatar_url::v3::Request>,
) -> Result<set_avatar_url::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -161,7 +165,8 @@ pub(crate) async fn set_avatar_url_route(
/// - If user is on another server and we do not have a local copy already fetch
/// `avatar_url` and blurhash over federation
pub(crate) async fn get_avatar_url_route(
State(services): State<crate::State>, body: Ruma<get_avatar_url::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_avatar_url::v3::Request>,
) -> Result<get_avatar_url::v3::Response> {
if !services.globals.user_is_local(&body.user_id) {
// Create and update our local copy of the user
@ -218,7 +223,8 @@ pub(crate) async fn get_avatar_url_route(
/// - If user is on another server and we do not have a local copy already,
/// fetch profile over federation.
pub(crate) async fn get_profile_route(
State(services): State<crate::State>, body: Ruma<get_profile::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_profile::v3::Request>,
) -> Result<get_profile::v3::Response> {
if !services.globals.user_is_local(&body.user_id) {
// Create and update our local copy of the user
@ -254,9 +260,11 @@ pub(crate) async fn get_profile_route(
.set_timezone(&body.user_id, response.tz.clone());
for (profile_key, profile_key_value) in &response.custom_profile_fields {
services
.users
.set_profile_key(&body.user_id, profile_key, Some(profile_key_value.clone()));
services.users.set_profile_key(
&body.user_id,
profile_key,
Some(profile_key_value.clone()),
);
}
return Ok(get_profile::v3::Response {
@ -295,7 +303,10 @@ pub(crate) async fn get_profile_route(
}
pub async fn update_displayname(
services: &Services, user_id: &UserId, displayname: Option<String>, all_joined_rooms: &[OwnedRoomId],
services: &Services,
user_id: &UserId,
displayname: Option<String>,
all_joined_rooms: &[OwnedRoomId],
) {
let (current_avatar_url, current_blurhash, current_displayname) = join3(
services.users.avatar_url(user_id),
@ -322,9 +333,7 @@ pub async fn update_displayname(
.iter()
.try_stream()
.and_then(|room_id: &OwnedRoomId| async move {
let pdu = PduBuilder::state(
user_id.to_string(),
&RoomMemberEventContent {
let pdu = PduBuilder::state(user_id.to_string(), &RoomMemberEventContent {
displayname: displayname.clone(),
membership: MembershipState::Join,
avatar_url: avatar_url.clone(),
@ -333,8 +342,7 @@ pub async fn update_displayname(
reason: None,
is_direct: None,
third_party_invite: None,
},
);
});
Ok((pdu, room_id))
})
@ -346,7 +354,10 @@ pub async fn update_displayname(
}
pub async fn update_avatar_url(
services: &Services, user_id: &UserId, avatar_url: Option<OwnedMxcUri>, blurhash: Option<String>,
services: &Services,
user_id: &UserId,
avatar_url: Option<OwnedMxcUri>,
blurhash: Option<String>,
all_joined_rooms: &[OwnedRoomId],
) {
let (current_avatar_url, current_blurhash, current_displayname) = join3(
@ -375,9 +386,7 @@ pub async fn update_avatar_url(
.iter()
.try_stream()
.and_then(|room_id: &OwnedRoomId| async move {
let pdu = PduBuilder::state(
user_id.to_string(),
&RoomMemberEventContent {
let pdu = PduBuilder::state(user_id.to_string(), &RoomMemberEventContent {
avatar_url: avatar_url.clone(),
blurhash: blurhash.clone(),
membership: MembershipState::Join,
@ -386,8 +395,7 @@ pub async fn update_avatar_url(
reason: None,
is_direct: None,
third_party_invite: None,
},
);
});
Ok((pdu, room_id))
})
@ -399,7 +407,9 @@ pub async fn update_avatar_url(
}
pub async fn update_all_rooms(
services: &Services, all_joined_rooms: Vec<(PduBuilder, &OwnedRoomId)>, user_id: &UserId,
services: &Services,
all_joined_rooms: Vec<(PduBuilder, &OwnedRoomId)>,
user_id: &UserId,
) {
for (pdu_builder, room_id) in all_joined_rooms {
let state_lock = services.rooms.state.mutex.lock(room_id).await;

View file

@ -4,15 +4,19 @@ use ruma::{
api::client::{
error::ErrorKind,
push::{
delete_pushrule, get_pushers, get_pushrule, get_pushrule_actions, get_pushrule_enabled, get_pushrules_all,
get_pushrules_global_scope, set_pusher, set_pushrule, set_pushrule_actions, set_pushrule_enabled,
delete_pushrule, get_pushers, get_pushrule, get_pushrule_actions,
get_pushrule_enabled, get_pushrules_all, get_pushrules_global_scope, set_pusher,
set_pushrule, set_pushrule_actions, set_pushrule_enabled,
},
},
events::{
push_rules::{PushRulesEvent, PushRulesEventContent},
GlobalAccountDataEventType,
},
push::{InsertPushRuleError, PredefinedContentRuleId, PredefinedOverrideRuleId, RemovePushRuleError, Ruleset},
push::{
InsertPushRuleError, PredefinedContentRuleId, PredefinedOverrideRuleId,
RemovePushRuleError, Ruleset,
},
CanonicalJsonObject, CanonicalJsonValue,
};
use service::Services;
@ -23,7 +27,8 @@ use crate::{Error, Result, Ruma};
///
/// Retrieves the push rules event for this user.
pub(crate) async fn get_pushrules_all_route(
State(services): State<crate::State>, body: Ruma<get_pushrules_all::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_pushrules_all::v3::Request>,
) -> Result<get_pushrules_all::v3::Response> {
let sender_user = body.sender_user();
@ -40,8 +45,10 @@ pub(crate) async fn get_pushrules_all_route(
return recreate_push_rules_and_return(&services, sender_user).await;
};
let account_data_content = serde_json::from_value::<PushRulesEventContent>(content_value.into())
.map_err(|e| err!(Database(warn!("Invalid push rules account data event in database: {e}"))))?;
let account_data_content =
serde_json::from_value::<PushRulesEventContent>(content_value.into()).map_err(|e| {
err!(Database(warn!("Invalid push rules account data event in database: {e}")))
})?;
let mut global_ruleset = account_data_content.global;
@ -79,9 +86,7 @@ pub(crate) async fn get_pushrules_all_route(
sender_user,
GlobalAccountDataEventType::PushRules.to_string().into(),
&serde_json::to_value(PushRulesEvent {
content: PushRulesEventContent {
global: global_ruleset.clone(),
},
content: PushRulesEventContent { global: global_ruleset.clone() },
})
.expect("to json always works"),
)
@ -89,9 +94,7 @@ pub(crate) async fn get_pushrules_all_route(
}
};
Ok(get_pushrules_all::v3::Response {
global: global_ruleset,
})
Ok(get_pushrules_all::v3::Response { global: global_ruleset })
}
/// # `GET /_matrix/client/r0/pushrules/global/`
@ -100,7 +103,8 @@ pub(crate) async fn get_pushrules_all_route(
///
/// This appears to be the exact same as `GET /_matrix/client/r0/pushrules/`.
pub(crate) async fn get_pushrules_global_route(
State(services): State<crate::State>, body: Ruma<get_pushrules_global_scope::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_pushrules_global_scope::v3::Request>,
) -> Result<get_pushrules_global_scope::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -134,8 +138,10 @@ pub(crate) async fn get_pushrules_global_route(
});
};
let account_data_content = serde_json::from_value::<PushRulesEventContent>(content_value.into())
.map_err(|e| err!(Database(warn!("Invalid push rules account data event in database: {e}"))))?;
let account_data_content =
serde_json::from_value::<PushRulesEventContent>(content_value.into()).map_err(|e| {
err!(Database(warn!("Invalid push rules account data event in database: {e}")))
})?;
let mut global_ruleset = account_data_content.global;
@ -173,9 +179,7 @@ pub(crate) async fn get_pushrules_global_route(
sender_user,
GlobalAccountDataEventType::PushRules.to_string().into(),
&serde_json::to_value(PushRulesEvent {
content: PushRulesEventContent {
global: global_ruleset.clone(),
},
content: PushRulesEventContent { global: global_ruleset.clone() },
})
.expect("to json always works"),
)
@ -183,16 +187,15 @@ pub(crate) async fn get_pushrules_global_route(
}
};
Ok(get_pushrules_global_scope::v3::Response {
global: global_ruleset,
})
Ok(get_pushrules_global_scope::v3::Response { global: global_ruleset })
}
/// # `GET /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}`
///
/// Retrieves a single specified push rule for this user.
pub(crate) async fn get_pushrule_route(
State(services): State<crate::State>, body: Ruma<get_pushrule::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_pushrule::v3::Request>,
) -> Result<get_pushrule::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -218,9 +221,7 @@ pub(crate) async fn get_pushrule_route(
.map(Into::into);
if let Some(rule) = rule {
Ok(get_pushrule::v3::Response {
rule,
})
Ok(get_pushrule::v3::Response { rule })
} else {
Err(Error::BadRequest(ErrorKind::NotFound, "Push rule not found."))
}
@ -230,7 +231,8 @@ pub(crate) async fn get_pushrule_route(
///
/// Creates a single specified push rule for this user.
pub(crate) async fn set_pushrule_route(
State(services): State<crate::State>, body: Ruma<set_pushrule::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_pushrule::v3::Request>,
) -> Result<set_pushrule::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let body = body.body;
@ -241,32 +243,33 @@ pub(crate) async fn set_pushrule_route(
.await
.map_err(|_| err!(Request(NotFound("PushRules event not found."))))?;
if let Err(error) =
account_data
.content
.global
.insert(body.rule.clone(), body.after.as_deref(), body.before.as_deref())
{
if let Err(error) = account_data.content.global.insert(
body.rule.clone(),
body.after.as_deref(),
body.before.as_deref(),
) {
let err = match error {
InsertPushRuleError::ServerDefaultRuleId => Error::BadRequest(
| InsertPushRuleError::ServerDefaultRuleId => Error::BadRequest(
ErrorKind::InvalidParam,
"Rule IDs starting with a dot are reserved for server-default rules.",
),
InsertPushRuleError::InvalidRuleId => {
Error::BadRequest(ErrorKind::InvalidParam, "Rule ID containing invalid characters.")
},
InsertPushRuleError::RelativeToServerDefaultRule => Error::BadRequest(
| InsertPushRuleError::InvalidRuleId => Error::BadRequest(
ErrorKind::InvalidParam,
"Rule ID containing invalid characters.",
),
| InsertPushRuleError::RelativeToServerDefaultRule => Error::BadRequest(
ErrorKind::InvalidParam,
"Can't place a push rule relatively to a server-default rule.",
),
InsertPushRuleError::UnknownRuleId => {
Error::BadRequest(ErrorKind::NotFound, "The before or after rule could not be found.")
},
InsertPushRuleError::BeforeHigherThanAfter => Error::BadRequest(
| InsertPushRuleError::UnknownRuleId => Error::BadRequest(
ErrorKind::NotFound,
"The before or after rule could not be found.",
),
| InsertPushRuleError::BeforeHigherThanAfter => Error::BadRequest(
ErrorKind::InvalidParam,
"The before rule has a higher priority than the after rule.",
),
_ => Error::BadRequest(ErrorKind::InvalidParam, "Invalid data."),
| _ => Error::BadRequest(ErrorKind::InvalidParam, "Invalid data."),
};
return Err(err);
@ -289,7 +292,8 @@ pub(crate) async fn set_pushrule_route(
///
/// Gets the actions of a single specified push rule for this user.
pub(crate) async fn get_pushrule_actions_route(
State(services): State<crate::State>, body: Ruma<get_pushrule_actions::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_pushrule_actions::v3::Request>,
) -> Result<get_pushrule_actions::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -315,16 +319,15 @@ pub(crate) async fn get_pushrule_actions_route(
.map(|rule| rule.actions().to_owned())
.ok_or_else(|| err!(Request(NotFound("Push rule not found."))))?;
Ok(get_pushrule_actions::v3::Response {
actions,
})
Ok(get_pushrule_actions::v3::Response { actions })
}
/// # `PUT /_matrix/client/r0/pushrules/global/{kind}/{ruleId}/actions`
///
/// Sets the actions of a single specified push rule for this user.
pub(crate) async fn set_pushrule_actions_route(
State(services): State<crate::State>, body: Ruma<set_pushrule_actions::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_pushrule_actions::v3::Request>,
) -> Result<set_pushrule_actions::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -360,7 +363,8 @@ pub(crate) async fn set_pushrule_actions_route(
///
/// Gets the enabled status of a single specified push rule for this user.
pub(crate) async fn get_pushrule_enabled_route(
State(services): State<crate::State>, body: Ruma<get_pushrule_enabled::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_pushrule_enabled::v3::Request>,
) -> Result<get_pushrule_enabled::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -370,9 +374,7 @@ pub(crate) async fn get_pushrule_enabled_route(
|| body.rule_id.as_str() == PredefinedOverrideRuleId::ContainsDisplayName.as_str()
|| body.rule_id.as_str() == PredefinedOverrideRuleId::RoomNotif.as_str()
{
return Ok(get_pushrule_enabled::v3::Response {
enabled: false,
});
return Ok(get_pushrule_enabled::v3::Response { enabled: false });
}
let event: PushRulesEvent = services
@ -388,16 +390,15 @@ pub(crate) async fn get_pushrule_enabled_route(
.map(ruma::push::AnyPushRuleRef::enabled)
.ok_or_else(|| err!(Request(NotFound("Push rule not found."))))?;
Ok(get_pushrule_enabled::v3::Response {
enabled,
})
Ok(get_pushrule_enabled::v3::Response { enabled })
}
/// # `PUT /_matrix/client/r0/pushrules/global/{kind}/{ruleId}/enabled`
///
/// Sets the enabled status of a single specified push rule for this user.
pub(crate) async fn set_pushrule_enabled_route(
State(services): State<crate::State>, body: Ruma<set_pushrule_enabled::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_pushrule_enabled::v3::Request>,
) -> Result<set_pushrule_enabled::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -433,7 +434,8 @@ pub(crate) async fn set_pushrule_enabled_route(
///
/// Deletes a single specified push rule for this user.
pub(crate) async fn delete_pushrule_route(
State(services): State<crate::State>, body: Ruma<delete_pushrule::v3::Request>,
State(services): State<crate::State>,
body: Ruma<delete_pushrule::v3::Request>,
) -> Result<delete_pushrule::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -449,11 +451,13 @@ pub(crate) async fn delete_pushrule_route(
.remove(body.kind.clone(), &body.rule_id)
{
let err = match error {
RemovePushRuleError::ServerDefault => {
Error::BadRequest(ErrorKind::InvalidParam, "Cannot delete a server-default pushrule.")
},
RemovePushRuleError::NotFound => Error::BadRequest(ErrorKind::NotFound, "Push rule not found."),
_ => Error::BadRequest(ErrorKind::InvalidParam, "Invalid data."),
| RemovePushRuleError::ServerDefault => Error::BadRequest(
ErrorKind::InvalidParam,
"Cannot delete a server-default pushrule.",
),
| RemovePushRuleError::NotFound =>
Error::BadRequest(ErrorKind::NotFound, "Push rule not found."),
| _ => Error::BadRequest(ErrorKind::InvalidParam, "Invalid data."),
};
return Err(err);
@ -476,7 +480,8 @@ pub(crate) async fn delete_pushrule_route(
///
/// Gets all currently active pushers for the sender user.
pub(crate) async fn get_pushers_route(
State(services): State<crate::State>, body: Ruma<get_pushers::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_pushers::v3::Request>,
) -> Result<get_pushers::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -491,7 +496,8 @@ pub(crate) async fn get_pushers_route(
///
/// - TODO: Handle `append`
pub(crate) async fn set_pushers_route(
State(services): State<crate::State>, body: Ruma<set_pusher::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_pusher::v3::Request>,
) -> Result<set_pusher::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -506,7 +512,8 @@ pub(crate) async fn set_pushers_route(
/// user somehow has bad push rules, these must always exist per spec.
/// so recreate it and return server default silently
async fn recreate_push_rules_and_return(
services: &Services, sender_user: &ruma::UserId,
services: &Services,
sender_user: &ruma::UserId,
) -> Result<get_pushrules_all::v3::Response> {
services
.account_data

View file

@ -21,15 +21,14 @@ use crate::{Result, Ruma};
/// - If `read_receipt` is set: Update private marker and public read receipt
/// EDU
pub(crate) async fn set_read_marker_route(
State(services): State<crate::State>, body: Ruma<set_read_marker::v3::Request>,
State(services): State<crate::State>,
body: Ruma<set_read_marker::v3::Request>,
) -> Result<set_read_marker::v3::Response> {
let sender_user = body.sender_user();
if let Some(event) = &body.fully_read {
let fully_read_event = ruma::events::fully_read::FullyReadEvent {
content: ruma::events::fully_read::FullyReadEventContent {
event_id: event.clone(),
},
content: ruma::events::fully_read::FullyReadEventContent { event_id: event.clone() },
};
services
@ -55,13 +54,10 @@ pub(crate) async fn set_read_marker_route(
event.to_owned(),
BTreeMap::from_iter([(
ReceiptType::Read,
BTreeMap::from_iter([(
sender_user.to_owned(),
ruma::events::receipt::Receipt {
BTreeMap::from_iter([(sender_user.to_owned(), ruma::events::receipt::Receipt {
ts: Some(MilliSecondsSinceUnixEpoch::now()),
thread: ReceiptThread::Unthreaded,
},
)]),
})]),
)]),
)]);
@ -88,7 +84,9 @@ pub(crate) async fn set_read_marker_route(
.map_err(|_| err!(Request(NotFound("Event not found."))))?;
let PduCount::Normal(count) = count else {
return Err!(Request(InvalidParam("Event is a backfilled PDU and cannot be marked as read.")));
return Err!(Request(InvalidParam(
"Event is a backfilled PDU and cannot be marked as read."
)));
};
services
@ -104,7 +102,8 @@ pub(crate) async fn set_read_marker_route(
///
/// Sets private read marker and public read receipt EDU.
pub(crate) async fn create_receipt_route(
State(services): State<crate::State>, body: Ruma<create_receipt::v3::Request>,
State(services): State<crate::State>,
body: Ruma<create_receipt::v3::Request>,
) -> Result<create_receipt::v3::Response> {
let sender_user = body.sender_user();
@ -119,7 +118,7 @@ pub(crate) async fn create_receipt_route(
}
match body.receipt_type {
create_receipt::v3::ReceiptType::FullyRead => {
| create_receipt::v3::ReceiptType::FullyRead => {
let fully_read_event = ruma::events::fully_read::FullyReadEvent {
content: ruma::events::fully_read::FullyReadEventContent {
event_id: body.event_id.clone(),
@ -135,7 +134,7 @@ pub(crate) async fn create_receipt_route(
)
.await?;
},
create_receipt::v3::ReceiptType::Read => {
| create_receipt::v3::ReceiptType::Read => {
let receipt_content = BTreeMap::from_iter([(
body.event_id.clone(),
BTreeMap::from_iter([(
@ -163,7 +162,7 @@ pub(crate) async fn create_receipt_route(
)
.await;
},
create_receipt::v3::ReceiptType::ReadPrivate => {
| create_receipt::v3::ReceiptType::ReadPrivate => {
let count = services
.rooms
.timeline
@ -172,7 +171,9 @@ pub(crate) async fn create_receipt_route(
.map_err(|_| err!(Request(NotFound("Event not found."))))?;
let PduCount::Normal(count) = count else {
return Err!(Request(InvalidParam("Event is a backfilled PDU and cannot be marked as read.")));
return Err!(Request(InvalidParam(
"Event is a backfilled PDU and cannot be marked as read."
)));
};
services
@ -180,12 +181,11 @@ pub(crate) async fn create_receipt_route(
.read_receipt
.private_read_set(&body.room_id, sender_user, count);
},
_ => {
| _ =>
return Err!(Request(InvalidParam(warn!(
"Received unknown read receipt type: {}",
&body.receipt_type
))))
},
)))),
}
Ok(create_receipt::v3::Response {})

View file

@ -1,5 +1,7 @@
use axum::extract::State;
use ruma::{api::client::redact::redact_event, events::room::redaction::RoomRedactionEventContent};
use ruma::{
api::client::redact::redact_event, events::room::redaction::RoomRedactionEventContent,
};
use crate::{service::pdu::PduBuilder, Result, Ruma};
@ -9,7 +11,8 @@ use crate::{service::pdu::PduBuilder, Result, Ruma};
///
/// - TODO: Handle txn id
pub(crate) async fn redact_event_route(
State(services): State<crate::State>, body: Ruma<redact_event::v3::Request>,
State(services): State<crate::State>,
body: Ruma<redact_event::v3::Request>,
) -> Result<redact_event::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let body = body.body;
@ -35,7 +38,5 @@ pub(crate) async fn redact_event_route(
drop(state_lock);
Ok(redact_event::v3::Response {
event_id: event_id.into(),
})
Ok(redact_event::v3::Response { event_id: event_id.into() })
}

View file

@ -8,7 +8,8 @@ use futures::StreamExt;
use ruma::{
api::{
client::relations::{
get_relating_events, get_relating_events_with_rel_type, get_relating_events_with_rel_type_and_event_type,
get_relating_events, get_relating_events_with_rel_type,
get_relating_events_with_rel_type_and_event_type,
},
Direction,
},
@ -21,7 +22,8 @@ use crate::Ruma;
/// # `GET /_matrix/client/r0/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}`
pub(crate) async fn get_relating_events_with_rel_type_and_event_type_route(
State(services): State<crate::State>, body: Ruma<get_relating_events_with_rel_type_and_event_type::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_relating_events_with_rel_type_and_event_type::v1::Request>,
) -> Result<get_relating_events_with_rel_type_and_event_type::v1::Response> {
paginate_relations_with_filter(
&services,
@ -47,7 +49,8 @@ pub(crate) async fn get_relating_events_with_rel_type_and_event_type_route(
/// # `GET /_matrix/client/r0/rooms/{roomId}/relations/{eventId}/{relType}`
pub(crate) async fn get_relating_events_with_rel_type_route(
State(services): State<crate::State>, body: Ruma<get_relating_events_with_rel_type::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_relating_events_with_rel_type::v1::Request>,
) -> Result<get_relating_events_with_rel_type::v1::Response> {
paginate_relations_with_filter(
&services,
@ -73,7 +76,8 @@ pub(crate) async fn get_relating_events_with_rel_type_route(
/// # `GET /_matrix/client/r0/rooms/{roomId}/relations/{eventId}`
pub(crate) async fn get_relating_events_route(
State(services): State<crate::State>, body: Ruma<get_relating_events::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_relating_events::v1::Request>,
) -> Result<get_relating_events::v1::Response> {
paginate_relations_with_filter(
&services,
@ -93,16 +97,24 @@ pub(crate) async fn get_relating_events_route(
#[allow(clippy::too_many_arguments)]
async fn paginate_relations_with_filter(
services: &Services, sender_user: &UserId, room_id: &RoomId, target: &EventId,
filter_event_type: Option<TimelineEventType>, filter_rel_type: Option<RelationType>, from: Option<&str>,
to: Option<&str>, limit: Option<UInt>, recurse: bool, dir: Direction,
services: &Services,
sender_user: &UserId,
room_id: &RoomId,
target: &EventId,
filter_event_type: Option<TimelineEventType>,
filter_rel_type: Option<RelationType>,
from: Option<&str>,
to: Option<&str>,
limit: Option<UInt>,
recurse: bool,
dir: Direction,
) -> Result<get_relating_events::v1::Response> {
let start: PduCount = from
.map(str::parse)
.transpose()?
.unwrap_or_else(|| match dir {
Direction::Forward => PduCount::min(),
Direction::Backward => PduCount::max(),
| Direction::Forward => PduCount::min(),
| Direction::Backward => PduCount::max(),
});
let to: Option<PduCount> = to.map(str::parse).flat_ok();
@ -115,11 +127,7 @@ async fn paginate_relations_with_filter(
.min(100);
// Spec (v1.10) recommends depth of at least 3
let depth: u8 = if recurse {
3
} else {
1
};
let depth: u8 = if recurse { 3 } else { 1 };
let events: Vec<PdusIterItem> = services
.rooms
@ -145,8 +153,8 @@ async fn paginate_relations_with_filter(
.await;
let next_batch = match dir {
Direction::Forward => events.last(),
Direction::Backward => events.first(),
| Direction::Forward => events.last(),
| Direction::Backward => events.first(),
}
.map(at!(0))
.as_ref()
@ -164,7 +172,11 @@ async fn paginate_relations_with_filter(
})
}
async fn visibility_filter(services: &Services, sender_user: &UserId, item: PdusIterItem) -> Option<PdusIterItem> {
async fn visibility_filter(
services: &Services,
sender_user: &UserId,
item: PdusIterItem,
) -> Option<PdusIterItem> {
let (_, pdu) = &item;
services

View file

@ -25,7 +25,8 @@ use crate::{
/// Reports an abusive room to homeserver admins
#[tracing::instrument(skip_all, fields(%client), name = "report_room")]
pub(crate) async fn report_room_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<report_room::v3::Request>,
) -> Result<report_room::v3::Response> {
// user authentication
@ -78,14 +79,16 @@ pub(crate) async fn report_room_route(
/// Reports an inappropriate event to homeserver admins
#[tracing::instrument(skip_all, fields(%client), name = "report_event")]
pub(crate) async fn report_event_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<report_content::v3::Request>,
) -> Result<report_content::v3::Response> {
// user authentication
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
info!(
"Received event report by user {sender_user} for room {} and event ID {}, with reason: \"{}\"",
"Received event report by user {sender_user} for room {} and event ID {}, with reason: \
\"{}\"",
body.room_id,
body.event_id,
body.reason.as_deref().unwrap_or("")
@ -114,8 +117,8 @@ pub(crate) async fn report_event_route(
services
.admin
.send_message(message::RoomMessageEventContent::text_markdown(format!(
"@room Event report received from {} -\n\nEvent ID: {}\nRoom ID: {}\nSent By: {}\n\nReport Score: \
{}\nReport Reason: {}",
"@room Event report received from {} -\n\nEvent ID: {}\nRoom ID: {}\nSent By: \
{}\n\nReport Score: {}\nReport Reason: {}",
sender_user.to_owned(),
pdu.event_id,
pdu.room_id,
@ -136,10 +139,18 @@ pub(crate) async fn report_event_route(
/// check if report reasoning is less than or equal to 750 characters
/// check if reporting user is in the reporting room
async fn is_event_report_valid(
services: &Services, event_id: &EventId, room_id: &RoomId, sender_user: &UserId, reason: Option<&String>,
score: Option<ruma::Int>, pdu: &PduEvent,
services: &Services,
event_id: &EventId,
room_id: &RoomId,
sender_user: &UserId,
reason: Option<&String>,
score: Option<ruma::Int>,
pdu: &PduEvent,
) -> Result<()> {
debug_info!("Checking if report from user {sender_user} for event {event_id} in room {room_id} is valid");
debug_info!(
"Checking if report from user {sender_user} for event {event_id} in room {room_id} is \
valid"
);
if room_id != pdu.room_id {
return Err(Error::BadRequest(
@ -183,6 +194,9 @@ async fn is_event_report_valid(
/// enumerating for potential events existing in our server.
async fn delay_response() {
let time_to_wait = rand::thread_rng().gen_range(2..5);
debug_info!("Got successful /report request, waiting {time_to_wait} seconds before sending successful response.");
debug_info!(
"Got successful /report request, waiting {time_to_wait} seconds before sending \
successful response."
);
sleep(Duration::from_secs(time_to_wait)).await;
}

View file

@ -12,7 +12,8 @@ use crate::Ruma;
/// - Only users joined to the room are allowed to call this, or if
/// `history_visibility` is world readable in the room
pub(crate) async fn get_room_aliases_route(
State(services): State<crate::State>, body: Ruma<aliases::v3::Request>,
State(services): State<crate::State>,
body: Ruma<aliases::v3::Request>,
) -> Result<aliases::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");

View file

@ -24,7 +24,8 @@ use ruma::{
},
int,
serde::{JsonObject, Raw},
CanonicalJsonObject, Int, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId, RoomVersionId,
CanonicalJsonObject, Int, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId,
RoomVersionId,
};
use serde_json::{json, value::to_raw_value};
use service::{appservice::RegistrationInfo, Services};
@ -49,7 +50,8 @@ use crate::{client::invite_helper, Ruma};
/// - Send invite events
#[allow(clippy::large_stack_frames)]
pub(crate) async fn create_room_route(
State(services): State<crate::State>, body: Ruma<create_room::v3::Request>,
State(services): State<crate::State>,
body: Ruma<create_room::v3::Request>,
) -> Result<create_room::v3::Response> {
use create_room::v3::RoomPreset;
@ -59,7 +61,10 @@ pub(crate) async fn create_room_route(
&& body.appservice_info.is_none()
&& !services.users.is_admin(sender_user).await
{
return Err(Error::BadRequest(ErrorKind::forbidden(), "Room creation has been disabled."));
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Room creation has been disabled.",
));
}
let room_id: OwnedRoomId = if let Some(custom_room_id) = &body.room_id {
@ -91,8 +96,8 @@ pub(crate) async fn create_room_route(
services
.admin
.send_text(&format!(
"Non-admin user {sender_user} tried to publish {0} to the room directory while \
\"lockdown_public_room_directory\" is enabled",
"Non-admin user {sender_user} tried to publish {0} to the room directory \
while \"lockdown_public_room_directory\" is enabled",
&room_id
))
.await;
@ -115,7 +120,7 @@ pub(crate) async fn create_room_route(
};
let room_version = match body.room_version.clone() {
Some(room_version) => {
| Some(room_version) =>
if services.server.supported_room_version(&room_version) {
room_version
} else {
@ -123,13 +128,12 @@ pub(crate) async fn create_room_route(
ErrorKind::UnsupportedRoomVersion,
"This server does not support that room version.",
));
}
},
None => services.server.config.default_room_version.clone(),
| None => services.server.config.default_room_version.clone(),
};
let create_content = match &body.creation_content {
Some(content) => {
| Some(content) => {
use RoomVersionId::*;
let mut content = content
@ -139,7 +143,7 @@ pub(crate) async fn create_room_route(
Error::bad_database("Failed to deserialise content as canonical JSON.")
})?;
match room_version {
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
content.insert(
"creator".into(),
json!(&sender_user).try_into().map_err(|e| {
@ -148,24 +152,25 @@ pub(crate) async fn create_room_route(
})?,
);
},
_ => {
| _ => {
// V11+ removed the "creator" key
},
}
content.insert(
"room_version".into(),
json!(room_version.as_str())
.try_into()
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid creation content"))?,
json!(room_version.as_str()).try_into().map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid creation content")
})?,
);
content
},
None => {
| None => {
use RoomVersionId::*;
let content = match room_version {
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => RoomCreateEventContent::new_v1(sender_user.clone()),
_ => RoomCreateEventContent::new_v11(),
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 =>
RoomCreateEventContent::new_v1(sender_user.clone()),
| _ => RoomCreateEventContent::new_v11(),
};
let mut content = serde_json::from_str::<CanonicalJsonObject>(
to_raw_value(&content)
@ -190,7 +195,8 @@ pub(crate) async fn create_room_route(
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomCreate,
content: to_raw_value(&create_content).expect("create event content serialization"),
content: to_raw_value(&create_content)
.expect("create event content serialization"),
state_key: Some(String::new()),
..Default::default()
},
@ -206,16 +212,13 @@ pub(crate) async fn create_room_route(
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(
sender_user.to_string(),
&RoomMemberEventContent {
PduBuilder::state(sender_user.to_string(), &RoomMemberEventContent {
displayname: services.users.displayname(sender_user).await.ok(),
avatar_url: services.users.avatar_url(sender_user).await.ok(),
blurhash: services.users.blurhash(sender_user).await.ok(),
is_direct: Some(body.is_direct),
..RoomMemberEventContent::new(MembershipState::Join)
},
),
}),
sender_user,
&room_id,
&state_lock,
@ -227,8 +230,8 @@ pub(crate) async fn create_room_route(
// Figure out preset. We need it for preset specific events
let preset = body.preset.clone().unwrap_or(match &body.visibility {
room::Visibility::Public => RoomPreset::PublicChat,
_ => RoomPreset::PrivateChat, // Room visibility should not be custom
| room::Visibility::Public => RoomPreset::PublicChat,
| _ => RoomPreset::PrivateChat, // Room visibility should not be custom
});
let mut users = BTreeMap::from_iter([(sender_user.clone(), int!(100))]);
@ -236,7 +239,9 @@ pub(crate) async fn create_room_route(
if preset == RoomPreset::TrustedPrivateChat {
for invite in &body.invite {
if services.users.user_is_ignored(sender_user, invite).await {
return Err!(Request(Forbidden("You cannot invite users you have ignored to rooms.")));
return Err!(Request(Forbidden(
"You cannot invite users you have ignored to rooms."
)));
} else if services.users.user_is_ignored(invite, sender_user).await {
// silently drop the invite to the recipient if they've been ignored by the
// sender, pretend it worked
@ -247,8 +252,11 @@ pub(crate) async fn create_room_route(
}
}
let power_levels_content =
default_power_levels_content(body.power_level_content_override.as_ref(), &body.visibility, users)?;
let power_levels_content = default_power_levels_content(
body.power_level_content_override.as_ref(),
&body.visibility,
users,
)?;
services
.rooms
@ -256,7 +264,8 @@ pub(crate) async fn create_room_route(
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomPowerLevels,
content: to_raw_value(&power_levels_content).expect("serialized power_levels event content"),
content: to_raw_value(&power_levels_content)
.expect("serialized power_levels event content"),
state_key: Some(String::new()),
..Default::default()
},
@ -273,13 +282,10 @@ pub(crate) async fn create_room_route(
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(
String::new(),
&RoomCanonicalAliasEventContent {
PduBuilder::state(String::new(), &RoomCanonicalAliasEventContent {
alias: Some(room_alias_id.to_owned()),
alt_aliases: vec![],
},
),
}),
sender_user,
&room_id,
&state_lock,
@ -298,9 +304,9 @@ pub(crate) async fn create_room_route(
PduBuilder::state(
String::new(),
&RoomJoinRulesEventContent::new(match preset {
RoomPreset::PublicChat => JoinRule::Public,
| RoomPreset::PublicChat => JoinRule::Public,
// according to spec "invite" is the default
_ => JoinRule::Invite,
| _ => JoinRule::Invite,
}),
),
sender_user,
@ -334,8 +340,8 @@ pub(crate) async fn create_room_route(
PduBuilder::state(
String::new(),
&RoomGuestAccessEventContent::new(match preset {
RoomPreset::PublicChat => GuestAccess::Forbidden,
_ => GuestAccess::CanJoin,
| RoomPreset::PublicChat => GuestAccess::Forbidden,
| _ => GuestAccess::CanJoin,
}),
),
sender_user,
@ -367,7 +373,9 @@ pub(crate) async fn create_room_route(
pdu_builder.state_key.get_or_insert_with(String::new);
// Silently skip encryption events if they are not allowed
if pdu_builder.event_type == TimelineEventType::RoomEncryption && !services.globals.allow_encryption() {
if pdu_builder.event_type == TimelineEventType::RoomEncryption
&& !services.globals.allow_encryption()
{
continue;
}
@ -399,12 +407,7 @@ pub(crate) async fn create_room_route(
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(
String::new(),
&RoomTopicEventContent {
topic: topic.clone(),
},
),
PduBuilder::state(String::new(), &RoomTopicEventContent { topic: topic.clone() }),
sender_user,
&room_id,
&state_lock,
@ -417,14 +420,17 @@ pub(crate) async fn create_room_route(
drop(state_lock);
for user_id in &body.invite {
if services.users.user_is_ignored(sender_user, user_id).await {
return Err!(Request(Forbidden("You cannot invite users you have ignored to rooms.")));
return Err!(Request(Forbidden(
"You cannot invite users you have ignored to rooms."
)));
} else if services.users.user_is_ignored(user_id, sender_user).await {
// silently drop the invite to the recipient if they've been ignored by the
// sender, pretend it worked
continue;
}
if let Err(e) = invite_helper(&services, sender_user, user_id, &room_id, None, body.is_direct)
if let Err(e) =
invite_helper(&services, sender_user, user_id, &room_id, None, body.is_direct)
.boxed()
.await
{
@ -446,7 +452,10 @@ pub(crate) async fn create_room_route(
if services.globals.config.admin_room_notices {
services
.admin
.send_text(&format!("{sender_user} made {} public to the room directory", &room_id))
.send_text(&format!(
"{sender_user} made {} public to the room directory",
&room_id
))
.await;
}
info!("{sender_user} made {0} public to the room directory", &room_id);
@ -459,21 +468,24 @@ pub(crate) async fn create_room_route(
/// creates the power_levels_content for the PDU builder
fn default_power_levels_content(
power_level_content_override: Option<&Raw<RoomPowerLevelsEventContent>>, visibility: &room::Visibility,
power_level_content_override: Option<&Raw<RoomPowerLevelsEventContent>>,
visibility: &room::Visibility,
users: BTreeMap<OwnedUserId, Int>,
) -> Result<serde_json::Value> {
let mut power_levels_content = serde_json::to_value(RoomPowerLevelsEventContent {
users,
..Default::default()
})
let mut power_levels_content =
serde_json::to_value(RoomPowerLevelsEventContent { users, ..Default::default() })
.expect("event is valid, we just created it");
// secure proper defaults of sensitive/dangerous permissions that moderators
// (power level 50) should not have easy access to
power_levels_content["events"]["m.room.power_levels"] = serde_json::to_value(100).expect("100 is valid Value");
power_levels_content["events"]["m.room.server_acl"] = serde_json::to_value(100).expect("100 is valid Value");
power_levels_content["events"]["m.room.tombstone"] = serde_json::to_value(100).expect("100 is valid Value");
power_levels_content["events"]["m.room.encryption"] = serde_json::to_value(100).expect("100 is valid Value");
power_levels_content["events"]["m.room.power_levels"] =
serde_json::to_value(100).expect("100 is valid Value");
power_levels_content["events"]["m.room.server_acl"] =
serde_json::to_value(100).expect("100 is valid Value");
power_levels_content["events"]["m.room.tombstone"] =
serde_json::to_value(100).expect("100 is valid Value");
power_levels_content["events"]["m.room.encryption"] =
serde_json::to_value(100).expect("100 is valid Value");
power_levels_content["events"]["m.room.history_visibility"] =
serde_json::to_value(100).expect("100 is valid Value");
@ -481,14 +493,18 @@ fn default_power_levels_content(
// useful in read-only announcement rooms that post a public poll.
power_levels_content["events"]["org.matrix.msc3381.poll.response"] =
serde_json::to_value(0).expect("0 is valid Value");
power_levels_content["events"]["m.poll.response"] = serde_json::to_value(0).expect("0 is valid Value");
power_levels_content["events"]["m.poll.response"] =
serde_json::to_value(0).expect("0 is valid Value");
// synapse does this too. clients do not expose these permissions. it prevents
// default users from calling public rooms, for obvious reasons.
if *visibility == room::Visibility::Public {
power_levels_content["events"]["m.call.invite"] = serde_json::to_value(50).expect("50 is valid Value");
power_levels_content["events"]["m.call"] = serde_json::to_value(50).expect("50 is valid Value");
power_levels_content["events"]["m.call.member"] = serde_json::to_value(50).expect("50 is valid Value");
power_levels_content["events"]["m.call.invite"] =
serde_json::to_value(50).expect("50 is valid Value");
power_levels_content["events"]["m.call"] =
serde_json::to_value(50).expect("50 is valid Value");
power_levels_content["events"]["m.call.member"] =
serde_json::to_value(50).expect("50 is valid Value");
power_levels_content["events"]["org.matrix.msc3401.call"] =
serde_json::to_value(50).expect("50 is valid Value");
power_levels_content["events"]["org.matrix.msc3401.call.member"] =
@ -497,7 +513,9 @@ fn default_power_levels_content(
if let Some(power_level_content_override) = power_level_content_override {
let json: JsonObject = serde_json::from_str(power_level_content_override.json().get())
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid power_level_content_override."))?;
.map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid power_level_content_override.")
})?;
for (key, value) in json {
power_levels_content[key] = value;
@ -509,14 +527,16 @@ fn default_power_levels_content(
/// if a room is being created with a room alias, run our checks
async fn room_alias_check(
services: &Services, room_alias_name: &str, appservice_info: Option<&RegistrationInfo>,
services: &Services,
room_alias_name: &str,
appservice_info: Option<&RegistrationInfo>,
) -> Result<OwnedRoomAliasId> {
// Basic checks on the room alias validity
if room_alias_name.contains(':') {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Room alias contained `:` which is not allowed. Please note that this expects a localpart, not the full \
room alias.",
"Room alias contained `:` which is not allowed. Please note that this expects a \
localpart, not the full room alias.",
));
} else if room_alias_name.contains(char::is_whitespace) {
return Err(Error::BadRequest(
@ -534,7 +554,10 @@ async fn room_alias_check(
return Err(Error::BadRequest(ErrorKind::Unknown, "Room alias name is forbidden."));
}
let full_room_alias = RoomAliasId::parse(format!("#{}:{}", room_alias_name, services.globals.config.server_name))
let full_room_alias = RoomAliasId::parse(format!(
"#{}:{}",
room_alias_name, services.globals.config.server_name
))
.map_err(|e| {
info!("Failed to parse room alias {room_alias_name}: {e}");
Error::BadRequest(ErrorKind::InvalidParam, "Invalid room alias specified.")
@ -552,14 +575,20 @@ async fn room_alias_check(
if let Some(info) = appservice_info {
if !info.aliases.is_match(full_room_alias.as_str()) {
return Err(Error::BadRequest(ErrorKind::Exclusive, "Room alias is not in namespace."));
return Err(Error::BadRequest(
ErrorKind::Exclusive,
"Room alias is not in namespace.",
));
}
} else if services
.appservice
.is_exclusive_alias(&full_room_alias)
.await
{
return Err(Error::BadRequest(ErrorKind::Exclusive, "Room alias reserved by appservice."));
return Err(Error::BadRequest(
ErrorKind::Exclusive,
"Room alias reserved by appservice.",
));
}
debug_info!("Full room alias: {full_room_alias}");
@ -581,8 +610,8 @@ fn custom_room_id_check(services: &Services, custom_room_id: &str) -> Result<Own
if custom_room_id.contains(':') {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Custom room ID contained `:` which is not allowed. Please note that this expects a localpart, not the \
full room ID.",
"Custom room ID contained `:` which is not allowed. Please note that this expects a \
localpart, not the full room ID.",
));
} else if custom_room_id.contains(char::is_whitespace) {
return Err(Error::BadRequest(
@ -596,7 +625,10 @@ fn custom_room_id_check(services: &Services, custom_room_id: &str) -> Result<Own
debug_info!("Full custom room ID: {full_room_id}");
RoomId::parse(full_room_id).map_err(|e| {
info!("User attempted to create room with custom room ID {custom_room_id} but failed parsing: {e}");
info!(
"User attempted to create room with custom room ID {custom_room_id} but failed \
parsing: {e}"
);
Error::BadRequest(ErrorKind::InvalidParam, "Custom room ID could not be parsed")
})
}

View file

@ -9,7 +9,8 @@ use crate::{client::ignored_filter, Ruma};
///
/// Gets a single event.
pub(crate) async fn get_room_event_route(
State(services): State<crate::State>, ref body: Ruma<get_room_event::v3::Request>,
State(services): State<crate::State>,
ref body: Ruma<get_room_event::v3::Request>,
) -> Result<get_room_event::v3::Response> {
let event = services
.rooms
@ -47,7 +48,5 @@ pub(crate) async fn get_room_event_route(
let event = event.to_room_event();
Ok(get_room_event::v3::Response {
event,
})
Ok(get_room_event::v3::Response { event })
}

View file

@ -8,7 +8,8 @@ use crate::Ruma;
const LIMIT_MAX: usize = 100;
pub(crate) async fn room_initial_sync_route(
State(services): State<crate::State>, body: Ruma<Request>,
State(services): State<crate::State>,
body: Ruma<Request>,
) -> Result<Response> {
let room_id = &body.room_id;

View file

@ -43,7 +43,8 @@ const TRANSFERABLE_STATE_EVENTS: &[StateEventType; 9] = &[
/// - Moves local aliases
/// - Modifies old room power levels to prevent users from speaking
pub(crate) async fn upgrade_room_route(
State(services): State<crate::State>, body: Ruma<upgrade_room::v3::Request>,
State(services): State<crate::State>,
body: Ruma<upgrade_room::v3::Request>,
) -> Result<upgrade_room::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -72,13 +73,10 @@ pub(crate) async fn upgrade_room_route(
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(
String::new(),
&RoomTombstoneEventContent {
PduBuilder::state(String::new(), &RoomTombstoneEventContent {
body: "This room has been replaced".to_owned(),
replacement_room: replacement_room.clone(),
},
),
}),
sender_user,
&body.room_id,
&state_lock,
@ -108,7 +106,7 @@ pub(crate) async fn upgrade_room_route(
{
use RoomVersionId::*;
match body.new_version {
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
create_event_content.insert(
"creator".into(),
json!(&sender_user).try_into().map_err(|e| {
@ -117,7 +115,7 @@ pub(crate) async fn upgrade_room_route(
})?,
);
},
_ => {
| _ => {
// "creator" key no longer exists in V11+ rooms
create_event_content.remove("creator");
},
@ -154,7 +152,8 @@ pub(crate) async fn upgrade_room_route(
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomCreate,
content: to_raw_value(&create_event_content).expect("event is valid, we just created it"),
content: to_raw_value(&create_event_content)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(String::new()),
redacts: None,
@ -203,8 +202,8 @@ pub(crate) async fn upgrade_room_route(
.room_state_get(&body.room_id, event_type, "")
.await
{
Ok(v) => v.content.clone(),
Err(_) => continue, // Skipping missing events.
| Ok(v) => v.content.clone(),
| Err(_) => continue, // Skipping missing events.
};
services
@ -258,7 +257,9 @@ pub(crate) async fn upgrade_room_route(
power_levels_event_content
.users_default
.checked_add(int!(1))
.ok_or_else(|| err!(Request(BadJson("users_default power levels event content is not valid"))))?,
.ok_or_else(|| {
err!(Request(BadJson("users_default power levels event content is not valid")))
})?,
);
// Modify the power levels in the old room to prevent sending of events and
@ -267,14 +268,11 @@ pub(crate) async fn upgrade_room_route(
.rooms
.timeline
.build_and_append_pdu(
PduBuilder::state(
String::new(),
&RoomPowerLevelsEventContent {
PduBuilder::state(String::new(), &RoomPowerLevelsEventContent {
events_default: new_level,
invite: new_level,
..power_levels_event_content
},
),
}),
sender_user,
&body.room_id,
&state_lock,
@ -284,7 +282,5 @@ pub(crate) async fn upgrade_room_route(
drop(state_lock);
// Return the replacement room id
Ok(upgrade_room::v3::Response {
replacement_room,
})
Ok(upgrade_room::v3::Response { replacement_room })
}

View file

@ -35,7 +35,10 @@ const BATCH_MAX: usize = 20;
///
/// - Only works if the user is currently joined to the room (TODO: Respect
/// history visibility)
pub(crate) async fn search_events_route(State(services): State<crate::State>, body: Ruma<Request>) -> Result<Response> {
pub(crate) async fn search_events_route(
State(services): State<crate::State>,
body: Ruma<Request>,
) -> Result<Response> {
let sender_user = body.sender_user();
let next_batch = body.next_batch.as_deref();
let room_events_result: OptionFuture<_> = body
@ -56,7 +59,10 @@ pub(crate) async fn search_events_route(State(services): State<crate::State>, bo
#[allow(clippy::map_unwrap_or)]
async fn category_room_events(
services: &Services, sender_user: &UserId, next_batch: Option<&str>, criteria: &Criteria,
services: &Services,
sender_user: &UserId,
next_batch: Option<&str>,
criteria: &Criteria,
) -> Result<ResultRoomEvents> {
let filter = &criteria.filter;
@ -186,11 +192,17 @@ async fn procure_room_state(services: &Services, room_id: &RoomId) -> Result<Roo
Ok(state_events)
}
async fn check_room_visible(services: &Services, user_id: &UserId, room_id: &RoomId, search: &Criteria) -> Result {
async fn check_room_visible(
services: &Services,
user_id: &UserId,
room_id: &RoomId,
search: &Criteria,
) -> Result {
let check_visible = search.filter.rooms.is_some();
let check_state = check_visible && search.include_state.is_some_and(is_true!());
let is_joined = !check_visible || services.rooms.state_cache.is_joined(user_id, room_id).await;
let is_joined =
!check_visible || services.rooms.state_cache.is_joined(user_id, room_id).await;
let state_visible = !check_state
|| services

View file

@ -17,14 +17,17 @@ use crate::{service::pdu::PduBuilder, utils, Result, Ruma};
/// - Tries to send the event into the room, auth rules will determine if it is
/// allowed
pub(crate) async fn send_message_event_route(
State(services): State<crate::State>, body: Ruma<send_message_event::v3::Request>,
State(services): State<crate::State>,
body: Ruma<send_message_event::v3::Request>,
) -> Result<send_message_event::v3::Response> {
let sender_user = body.sender_user();
let sender_device = body.sender_device.as_deref();
let appservice_info = body.appservice_info.as_ref();
// Forbid m.room.encrypted if encryption is disabled
if MessageLikeEventType::RoomEncrypted == body.event_type && !services.globals.allow_encryption() {
if MessageLikeEventType::RoomEncrypted == body.event_type
&& !services.globals.allow_encryption()
{
return Err!(Request(Forbidden("Encryption has been disabled")));
}
@ -60,8 +63,8 @@ pub(crate) async fn send_message_event_route(
let mut unsigned = BTreeMap::new();
unsigned.insert("transaction_id".to_owned(), body.txn_id.to_string().into());
let content =
from_str(body.body.body.json().get()).map_err(|e| err!(Request(BadJson("Invalid JSON body: {e}"))))?;
let content = from_str(body.body.body.json().get())
.map_err(|e| err!(Request(BadJson("Invalid JSON body: {e}"))))?;
let event_id = services
.rooms
@ -80,13 +83,14 @@ pub(crate) async fn send_message_event_route(
)
.await?;
services
.transaction_ids
.add_txnid(sender_user, sender_device, &body.txn_id, event_id.as_bytes());
services.transaction_ids.add_txnid(
sender_user,
sender_device,
&body.txn_id,
event_id.as_bytes(),
);
drop(state_lock);
Ok(send_message_event::v3::Response {
event_id: event_id.into(),
})
Ok(send_message_event::v3::Response { event_id: event_id.into() })
}

View file

@ -37,7 +37,8 @@ struct Claims {
/// the `type` field when logging in.
#[tracing::instrument(skip_all, fields(%client), name = "login")]
pub(crate) async fn get_login_types_route(
InsecureClientIp(client): InsecureClientIp, _body: Ruma<get_login_types::v3::Request>,
InsecureClientIp(client): InsecureClientIp,
_body: Ruma<get_login_types::v3::Request>,
) -> Result<get_login_types::v3::Response> {
Ok(get_login_types::v3::Response::new(vec![
get_login_types::v3::LoginType::Password(PasswordLoginType::default()),
@ -61,13 +62,15 @@ pub(crate) async fn get_login_types_route(
/// supported login types.
#[tracing::instrument(skip_all, fields(%client), name = "login")]
pub(crate) async fn login_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp, body: Ruma<login::v3::Request>,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<login::v3::Request>,
) -> Result<login::v3::Response> {
// Validate login method
// TODO: Other login methods
let user_id = match &body.login_info {
#[allow(deprecated)]
login::v3::LoginInfo::Password(login::v3::Password {
| login::v3::LoginInfo::Password(login::v3::Password {
identifier,
password,
user,
@ -75,7 +78,10 @@ pub(crate) async fn login_route(
}) => {
debug!("Got password login type");
let user_id = if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
UserId::parse_with_server_name(user_id.to_lowercase(), services.globals.server_name())
UserId::parse_with_server_name(
user_id.to_lowercase(),
services.globals.server_name(),
)
} else if let Some(user) = user {
UserId::parse(user)
} else {
@ -100,13 +106,14 @@ pub(crate) async fn login_route(
user_id
},
login::v3::LoginInfo::Token(login::v3::Token {
token,
}) => {
| login::v3::LoginInfo::Token(login::v3::Token { token }) => {
debug!("Got token login type");
if let Some(jwt_decoding_key) = services.globals.jwt_decoding_key() {
let token =
jsonwebtoken::decode::<Claims>(token, jwt_decoding_key, &jsonwebtoken::Validation::default())
let token = jsonwebtoken::decode::<Claims>(
token,
jwt_decoding_key,
&jsonwebtoken::Validation::default(),
)
.map_err(|e| {
warn!("Failed to parse JWT token from user logging in: {e}");
Error::BadRequest(ErrorKind::InvalidUsername, "Token is invalid.")
@ -114,8 +121,14 @@ pub(crate) async fn login_route(
let username = token.claims.sub.to_lowercase();
UserId::parse_with_server_name(username, services.globals.server_name())
.map_err(|e| err!(Request(InvalidUsername(debug_error!(?e, "Failed to parse login username")))))?
UserId::parse_with_server_name(username, services.globals.server_name()).map_err(
|e| {
err!(Request(InvalidUsername(debug_error!(
?e,
"Failed to parse login username"
))))
},
)?
} else {
return Err!(Request(Unknown(
"Token login is not supported (server has no jwt decoding key)."
@ -123,13 +136,16 @@ pub(crate) async fn login_route(
}
},
#[allow(deprecated)]
login::v3::LoginInfo::ApplicationService(login::v3::ApplicationService {
| login::v3::LoginInfo::ApplicationService(login::v3::ApplicationService {
identifier,
user,
}) => {
debug!("Got appservice login type");
let user_id = if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
UserId::parse_with_server_name(user_id.to_lowercase(), services.globals.server_name())
UserId::parse_with_server_name(
user_id.to_lowercase(),
services.globals.server_name(),
)
} else if let Some(user) = user {
UserId::parse(user)
} else {
@ -143,18 +159,27 @@ pub(crate) async fn login_route(
if let Some(ref info) = body.appservice_info {
if !info.is_user_match(&user_id) {
return Err(Error::BadRequest(ErrorKind::Exclusive, "User is not in namespace."));
return Err(Error::BadRequest(
ErrorKind::Exclusive,
"User is not in namespace.",
));
}
} else {
return Err(Error::BadRequest(ErrorKind::MissingToken, "Missing appservice token."));
return Err(Error::BadRequest(
ErrorKind::MissingToken,
"Missing appservice token.",
));
}
user_id
},
_ => {
| _ => {
warn!("Unsupported or unknown login type: {:?}", &body.login_info);
debug!("JSON body: {:?}", &body.json_body);
return Err(Error::BadRequest(ErrorKind::Unknown, "Unsupported or unknown login type."));
return Err(Error::BadRequest(
ErrorKind::Unknown,
"Unsupported or unknown login type.",
));
},
};
@ -233,7 +258,9 @@ pub(crate) async fn login_route(
/// - Triggers device list updates
#[tracing::instrument(skip_all, fields(%client), name = "logout")]
pub(crate) async fn logout_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp, body: Ruma<logout::v3::Request>,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<logout::v3::Request>,
) -> Result<logout::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
@ -261,7 +288,8 @@ pub(crate) async fn logout_route(
/// user.
#[tracing::instrument(skip_all, fields(%client), name = "logout")]
pub(crate) async fn logout_all_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<logout_all::v3::Request>,
) -> Result<logout_all::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");

View file

@ -13,7 +13,8 @@ use crate::{service::rooms::spaces::PaginationToken, Error, Result, Ruma};
/// Paginates over the space tree in a depth-first manner to locate child rooms
/// of a given space.
pub(crate) async fn get_hierarchy_route(
State(services): State<crate::State>, body: Ruma<get_hierarchy::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_hierarchy::v1::Request>,
) -> Result<get_hierarchy::v1::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");

View file

@ -31,7 +31,8 @@ use crate::{Ruma, RumaResponse};
/// allowed
/// - If event is new `canonical_alias`: Rejects if alias is incorrect
pub(crate) async fn send_state_event_for_key_route(
State(services): State<crate::State>, body: Ruma<send_state_event::v3::Request>,
State(services): State<crate::State>,
body: Ruma<send_state_event::v3::Request>,
) -> Result<send_state_event::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -63,7 +64,8 @@ pub(crate) async fn send_state_event_for_key_route(
/// allowed
/// - If event is new `canonical_alias`: Rejects if alias is incorrect
pub(crate) async fn send_state_event_for_empty_key_route(
State(services): State<crate::State>, body: Ruma<send_state_event::v3::Request>,
State(services): State<crate::State>,
body: Ruma<send_state_event::v3::Request>,
) -> Result<RumaResponse<send_state_event::v3::Response>> {
send_state_event_for_key_route(State(services), body)
.await
@ -77,7 +79,8 @@ pub(crate) async fn send_state_event_for_empty_key_route(
/// - If not joined: Only works if current room history visibility is world
/// readable
pub(crate) async fn get_state_events_route(
State(services): State<crate::State>, body: Ruma<get_state_events::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_state_events::v3::Request>,
) -> Result<get_state_events::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -111,7 +114,8 @@ pub(crate) async fn get_state_events_route(
/// - If not joined: Only works if current room history visibility is world
/// readable
pub(crate) async fn get_state_events_for_key_route(
State(services): State<crate::State>, body: Ruma<get_state_events_for_key::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_state_events_for_key::v3::Request>,
) -> Result<get_state_events_for_key::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -157,7 +161,8 @@ pub(crate) async fn get_state_events_for_key_route(
/// - If not joined: Only works if current room history visibility is world
/// readable
pub(crate) async fn get_state_events_for_empty_key_route(
State(services): State<crate::State>, body: Ruma<get_state_events_for_key::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_state_events_for_key::v3::Request>,
) -> Result<RumaResponse<get_state_events_for_key::v3::Response>> {
get_state_events_for_key_route(State(services), body)
.await
@ -165,8 +170,13 @@ pub(crate) async fn get_state_events_for_empty_key_route(
}
async fn send_state_event_for_key_helper(
services: &Services, sender: &UserId, room_id: &RoomId, event_type: &StateEventType,
json: &Raw<AnyStateEventContent>, state_key: String, timestamp: Option<ruma::MilliSecondsSinceUnixEpoch>,
services: &Services,
sender: &UserId,
room_id: &RoomId,
event_type: &StateEventType,
json: &Raw<AnyStateEventContent>,
state_key: String,
timestamp: Option<ruma::MilliSecondsSinceUnixEpoch>,
) -> Result<Arc<EventId>> {
allowed_to_send_state_event(services, room_id, event_type, json).await?;
let state_lock = services.rooms.state.mutex.lock(room_id).await;
@ -191,20 +201,27 @@ async fn send_state_event_for_key_helper(
}
async fn allowed_to_send_state_event(
services: &Services, room_id: &RoomId, event_type: &StateEventType, json: &Raw<AnyStateEventContent>,
services: &Services,
room_id: &RoomId,
event_type: &StateEventType,
json: &Raw<AnyStateEventContent>,
) -> Result {
match event_type {
// Forbid m.room.encryption if encryption is disabled
StateEventType::RoomEncryption => {
| StateEventType::RoomEncryption =>
if !services.globals.allow_encryption() {
return Err(Error::BadRequest(ErrorKind::forbidden(), "Encryption has been disabled"));
}
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Encryption has been disabled",
));
},
// admin room is a sensitive room, it should not ever be made public
StateEventType::RoomJoinRules => {
| StateEventType::RoomJoinRules => {
if let Ok(admin_room_id) = services.admin.get_admin_room().await {
if admin_room_id == room_id {
if let Ok(join_rule) = serde_json::from_str::<RoomJoinRulesEventContent>(json.json().get()) {
if let Ok(join_rule) =
serde_json::from_str::<RoomJoinRulesEventContent>(json.json().get())
{
if join_rule.join_rule == JoinRule::Public {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
@ -216,16 +233,20 @@ async fn allowed_to_send_state_event(
}
},
// admin room is a sensitive room, it should not ever be made world readable
StateEventType::RoomHistoryVisibility => {
| StateEventType::RoomHistoryVisibility => {
if let Ok(admin_room_id) = services.admin.get_admin_room().await {
if admin_room_id == room_id {
if let Ok(visibility_content) =
serde_json::from_str::<RoomHistoryVisibilityEventContent>(json.json().get())
if let Ok(visibility_content) = serde_json::from_str::<
RoomHistoryVisibilityEventContent,
>(json.json().get())
{
if visibility_content.history_visibility
== HistoryVisibility::WorldReadable
{
if visibility_content.history_visibility == HistoryVisibility::WorldReadable {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Admin room is not allowed to be made world readable (public room history).",
"Admin room is not allowed to be made world readable (public \
room history).",
));
}
}
@ -233,8 +254,10 @@ async fn allowed_to_send_state_event(
}
},
// TODO: allow alias if it previously existed
StateEventType::RoomCanonicalAlias => {
if let Ok(canonical_alias) = serde_json::from_str::<RoomCanonicalAliasEventContent>(json.json().get()) {
| StateEventType::RoomCanonicalAlias => {
if let Ok(canonical_alias) =
serde_json::from_str::<RoomCanonicalAliasEventContent>(json.json().get())
{
let mut aliases = canonical_alias.alt_aliases.clone();
if let Some(alias) = canonical_alias.alias {
@ -243,7 +266,9 @@ async fn allowed_to_send_state_event(
for alias in aliases {
if !services.globals.server_is_ours(alias.server_name()) {
return Err!(Request(Forbidden("canonical_alias must be for this server")));
return Err!(Request(Forbidden(
"canonical_alias must be for this server"
)));
}
if !services
@ -255,13 +280,14 @@ async fn allowed_to_send_state_event(
// Make sure it's the right room
{
return Err!(Request(Forbidden(
"You are only allowed to send canonical_alias events when its aliases already exist"
"You are only allowed to send canonical_alias events when its \
aliases already exist"
)));
}
}
}
},
_ => (),
| _ => (),
}
Ok(())

View file

@ -12,8 +12,12 @@ pub(crate) use self::{v3::sync_events_route, v4::sync_events_v4_route};
use crate::{service::Services, Error, PduEvent, Result};
async fn load_timeline(
services: &Services, sender_user: &UserId, room_id: &RoomId, roomsincecount: PduCount,
next_batch: Option<PduCount>, limit: usize,
services: &Services,
sender_user: &UserId,
room_id: &RoomId,
roomsincecount: PduCount,
next_batch: Option<PduCount>,
limit: usize,
) -> Result<(Vec<(PduCount, PduEvent)>, bool), Error> {
let last_timeline_count = services
.rooms
@ -51,7 +55,10 @@ async fn load_timeline(
}
async fn share_encrypted_room(
services: &Services, sender_user: &UserId, user_id: &UserId, ignore_room: Option<&RoomId>,
services: &Services,
sender_user: &UserId,
user_id: &UserId,
ignore_room: Option<&RoomId>,
) -> bool {
services
.rooms

View file

@ -32,8 +32,9 @@ use ruma::{
sync::sync_events::{
self,
v3::{
Ephemeral, Filter, GlobalAccountData, InviteState, InvitedRoom, JoinedRoom, LeftRoom, Presence,
RoomAccountData, RoomSummary, Rooms, State as RoomState, Timeline, ToDevice,
Ephemeral, Filter, GlobalAccountData, InviteState, InvitedRoom, JoinedRoom,
LeftRoom, Presence, RoomAccountData, RoomSummary, Rooms, State as RoomState,
Timeline, ToDevice,
},
DeviceLists, UnreadNotificationsCount,
},
@ -107,7 +108,8 @@ type PresenceUpdates = HashMap<OwnedUserId, PresenceEvent>;
)
)]
pub(crate) async fn sync_events_route(
State(services): State<crate::State>, body: Ruma<sync_events::v3::Request>,
State(services): State<crate::State>,
body: Ruma<sync_events::v3::Request>,
) -> Result<sync_events::v3::Response, RumaResponse<UiaaResponse>> {
let (sender_user, sender_device) = body.sender();
@ -127,9 +129,9 @@ pub(crate) async fn sync_events_route(
// Load filter
let filter = match body.body.filter.as_ref() {
None => FilterDefinition::default(),
Some(Filter::FilterDefinition(ref filter)) => filter.clone(),
Some(Filter::FilterId(ref filter_id)) => services
| None => FilterDefinition::default(),
| Some(Filter::FilterDefinition(ref filter)) => filter.clone(),
| Some(Filter::FilterId(ref filter_id)) => services
.users
.get_filter(sender_user, filter_id)
.await
@ -138,11 +140,11 @@ pub(crate) async fn sync_events_route(
// some clients, at least element, seem to require knowledge of redundant
// members for "inline" profiles on the timeline to work properly
let (lazy_load_enabled, lazy_load_send_redundant) = match filter.room.state.lazy_load_options {
LazyLoadOptions::Enabled {
include_redundant_members,
} => (true, include_redundant_members),
LazyLoadOptions::Disabled => (false, cfg!(feature = "element_hacks")),
let (lazy_load_enabled, lazy_load_send_redundant) = match filter.room.state.lazy_load_options
{
| LazyLoadOptions::Enabled { include_redundant_members } =>
(true, include_redundant_members),
| LazyLoadOptions::Disabled => (false, cfg!(feature = "element_hacks")),
};
let full_state = body.body.full_state;
@ -230,9 +232,7 @@ pub(crate) async fn sync_events_route(
}
let invited_room = InvitedRoom {
invite_state: InviteState {
events: invite_state,
},
invite_state: InviteState { events: invite_state },
};
invited_rooms.insert(room_id, invited_room);
@ -268,7 +268,8 @@ pub(crate) async fn sync_events_route(
.count_one_time_keys(sender_user, sender_device);
// Remove all to-device events the device received *last time*
let remove_to_device_events = services
let remove_to_device_events =
services
.users
.remove_to_device_events(sender_user, sender_device, since);
@ -290,7 +291,8 @@ pub(crate) async fn sync_events_route(
.into_iter()
.stream()
.broad_filter_map(|user_id| async move {
let no_shared_encrypted_room = !share_encrypted_room(&services, sender_user, &user_id, None).await;
let no_shared_encrypted_room =
!share_encrypted_room(&services, sender_user, &user_id, None).await;
no_shared_encrypted_room.then_some(user_id)
})
.ready_fold(HashSet::new(), |mut device_list_left, user_id| {
@ -300,9 +302,7 @@ pub(crate) async fn sync_events_route(
.await;
let response = sync_events::v3::Response {
account_data: GlobalAccountData {
events: account_data,
},
account_data: GlobalAccountData { events: account_data },
device_lists: DeviceLists {
changed: device_list_updates.into_iter().collect(),
left: device_list_left.into_iter().collect(),
@ -324,9 +324,7 @@ pub(crate) async fn sync_events_route(
invite: invited_rooms,
knock: BTreeMap::new(), // TODO
},
to_device: ToDevice {
events: to_device_events,
},
to_device: ToDevice { events: to_device_events },
};
// TODO: Retry the endpoint instead of returning
@ -348,7 +346,11 @@ pub(crate) async fn sync_events_route(
}
#[tracing::instrument(name = "presence", level = "debug", skip_all)]
async fn process_presence_updates(services: &Services, since: u64, syncing_user: &UserId) -> PresenceUpdates {
async fn process_presence_updates(
services: &Services,
since: u64,
syncing_user: &UserId,
) -> PresenceUpdates {
services
.presence
.presence_since(since)
@ -367,10 +369,10 @@ async fn process_presence_updates(services: &Services, since: u64, syncing_user:
})
.ready_fold(PresenceUpdates::new(), |mut updates, (user_id, event)| {
match updates.entry(user_id.into()) {
Entry::Vacant(slot) => {
| Entry::Vacant(slot) => {
slot.insert(event);
},
Entry::Occupied(mut slot) => {
| Entry::Occupied(mut slot) => {
let curr_event = slot.get_mut();
let curr_content = &mut curr_event.content;
let new_content = event.content;
@ -380,7 +382,8 @@ async fn process_presence_updates(services: &Services, since: u64, syncing_user:
curr_content.status_msg = new_content
.status_msg
.or_else(|| curr_content.status_msg.take());
curr_content.last_active_ago = new_content.last_active_ago.or(curr_content.last_active_ago);
curr_content.last_active_ago =
new_content.last_active_ago.or(curr_content.last_active_ago);
curr_content.displayname = new_content
.displayname
.or_else(|| curr_content.displayname.take());
@ -410,8 +413,13 @@ async fn process_presence_updates(services: &Services, since: u64, syncing_user:
)]
#[allow(clippy::too_many_arguments)]
async fn handle_left_room(
services: &Services, since: u64, ref room_id: OwnedRoomId, sender_user: &UserId, next_batch_string: &str,
full_state: bool, lazy_load_enabled: bool,
services: &Services,
since: u64,
ref room_id: OwnedRoomId,
sender_user: &UserId,
next_batch_string: &str,
full_state: bool,
lazy_load_enabled: bool,
) -> Result<Option<LeftRoom>> {
// Get and drop the lock to wait for remaining operations to finish
let insert_lock = services.rooms.timeline.mutex_insert.lock(room_id).await;
@ -440,7 +448,8 @@ async fn handle_left_room(
.try_into()
.expect("Timestamp is valid js_int value"),
kind: RoomMember,
content: serde_json::from_str(r#"{"membership":"leave"}"#).expect("this is valid JSON"),
content: serde_json::from_str(r#"{"membership":"leave"}"#)
.expect("this is valid JSON"),
state_key: Some(sender_user.to_string()),
unsigned: None,
// The following keys are dropped on conversion
@ -449,16 +458,12 @@ async fn handle_left_room(
depth: uint!(1),
auth_events: vec![],
redacts: None,
hashes: EventHash {
sha256: String::new(),
},
hashes: EventHash { sha256: String::new() },
signatures: None,
};
return Ok(Some(LeftRoom {
account_data: RoomAccountData {
events: Vec::new(),
},
account_data: RoomAccountData { events: Vec::new() },
timeline: Timeline {
limited: false,
prev_batch: Some(next_batch_string.to_owned()),
@ -479,8 +484,8 @@ async fn handle_left_room(
.await;
let since_state_ids = match since_shortstatehash {
Ok(s) => services.rooms.state_accessor.state_full_ids(s).await?,
Err(_) => HashMap::new(),
| Ok(s) => services.rooms.state_accessor.state_full_ids(s).await?,
| Err(_) => HashMap::new(),
};
let Ok(left_event_id): Result<OwnedEventId> = services
@ -542,17 +547,14 @@ async fn handle_left_room(
}
Ok(Some(LeftRoom {
account_data: RoomAccountData {
events: Vec::new(),
},
account_data: RoomAccountData { events: Vec::new() },
timeline: Timeline {
limited: true, // TODO: support left timeline events so we dont need to set this to true
limited: true, /* TODO: support left timeline events so we dont need to set this to
* true */
prev_batch: Some(next_batch_string.to_owned()),
events: Vec::new(), // and so we dont need to set this to empty vec
},
state: RoomState {
events: left_state_events,
},
state: RoomState { events: left_state_events },
}))
}
@ -566,8 +568,15 @@ async fn handle_left_room(
)]
#[allow(clippy::too_many_arguments)]
async fn load_joined_room(
services: &Services, sender_user: &UserId, sender_device: &DeviceId, ref room_id: OwnedRoomId, since: u64,
next_batch: u64, lazy_load_enabled: bool, lazy_load_send_redundant: bool, full_state: bool,
services: &Services,
sender_user: &UserId,
sender_device: &DeviceId,
ref room_id: OwnedRoomId,
since: u64,
next_batch: u64,
lazy_load_enabled: bool,
lazy_load_send_redundant: bool,
full_state: bool,
) -> Result<(JoinedRoom, HashSet<OwnedUserId>, HashSet<OwnedUserId>)> {
// Get and drop the lock to wait for remaining operations to finish
// This will make sure the we have all events until next_batch
@ -590,13 +599,21 @@ async fn load_joined_room(
.ok()
.map(Ok);
let timeline = load_timeline(services, sender_user, room_id, sincecount, Some(next_batchcount), 10_usize);
let timeline = load_timeline(
services,
sender_user,
room_id,
sincecount,
Some(next_batchcount),
10_usize,
);
let (current_shortstatehash, since_shortstatehash, timeline) =
try_join3(current_shortstatehash, since_shortstatehash, timeline).await?;
let (timeline_pdus, limited) = timeline;
let timeline_users = timeline_pdus
let timeline_users =
timeline_pdus
.iter()
.fold(HashSet::new(), |mut timeline_users, (_, event)| {
timeline_users.insert(event.sender.as_str().to_owned());
@ -617,13 +634,16 @@ async fn load_joined_room(
.is_none_or(|&count| count > since)
.await;
services
.rooms
.lazy_loading
.lazy_load_confirm_delivery(sender_user, sender_device, room_id, sincecount);
services.rooms.lazy_loading.lazy_load_confirm_delivery(
sender_user,
sender_device,
room_id,
sincecount,
);
let no_state_changes = timeline_pdus.is_empty()
&& (since_shortstatehash.is_none() || since_shortstatehash.is_some_and(is_equal_to!(current_shortstatehash)));
&& (since_shortstatehash.is_none()
|| since_shortstatehash.is_some_and(is_equal_to!(current_shortstatehash)));
let mut device_list_updates = HashSet::<OwnedUserId>::new();
let mut left_encrypted_users = HashSet::<OwnedUserId>::new();
@ -732,7 +752,8 @@ async fn load_joined_room(
let events = join4(room_events, account_data_events, receipt_events, typing_events);
let unread_notifications = join(notification_count, highlight_count);
let (unread_notifications, events, device_updates) = join3(unread_notifications, events, device_updates)
let (unread_notifications, events, device_updates) =
join3(unread_notifications, events, device_updates)
.boxed()
.await;
@ -773,9 +794,7 @@ async fn load_joined_room(
.await;
let joined_room = JoinedRoom {
account_data: RoomAccountData {
events: account_data_events,
},
account_data: RoomAccountData { events: account_data_events },
summary: RoomSummary {
joined_member_count: joined_member_count.map(ruma_from_u64),
invited_member_count: invited_member_count.map(ruma_from_u64),
@ -786,10 +805,7 @@ async fn load_joined_room(
.filter_map(Result::ok)
.collect(),
},
unread_notifications: UnreadNotificationsCount {
highlight_count,
notification_count,
},
unread_notifications: UnreadNotificationsCount { highlight_count, notification_count },
timeline: Timeline {
limited: limited || joined_since_last_sync,
events: room_events,
@ -805,9 +821,7 @@ async fn load_joined_room(
.map(PduEvent::to_sync_state_event)
.collect(),
},
ephemeral: Ephemeral {
events: edus,
},
ephemeral: Ephemeral { events: edus },
unread_thread_notifications: BTreeMap::new(),
};
@ -827,11 +841,20 @@ async fn load_joined_room(
)]
#[allow(clippy::too_many_arguments)]
async fn calculate_state_changes(
services: &Services, sender_user: &UserId, sender_device: &DeviceId, room_id: &RoomId, next_batchcount: PduCount,
lazy_load_enabled: bool, lazy_load_send_redundant: bool, full_state: bool,
device_list_updates: &mut HashSet<OwnedUserId>, left_encrypted_users: &mut HashSet<OwnedUserId>,
since_shortstatehash: Option<ShortStateHash>, current_shortstatehash: ShortStateHash,
timeline_pdus: &Vec<(PduCount, PduEvent)>, timeline_users: &HashSet<String>,
services: &Services,
sender_user: &UserId,
sender_device: &DeviceId,
room_id: &RoomId,
next_batchcount: PduCount,
lazy_load_enabled: bool,
lazy_load_send_redundant: bool,
full_state: bool,
device_list_updates: &mut HashSet<OwnedUserId>,
left_encrypted_users: &mut HashSet<OwnedUserId>,
since_shortstatehash: Option<ShortStateHash>,
current_shortstatehash: ShortStateHash,
timeline_pdus: &Vec<(PduCount, PduEvent)>,
timeline_users: &HashSet<String>,
) -> Result<StateChanges> {
let since_sender_member: OptionFuture<_> = since_shortstatehash
.map(|short| {
@ -843,10 +866,11 @@ async fn calculate_state_changes(
})
.into();
let joined_since_last_sync = since_sender_member
let joined_since_last_sync =
since_sender_member
.await
.flatten()
.map_or(true, |content: RoomMemberEventContent| {
.is_none_or(|content: RoomMemberEventContent| {
content.membership != MembershipState::Join
});
@ -886,8 +910,14 @@ async fn calculate_state_changes(
#[tracing::instrument(name = "initial", level = "trace", skip_all)]
#[allow(clippy::too_many_arguments)]
async fn calculate_state_initial(
services: &Services, sender_user: &UserId, sender_device: &DeviceId, room_id: &RoomId, next_batchcount: PduCount,
lazy_load_enabled: bool, full_state: bool, current_shortstatehash: ShortStateHash,
services: &Services,
sender_user: &UserId,
sender_device: &DeviceId,
room_id: &RoomId,
next_batchcount: PduCount,
lazy_load_enabled: bool,
full_state: bool,
current_shortstatehash: ShortStateHash,
timeline_users: &HashSet<String>,
) -> Result<StateChanges> {
// Probably since = 0, we will do an initial sync
@ -956,10 +986,13 @@ async fn calculate_state_initial(
// The state_events above should contain all timeline_users, let's mark them as
// lazy loaded.
services
.rooms
.lazy_loading
.lazy_load_mark_sent(sender_user, sender_device, room_id, lazy_loaded, next_batchcount);
services.rooms.lazy_loading.lazy_load_mark_sent(
sender_user,
sender_device,
room_id,
lazy_loaded,
next_batchcount,
);
Ok(StateChanges {
heroes,
@ -973,13 +1006,23 @@ async fn calculate_state_initial(
#[tracing::instrument(name = "incremental", level = "trace", skip_all)]
#[allow(clippy::too_many_arguments)]
async fn calculate_state_incremental(
services: &Services, sender_user: &UserId, sender_device: &DeviceId, room_id: &RoomId, next_batchcount: PduCount,
lazy_load_send_redundant: bool, full_state: bool, device_list_updates: &mut HashSet<OwnedUserId>,
left_encrypted_users: &mut HashSet<OwnedUserId>, since_shortstatehash: Option<ShortStateHash>,
current_shortstatehash: ShortStateHash, timeline_pdus: &Vec<(PduCount, PduEvent)>, joined_since_last_sync: bool,
services: &Services,
sender_user: &UserId,
sender_device: &DeviceId,
room_id: &RoomId,
next_batchcount: PduCount,
lazy_load_send_redundant: bool,
full_state: bool,
device_list_updates: &mut HashSet<OwnedUserId>,
left_encrypted_users: &mut HashSet<OwnedUserId>,
since_shortstatehash: Option<ShortStateHash>,
current_shortstatehash: ShortStateHash,
timeline_pdus: &Vec<(PduCount, PduEvent)>,
joined_since_last_sync: bool,
) -> Result<StateChanges> {
// Incremental /sync
let since_shortstatehash = since_shortstatehash.expect("missing since_shortstatehash on incremental sync");
let since_shortstatehash =
since_shortstatehash.expect("missing since_shortstatehash on incremental sync");
let mut delta_state_events = Vec::new();
@ -994,8 +1037,10 @@ async fn calculate_state_incremental(
.state_accessor
.state_full_ids(since_shortstatehash);
let (current_state_ids, since_state_ids): (HashMap<_, OwnedEventId>, HashMap<_, OwnedEventId>) =
try_join(current_state_ids, since_state_ids).await?;
let (current_state_ids, since_state_ids): (
HashMap<_, OwnedEventId>,
HashMap<_, OwnedEventId>,
) = try_join(current_state_ids, since_state_ids).await?;
current_state_ids
.iter()
@ -1044,17 +1089,19 @@ async fn calculate_state_incremental(
let content: RoomMemberEventContent = state_event.get_content()?;
match content.membership {
MembershipState::Join => {
| MembershipState::Join => {
// A new user joined an encrypted room
if !share_encrypted_room(services, sender_user, &user_id, Some(room_id)).await {
if !share_encrypted_room(services, sender_user, &user_id, Some(room_id))
.await
{
device_list_updates.insert(user_id);
}
},
MembershipState::Leave => {
| MembershipState::Leave => {
// Write down users that have left encrypted rooms we are in
left_encrypted_users.insert(user_id);
},
_ => {},
| _ => {},
}
}
}
@ -1139,10 +1186,13 @@ async fn calculate_state_incremental(
state_events.push(member_event);
}
services
.rooms
.lazy_loading
.lazy_load_mark_sent(sender_user, sender_device, room_id, lazy_loaded, next_batchcount);
services.rooms.lazy_loading.lazy_load_mark_sent(
sender_user,
sender_device,
room_id,
lazy_loaded,
next_batchcount,
);
Ok(StateChanges {
heroes,
@ -1154,7 +1204,9 @@ async fn calculate_state_incremental(
}
async fn calculate_counts(
services: &Services, room_id: &RoomId, sender_user: &UserId,
services: &Services,
room_id: &RoomId,
sender_user: &UserId,
) -> Result<(Option<u64>, Option<u64>, Option<Vec<OwnedUserId>>)> {
let joined_member_count = services
.rooms
@ -1168,7 +1220,8 @@ async fn calculate_counts(
.room_invited_count(room_id)
.unwrap_or(0);
let (joined_member_count, invited_member_count) = join(joined_member_count, invited_member_count).await;
let (joined_member_count, invited_member_count) =
join(joined_member_count, invited_member_count).await;
let small_room = joined_member_count.saturating_add(invited_member_count) > 5;
@ -1179,20 +1232,32 @@ async fn calculate_counts(
Ok((Some(joined_member_count), Some(invited_member_count), heroes.await))
}
async fn calculate_heroes(services: &Services, room_id: &RoomId, sender_user: &UserId) -> Vec<OwnedUserId> {
async fn calculate_heroes(
services: &Services,
room_id: &RoomId,
sender_user: &UserId,
) -> Vec<OwnedUserId> {
services
.rooms
.timeline
.all_pdus(sender_user, room_id)
.ready_filter(|(_, pdu)| pdu.kind == RoomMember)
.fold_default(|heroes: Vec<_>, (_, pdu)| fold_hero(heroes, services, room_id, sender_user, pdu))
.fold_default(|heroes: Vec<_>, (_, pdu)| {
fold_hero(heroes, services, room_id, sender_user, pdu)
})
.await
}
async fn fold_hero(
mut heroes: Vec<OwnedUserId>, services: &Services, room_id: &RoomId, sender_user: &UserId, pdu: PduEvent,
mut heroes: Vec<OwnedUserId>,
services: &Services,
room_id: &RoomId,
sender_user: &UserId,
pdu: PduEvent,
) -> Vec<OwnedUserId> {
let Some(user_id): Option<&UserId> = pdu.state_key.as_deref().map(TryInto::try_into).flat_ok() else {
let Some(user_id): Option<&UserId> =
pdu.state_key.as_deref().map(TryInto::try_into).flat_ok()
else {
return heroes;
};

View file

@ -46,7 +46,8 @@ const DEFAULT_BUMP_TYPES: &[TimelineEventType; 6] =
///
/// Sliding Sync endpoint (future endpoint: `/_matrix/client/v4/sync`)
pub(crate) async fn sync_events_v4_route(
State(services): State<crate::State>, body: Ruma<sync_events::v4::Request>,
State(services): State<crate::State>,
body: Ruma<sync_events::v4::Request>,
) -> Result<sync_events::v4::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_device = body.sender_device.expect("user is authenticated");
@ -81,16 +82,19 @@ pub(crate) async fn sync_events_v4_route(
}
if globalsince == 0 {
services
.sync
.forget_sync_request_connection(sender_user.clone(), sender_device.clone(), conn_id.clone());
services.sync.forget_sync_request_connection(
sender_user.clone(),
sender_device.clone(),
conn_id.clone(),
);
}
// Get sticky parameters from cache
let known_rooms =
services
.sync
.update_sync_request_with_cache(sender_user.clone(), sender_device.clone(), &mut body);
let known_rooms = services.sync.update_sync_request_with_cache(
sender_user.clone(),
sender_device.clone(),
&mut body,
);
let all_joined_rooms: Vec<_> = services
.rooms
@ -125,9 +129,7 @@ pub(crate) async fn sync_events_v4_route(
let mut device_list_changes = HashSet::new();
let mut device_list_left = HashSet::new();
let mut receipts = sync_events::v4::Receipts {
rooms: BTreeMap::new(),
};
let mut receipts = sync_events::v4::Receipts { rooms: BTreeMap::new() };
let mut account_data = sync_events::v4::AccountData {
global: Vec::new(),
@ -168,7 +170,9 @@ pub(crate) async fn sync_events_v4_route(
);
for room_id in &all_joined_rooms {
let Ok(current_shortstatehash) = services.rooms.state.get_room_shortstatehash(room_id).await else {
let Ok(current_shortstatehash) =
services.rooms.state.get_room_shortstatehash(room_id).await
else {
error!("Room {room_id} has no state");
continue;
};
@ -202,12 +206,17 @@ pub(crate) async fn sync_events_v4_route(
let since_sender_member: Option<RoomMemberEventContent> = services
.rooms
.state_accessor
.state_get_content(since_shortstatehash, &StateEventType::RoomMember, sender_user.as_str())
.state_get_content(
since_shortstatehash,
&StateEventType::RoomMember,
sender_user.as_str(),
)
.ok()
.await;
let joined_since_last_sync =
since_sender_member.map_or(true, |member| member.membership != MembershipState::Join);
let joined_since_last_sync = since_sender_member
.as_ref()
.is_none_or(|member| member.membership != MembershipState::Join);
let new_encrypted_room = encrypted_room && since_encryption.is_err();
@ -232,8 +241,10 @@ pub(crate) async fn sync_events_v4_route(
};
if pdu.kind == RoomMember {
if let Some(state_key) = &pdu.state_key {
let user_id = UserId::parse(state_key.clone())
.map_err(|_| Error::bad_database("Invalid UserId in member PDU."))?;
let user_id =
UserId::parse(state_key.clone()).map_err(|_| {
Error::bad_database("Invalid UserId in member PDU.")
})?;
if user_id == *sender_user {
continue;
@ -241,19 +252,25 @@ pub(crate) async fn sync_events_v4_route(
let content: RoomMemberEventContent = pdu.get_content()?;
match content.membership {
MembershipState::Join => {
| MembershipState::Join => {
// A new user joined an encrypted room
if !share_encrypted_room(&services, sender_user, &user_id, Some(room_id))
if !share_encrypted_room(
&services,
sender_user,
&user_id,
Some(room_id),
)
.await
{
device_list_changes.insert(user_id);
}
},
MembershipState::Leave => {
// Write down users that have left encrypted rooms we are in
| MembershipState::Leave => {
// Write down users that have left encrypted rooms we
// are in
left_encrypted_users.insert(user_id);
},
_ => {},
| _ => {},
}
}
}
@ -293,7 +310,8 @@ pub(crate) async fn sync_events_v4_route(
}
for user_id in left_encrypted_users {
let dont_share_encrypted_room = !share_encrypted_room(&services, sender_user, &user_id, None).await;
let dont_share_encrypted_room =
!share_encrypted_room(&services, sender_user, &user_id, None).await;
// If the user doesn't share an encrypted room with the target anymore, we need
// to tell them
@ -308,29 +326,27 @@ pub(crate) async fn sync_events_v4_route(
for (list_id, list) in &body.lists {
let active_rooms = match list.filters.clone().and_then(|f| f.is_invite) {
Some(true) => &all_invited_rooms,
Some(false) => &all_joined_rooms,
None => &all_rooms,
| Some(true) => &all_invited_rooms,
| Some(false) => &all_joined_rooms,
| None => &all_rooms,
};
let active_rooms = match list.filters.clone().map(|f| f.not_room_types) {
Some(filter) if filter.is_empty() => active_rooms.clone(),
Some(value) => filter_rooms(&services, active_rooms, &value, true).await,
None => active_rooms.clone(),
| Some(filter) if filter.is_empty() => active_rooms.clone(),
| Some(value) => filter_rooms(&services, active_rooms, &value, true).await,
| None => active_rooms.clone(),
};
let active_rooms = match list.filters.clone().map(|f| f.room_types) {
Some(filter) if filter.is_empty() => active_rooms.clone(),
Some(value) => filter_rooms(&services, &active_rooms, &value, false).await,
None => active_rooms,
| Some(filter) if filter.is_empty() => active_rooms.clone(),
| Some(value) => filter_rooms(&services, &active_rooms, &value, false).await,
| None => active_rooms,
};
let mut new_known_rooms = BTreeSet::new();
let ranges = list.ranges.clone();
lists.insert(
list_id.clone(),
sync_events::v4::SyncList {
lists.insert(list_id.clone(), sync_events::v4::SyncList {
ops: ranges
.into_iter()
.map(|mut r| {
@ -338,8 +354,10 @@ pub(crate) async fn sync_events_v4_route(
uint!(0),
UInt::try_from(active_rooms.len().saturating_sub(1)).unwrap_or(UInt::MAX),
);
r.1 =
r.1.clamp(r.0, UInt::try_from(active_rooms.len().saturating_sub(1)).unwrap_or(UInt::MAX));
r.1 = r.1.clamp(
r.0,
UInt::try_from(active_rooms.len().saturating_sub(1)).unwrap_or(UInt::MAX),
);
let room_ids = if !active_rooms.is_empty() {
active_rooms[usize_from_ruma(r.0)..=usize_from_ruma(r.1)].to_vec()
@ -349,10 +367,11 @@ pub(crate) async fn sync_events_v4_route(
new_known_rooms.extend(room_ids.iter().cloned());
for room_id in &room_ids {
let todo_room =
todo_rooms
.entry(room_id.clone())
.or_insert((BTreeSet::new(), 0_usize, u64::MAX));
let todo_room = todo_rooms.entry(room_id.clone()).or_insert((
BTreeSet::new(),
0_usize,
u64::MAX,
));
let limit: usize = list
.room_details
@ -385,8 +404,7 @@ pub(crate) async fn sync_events_v4_route(
})
.collect(),
count: ruma_from_usize(active_rooms.len()),
},
);
});
if let Some(conn_id) = &body.conn_id {
services.sync.update_sync_known_rooms(
@ -405,7 +423,8 @@ pub(crate) async fn sync_events_v4_route(
if !services.rooms.metadata.exists(room_id).await {
continue;
}
let todo_room = todo_rooms
let todo_room =
todo_rooms
.entry(room_id.clone())
.or_insert((BTreeSet::new(), 0_usize, u64::MAX));
@ -471,10 +490,18 @@ pub(crate) async fn sync_events_v4_route(
(timeline_pdus, limited) = (Vec::new(), true);
} else {
(timeline_pdus, limited) =
match load_timeline(&services, sender_user, room_id, roomsincecount, None, *timeline_limit).await {
Ok(value) => value,
Err(err) => {
(timeline_pdus, limited) = match load_timeline(
&services,
sender_user,
room_id,
roomsincecount,
None,
*timeline_limit,
)
.await
{
| Ok(value) => value,
| Err(err) => {
warn!("Encountered missing timeline in {}, error {}", room_id, err);
continue;
},
@ -543,11 +570,11 @@ pub(crate) async fn sync_events_v4_route(
.first()
.map_or(Ok::<_, Error>(None), |(pdu_count, _)| {
Ok(Some(match pdu_count {
PduCount::Backfilled(_) => {
| PduCount::Backfilled(_) => {
error!("timeline in backfill state?!");
"0".to_owned()
},
PduCount::Normal(c) => c.to_string(),
| PduCount::Normal(c) => c.to_string(),
}))
})?
.or_else(|| {
@ -568,7 +595,9 @@ pub(crate) async fn sync_events_v4_route(
for (_, pdu) in timeline_pdus {
let ts = MilliSecondsSinceUnixEpoch(pdu.origin_server_ts);
if DEFAULT_BUMP_TYPES.contains(pdu.event_type()) && timestamp.is_none_or(|time| time <= ts) {
if DEFAULT_BUMP_TYPES.contains(pdu.event_type())
&& timestamp.is_none_or(|time| time <= ts)
{
timestamp = Some(ts);
}
}
@ -611,7 +640,7 @@ pub(crate) async fn sync_events_v4_route(
.await;
let name = match heroes.len().cmp(&(1_usize)) {
Ordering::Greater => {
| Ordering::Greater => {
let firsts = heroes[1..]
.iter()
.map(|h| h.name.clone().unwrap_or_else(|| h.user_id.to_string()))
@ -625,13 +654,13 @@ pub(crate) async fn sync_events_v4_route(
Some(format!("{firsts} and {last}"))
},
Ordering::Equal => Some(
| Ordering::Equal => Some(
heroes[0]
.name
.clone()
.unwrap_or_else(|| heroes[0].user_id.to_string()),
),
Ordering::Less => None,
| Ordering::Less => None,
};
let heroes_avatar = if heroes.len() == 1 {
@ -640,9 +669,7 @@ pub(crate) async fn sync_events_v4_route(
None
};
rooms.insert(
room_id.clone(),
sync_events::v4::SlidingSyncRoom {
rooms.insert(room_id.clone(), sync_events::v4::SlidingSyncRoom {
name: services
.rooms
.state_accessor
@ -654,9 +681,9 @@ pub(crate) async fn sync_events_v4_route(
ruma::JsOption::Some(heroes_avatar)
} else {
match services.rooms.state_accessor.get_avatar(room_id).await {
ruma::JsOption::Some(avatar) => ruma::JsOption::from_option(avatar.url),
ruma::JsOption::Null => ruma::JsOption::Null,
ruma::JsOption::Undefined => ruma::JsOption::Undefined,
| ruma::JsOption::Some(avatar) => ruma::JsOption::from_option(avatar.url),
| ruma::JsOption::Null => ruma::JsOption::Null,
| ruma::JsOption::Undefined => ruma::JsOption::Undefined,
}
},
initial: Some(roomsince == &0),
@ -709,8 +736,7 @@ pub(crate) async fn sync_events_v4_route(
num_live: None, // Count events in timeline greater than global sync counter
timestamp,
heroes: Some(heroes),
},
);
});
}
if rooms
@ -757,16 +783,17 @@ pub(crate) async fn sync_events_v4_route(
},
account_data,
receipts,
typing: sync_events::v4::Typing {
rooms: BTreeMap::new(),
},
typing: sync_events::v4::Typing { rooms: BTreeMap::new() },
},
delta_token: None,
})
}
async fn filter_rooms(
services: &Services, rooms: &[OwnedRoomId], filter: &[RoomTypeFilter], negate: bool,
services: &Services,
rooms: &[OwnedRoomId],
filter: &[RoomTypeFilter],
negate: bool,
) -> Vec<OwnedRoomId> {
rooms
.iter()

View file

@ -17,7 +17,8 @@ use crate::{Result, Ruma};
///
/// - Inserts the tag into the tag event of the room account data.
pub(crate) async fn update_tag_route(
State(services): State<crate::State>, body: Ruma<create_tag::v3::Request>,
State(services): State<crate::State>,
body: Ruma<create_tag::v3::Request>,
) -> Result<create_tag::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -26,9 +27,7 @@ pub(crate) async fn update_tag_route(
.get_room(&body.room_id, sender_user, RoomAccountDataEventType::Tag)
.await
.unwrap_or(TagEvent {
content: TagEventContent {
tags: BTreeMap::new(),
},
content: TagEventContent { tags: BTreeMap::new() },
});
tags_event
@ -55,7 +54,8 @@ pub(crate) async fn update_tag_route(
///
/// - Removes the tag from the tag event of the room account data.
pub(crate) async fn delete_tag_route(
State(services): State<crate::State>, body: Ruma<delete_tag::v3::Request>,
State(services): State<crate::State>,
body: Ruma<delete_tag::v3::Request>,
) -> Result<delete_tag::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -64,9 +64,7 @@ pub(crate) async fn delete_tag_route(
.get_room(&body.room_id, sender_user, RoomAccountDataEventType::Tag)
.await
.unwrap_or(TagEvent {
content: TagEventContent {
tags: BTreeMap::new(),
},
content: TagEventContent { tags: BTreeMap::new() },
});
tags_event.content.tags.remove(&body.tag.clone().into());
@ -90,7 +88,8 @@ pub(crate) async fn delete_tag_route(
///
/// - Gets the tag event of the room account data.
pub(crate) async fn get_tags_route(
State(services): State<crate::State>, body: Ruma<get_tags::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_tags::v3::Request>,
) -> Result<get_tags::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -99,12 +98,8 @@ pub(crate) async fn get_tags_route(
.get_room(&body.room_id, sender_user, RoomAccountDataEventType::Tag)
.await
.unwrap_or(TagEvent {
content: TagEventContent {
tags: BTreeMap::new(),
},
content: TagEventContent { tags: BTreeMap::new() },
});
Ok(get_tags::v3::Response {
tags: tags_event.content.tags,
})
Ok(get_tags::v3::Response { tags: tags_event.content.tags })
}

View file

@ -11,9 +11,7 @@ pub(crate) async fn get_protocols_route(
_body: Ruma<get_protocols::v3::Request>,
) -> Result<get_protocols::v3::Response> {
// TODO
Ok(get_protocols::v3::Response {
protocols: BTreeMap::new(),
})
Ok(get_protocols::v3::Response { protocols: BTreeMap::new() })
}
/// # `GET /_matrix/client/unstable/thirdparty/protocols`

View file

@ -7,7 +7,8 @@ use crate::{Result, Ruma};
/// # `GET /_matrix/client/r0/rooms/{roomId}/threads`
pub(crate) async fn get_threads_route(
State(services): State<crate::State>, ref body: Ruma<get_threads::v1::Request>,
State(services): State<crate::State>,
ref body: Ruma<get_threads::v1::Request>,
) -> Result<get_threads::v1::Response> {
// Use limit or else 10, with maximum 100
let limit = body

View file

@ -17,7 +17,8 @@ use crate::Ruma;
///
/// Send a to-device event to a set of client devices.
pub(crate) async fn send_event_to_device_route(
State(services): State<crate::State>, body: Ruma<send_event_to_device::v3::Request>,
State(services): State<crate::State>,
body: Ruma<send_event_to_device::v3::Request>,
) -> Result<send_event_to_device::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_device = body.sender_device.as_deref();
@ -43,12 +44,14 @@ pub(crate) async fn send_event_to_device_route(
services.sending.send_edu_server(
target_user_id.server_name(),
serde_json::to_vec(&federation::transactions::edu::Edu::DirectToDevice(DirectDeviceContent {
serde_json::to_vec(&federation::transactions::edu::Edu::DirectToDevice(
DirectDeviceContent {
sender: sender_user.clone(),
ev_type: body.event_type.clone(),
message_id: count.to_string().into(),
messages,
}))
},
))
.expect("DirectToDevice EDU can be serialized"),
)?;
@ -62,14 +65,20 @@ pub(crate) async fn send_event_to_device_route(
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid"))?;
match target_device_id_maybe {
DeviceIdOrAllDevices::DeviceId(target_device_id) => {
| DeviceIdOrAllDevices::DeviceId(target_device_id) => {
services
.users
.add_to_device_event(sender_user, target_user_id, target_device_id, event_type, event)
.add_to_device_event(
sender_user,
target_user_id,
target_device_id,
event_type,
event,
)
.await;
},
DeviceIdOrAllDevices::AllDevices => {
| DeviceIdOrAllDevices::AllDevices => {
let (event_type, event) = (&event_type, &event);
services
.users

View file

@ -7,7 +7,8 @@ use crate::{utils, Error, Result, Ruma};
///
/// Sets the typing state of the sender user.
pub(crate) async fn create_typing_event_route(
State(services): State<crate::State>, body: Ruma<create_typing_event::v3::Request>,
State(services): State<crate::State>,
body: Ruma<create_typing_event::v3::Request>,
) -> Result<create_typing_event::v3::Response> {
use create_typing_event::v3::Typing;

View file

@ -10,8 +10,8 @@ use ruma::{
error::ErrorKind,
membership::mutual_rooms,
profile::{
delete_profile_key, delete_timezone_key, get_profile_key, get_timezone_key, set_profile_key,
set_timezone_key,
delete_profile_key, delete_timezone_key, get_profile_key, get_timezone_key,
set_profile_key, set_timezone_key,
},
room::get_summary,
},
@ -34,7 +34,8 @@ use crate::{Error, Result, Ruma, RumaResponse};
/// An implementation of [MSC2666](https://github.com/matrix-org/matrix-spec-proposals/pull/2666)
#[tracing::instrument(skip_all, fields(%client), name = "mutual_rooms")]
pub(crate) async fn get_mutual_rooms_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<mutual_rooms::unstable::Request>,
) -> Result<mutual_rooms::unstable::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -47,10 +48,7 @@ pub(crate) async fn get_mutual_rooms_route(
}
if !services.users.exists(&body.user_id).await {
return Ok(mutual_rooms::unstable::Response {
joined: vec![],
next_batch_token: None,
});
return Ok(mutual_rooms::unstable::Response { joined: vec![], next_batch_token: None });
}
let mutual_rooms: Vec<OwnedRoomId> = services
@ -77,7 +75,8 @@ pub(crate) async fn get_mutual_rooms_route(
///
/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266)
pub(crate) async fn get_room_summary_legacy(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_summary::msc3266::Request>,
) -> Result<RumaResponse<get_summary::msc3266::Response>> {
get_room_summary(State(services), InsecureClientIp(client), body)
@ -94,7 +93,8 @@ pub(crate) async fn get_room_summary_legacy(
/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266)
#[tracing::instrument(skip_all, fields(%client), name = "room_summary")]
pub(crate) async fn get_room_summary(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_summary::msc3266::Request>,
) -> Result<get_summary::msc3266::Response> {
let sender_user = body.sender_user.as_ref();
@ -194,7 +194,8 @@ pub(crate) async fn get_room_summary(
///
/// - Also makes sure other users receive the update using presence EDUs
pub(crate) async fn delete_timezone_key_route(
State(services): State<crate::State>, body: Ruma<delete_timezone_key::unstable::Request>,
State(services): State<crate::State>,
body: Ruma<delete_timezone_key::unstable::Request>,
) -> Result<delete_timezone_key::unstable::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -221,7 +222,8 @@ pub(crate) async fn delete_timezone_key_route(
///
/// - Also makes sure other users receive the update using presence EDUs
pub(crate) async fn set_timezone_key_route(
State(services): State<crate::State>, body: Ruma<set_timezone_key::unstable::Request>,
State(services): State<crate::State>,
body: Ruma<set_timezone_key::unstable::Request>,
) -> Result<set_timezone_key::unstable::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -248,7 +250,8 @@ pub(crate) async fn set_timezone_key_route(
///
/// This also handles the avatar_url and displayname being updated.
pub(crate) async fn set_profile_key_route(
State(services): State<crate::State>, body: Ruma<set_profile_key::unstable::Request>,
State(services): State<crate::State>,
body: Ruma<set_profile_key::unstable::Request>,
) -> Result<set_profile_key::unstable::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -264,7 +267,9 @@ pub(crate) async fn set_profile_key_route(
if body.kv_pair.len() > 1 {
// TODO: support PATCH or "recursively" adding keys in some sort
return Err!(Request(BadJson("This endpoint can only take one key-value pair at a time")));
return Err!(Request(BadJson(
"This endpoint can only take one key-value pair at a time"
)));
}
let Some(profile_key_value) = body.kv_pair.get(&body.key) else {
@ -294,7 +299,13 @@ pub(crate) async fn set_profile_key_route(
.collect()
.await;
update_displayname(&services, &body.user_id, Some(profile_key_value.to_string()), &all_joined_rooms).await;
update_displayname(
&services,
&body.user_id,
Some(profile_key_value.to_string()),
&all_joined_rooms,
)
.await;
} else if body.key == "avatar_url" {
let mxc = ruma::OwnedMxcUri::from(profile_key_value.to_string());
@ -330,7 +341,8 @@ pub(crate) async fn set_profile_key_route(
///
/// This also handles the avatar_url and displayname being updated.
pub(crate) async fn delete_profile_key_route(
State(services): State<crate::State>, body: Ruma<delete_profile_key::unstable::Request>,
State(services): State<crate::State>,
body: Ruma<delete_profile_key::unstable::Request>,
) -> Result<delete_profile_key::unstable::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@ -340,7 +352,9 @@ pub(crate) async fn delete_profile_key_route(
if body.kv_pair.len() > 1 {
// TODO: support PATCH or "recursively" adding keys in some sort
return Err!(Request(BadJson("This endpoint can only take one key-value pair at a time")));
return Err!(Request(BadJson(
"This endpoint can only take one key-value pair at a time"
)));
}
if body.key == "displayname" {
@ -387,7 +401,8 @@ pub(crate) async fn delete_profile_key_route(
/// - If user is on another server and we do not have a local copy already fetch
/// `timezone` over federation
pub(crate) async fn get_timezone_key_route(
State(services): State<crate::State>, body: Ruma<get_timezone_key::unstable::Request>,
State(services): State<crate::State>,
body: Ruma<get_timezone_key::unstable::Request>,
) -> Result<get_timezone_key::unstable::Response> {
if !services.globals.user_is_local(&body.user_id) {
// Create and update our local copy of the user
@ -422,9 +437,7 @@ pub(crate) async fn get_timezone_key_route(
.users
.set_timezone(&body.user_id, response.tz.clone());
return Ok(get_timezone_key::unstable::Response {
tz: response.tz,
});
return Ok(get_timezone_key::unstable::Response { tz: response.tz });
}
}
@ -446,7 +459,8 @@ pub(crate) async fn get_timezone_key_route(
/// - If user is on another server and we do not have a local copy already fetch
/// `timezone` over federation
pub(crate) async fn get_profile_key_route(
State(services): State<crate::State>, body: Ruma<get_profile_key::unstable::Request>,
State(services): State<crate::State>,
body: Ruma<get_profile_key::unstable::Request>,
) -> Result<get_profile_key::unstable::Response> {
let mut profile_key_value: BTreeMap<String, serde_json::Value> = BTreeMap::new();
@ -492,9 +506,7 @@ pub(crate) async fn get_profile_key_route(
return Err!(Request(NotFound("The requested profile key does not exist.")));
}
return Ok(get_profile_key::unstable::Response {
value: profile_key_value,
});
return Ok(get_profile_key::unstable::Response { value: profile_key_value });
}
}
@ -510,7 +522,5 @@ pub(crate) async fn get_profile_key_route(
return Err!(Request(NotFound("The requested profile key does not exist.")));
}
Ok(get_profile_key::unstable::Response {
value: profile_key_value,
})
Ok(get_profile_key::unstable::Response { value: profile_key_value })
}

View file

@ -74,7 +74,9 @@ pub(crate) async fn conduwuit_server_version() -> Result<impl IntoResponse> {
/// conduwuit-specific API to return the amount of users registered on this
/// homeserver. Endpoint is disabled if federation is disabled for privacy. This
/// only includes active users (not deactivated, no guests, etc)
pub(crate) async fn conduwuit_local_user_count(State(services): State<crate::State>) -> Result<impl IntoResponse> {
pub(crate) async fn conduwuit_local_user_count(
State(services): State<crate::State>,
) -> Result<impl IntoResponse> {
let user_count = services.users.list_local_users().count().await;
Ok(Json(serde_json::json!({

View file

@ -18,7 +18,8 @@ use crate::{Result, Ruma};
/// - Hides any local users that aren't in any public rooms (i.e. those that
/// have the join rule set to public) and don't share a room with the sender
pub(crate) async fn search_users_route(
State(services): State<crate::State>, body: Ruma<search_users::v3::Request>,
State(services): State<crate::State>,
body: Ruma<search_users::v3::Request>,
) -> Result<search_users::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let limit = usize::try_from(body.limit).map_or(10, usize::from).min(100); // default limit is 10
@ -61,7 +62,11 @@ pub(crate) async fn search_users_route(
services
.rooms
.state_accessor
.room_state_get_content::<RoomJoinRulesEventContent>(room, &StateEventType::RoomJoinRules, "")
.room_state_get_content::<RoomJoinRulesEventContent>(
room,
&StateEventType::RoomJoinRules,
"",
)
.map_ok_or(false, |content| content.join_rule == JoinRule::Public)
})
.await;
@ -89,8 +94,5 @@ pub(crate) async fn search_users_route(
let results = users.take(limit).collect().await;
Ok(search_users::v3::Response {
results,
limited,
})
Ok(search_users::v3::Response { results, limited })
}

View file

@ -17,7 +17,8 @@ type HmacSha1 = Hmac<Sha1>;
///
/// TODO: Returns information about the recommended turn server.
pub(crate) async fn turn_server_route(
State(services): State<crate::State>, body: Ruma<get_turn_server_info::v3::Request>,
State(services): State<crate::State>,
body: Ruma<get_turn_server_info::v3::Request>,
) -> Result<get_turn_server_info::v3::Response> {
// MSC4166: return M_NOT_FOUND 404 if no TURN URIs are specified in any way
if services.server.config.turn_uris.is_empty() {
@ -44,7 +45,8 @@ pub(crate) async fn turn_server_route(
let username: String = format!("{}:{}", expiry.get(), user);
let mut mac = HmacSha1::new_from_slice(turn_secret.as_bytes()).expect("HMAC can take key of any size");
let mut mac = HmacSha1::new_from_slice(turn_secret.as_bytes())
.expect("HMAC can take key of any size");
mac.update(username.as_bytes());
let password: String = general_purpose::STANDARD.encode(mac.finalize().into_bytes());

View file

@ -13,21 +13,18 @@ use crate::{Error, Result, Ruma};
///
/// Returns the .well-known URL if it is configured, otherwise returns 404.
pub(crate) async fn well_known_client(
State(services): State<crate::State>, _body: Ruma<discover_homeserver::Request>,
State(services): State<crate::State>,
_body: Ruma<discover_homeserver::Request>,
) -> Result<discover_homeserver::Response> {
let client_url = match services.server.config.well_known.client.as_ref() {
Some(url) => url.to_string(),
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
| Some(url) => url.to_string(),
| None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
};
Ok(discover_homeserver::Response {
homeserver: HomeserverInfo {
base_url: client_url.clone(),
},
homeserver: HomeserverInfo { base_url: client_url.clone() },
identity_server: None,
sliding_sync_proxy: Some(SlidingSyncProxyInfo {
url: client_url,
}),
sliding_sync_proxy: Some(SlidingSyncProxyInfo { url: client_url }),
tile_server: None,
})
}
@ -36,7 +33,8 @@ pub(crate) async fn well_known_client(
///
/// Server support contact and support page of a homeserver's domain.
pub(crate) async fn well_known_support(
State(services): State<crate::State>, _body: Ruma<discover_support::Request>,
State(services): State<crate::State>,
_body: Ruma<discover_support::Request>,
) -> Result<discover_support::Response> {
let support_page = services
.server
@ -65,11 +63,7 @@ pub(crate) async fn well_known_support(
let mut contacts: Vec<Contact> = vec![];
if let Some(role) = role {
let contact = Contact {
role,
email_address,
matrix_id,
};
let contact = Contact { role, email_address, matrix_id };
contacts.push(contact);
}
@ -79,22 +73,21 @@ pub(crate) async fn well_known_support(
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
}
Ok(discover_support::Response {
contacts,
support_page,
})
Ok(discover_support::Response { contacts, support_page })
}
/// # `GET /client/server.json`
///
/// Endpoint provided by sliding sync proxy used by some clients such as Element
/// Web as a non-standard health check.
pub(crate) async fn syncv3_client_server_json(State(services): State<crate::State>) -> Result<impl IntoResponse> {
pub(crate) async fn syncv3_client_server_json(
State(services): State<crate::State>,
) -> Result<impl IntoResponse> {
let server_url = match services.server.config.well_known.client.as_ref() {
Some(url) => url.to_string(),
None => match services.server.config.well_known.server.as_ref() {
Some(url) => url.to_string(),
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
| Some(url) => url.to_string(),
| None => match services.server.config.well_known.server.as_ref() {
| Some(url) => url.to_string(),
| None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
},
};

View file

@ -190,7 +190,10 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
router = router
.ruma_route(&server::get_server_version_route)
.route("/_matrix/key/v2/server", get(server::get_server_keys_route))
.route("/_matrix/key/v2/server/:key_id", get(server::get_server_keys_deprecated_route))
.route(
"/_matrix/key/v2/server/:key_id",
get(server::get_server_keys_deprecated_route),
)
.ruma_route(&server::get_public_rooms_route)
.ruma_route(&server::get_public_rooms_filtered_route)
.ruma_route(&server::send_transaction_message_route)
@ -284,6 +287,10 @@ async fn redirect_legacy_preview(uri: Uri) -> impl IntoResponse {
Redirect::temporary(&uri)
}
async fn legacy_media_disabled() -> impl IntoResponse { err!(Request(Forbidden("Unauthenticated media is disabled."))) }
async fn legacy_media_disabled() -> impl IntoResponse {
err!(Request(Forbidden("Unauthenticated media is disabled.")))
}
async fn federation_disabled() -> impl IntoResponse { err!(Request(Forbidden("Federation is disabled."))) }
async fn federation_disabled() -> impl IntoResponse {
err!(Request(Forbidden("Federation is disabled.")))
}

View file

@ -4,8 +4,8 @@ use axum::{async_trait, body::Body, extract::FromRequest};
use bytes::{BufMut, Bytes, BytesMut};
use conduwuit::{debug, debug_warn, err, trace, utils::string::EMPTY, Error, Result};
use ruma::{
api::IncomingRequest, CanonicalJsonObject, CanonicalJsonValue, DeviceId, OwnedDeviceId, OwnedServerName,
OwnedUserId, ServerName, UserId,
api::IncomingRequest, CanonicalJsonObject, CanonicalJsonValue, DeviceId, OwnedDeviceId,
OwnedServerName, OwnedUserId, ServerName, UserId,
};
use service::Services;
@ -43,7 +43,9 @@ where
T: IncomingRequest + Send + Sync + 'static,
{
#[inline]
pub(crate) fn sender(&self) -> (&UserId, &DeviceId) { (self.sender_user(), self.sender_device()) }
pub(crate) fn sender(&self) -> (&UserId, &DeviceId) {
(self.sender_user(), self.sender_device())
}
#[inline]
pub(crate) fn sender_user(&self) -> &UserId {
@ -83,7 +85,10 @@ where
{
type Rejection = Error;
async fn from_request(request: hyper::Request<Body>, services: &State) -> Result<Self, Self::Rejection> {
async fn from_request(
request: hyper::Request<Body>,
services: &State,
) -> Result<Self, Self::Rejection> {
let mut request = request::from(services, request).await?;
let mut json_body = serde_json::from_slice::<CanonicalJsonValue>(&request.body).ok();
@ -96,7 +101,10 @@ where
&& !request.parts.uri.path().contains("/media/")
{
trace!("json_body from_request: {:?}", json_body.clone());
debug_warn!("received a POST request with an empty body, defaulting/assuming to {{}} like Synapse does");
debug_warn!(
"received a POST request with an empty body, defaulting/assuming to {{}} like \
Synapse does"
);
json_body = Some(CanonicalJsonValue::Object(CanonicalJsonObject::new()));
}
let auth = auth::auth(services, &mut request, json_body.as_ref(), &T::METADATA).await?;
@ -112,14 +120,18 @@ where
}
fn make_body<T>(
services: &Services, request: &mut Request, json_body: Option<&mut CanonicalJsonValue>, auth: &Auth,
services: &Services,
request: &mut Request,
json_body: Option<&mut CanonicalJsonValue>,
auth: &Auth,
) -> Result<T>
where
T: IncomingRequest,
{
let body = take_body(services, request, json_body, auth);
let http_request = into_http_request(request, body);
T::try_from_http_request(http_request, &request.path).map_err(|e| err!(Request(BadJson(debug_warn!("{e}")))))
T::try_from_http_request(http_request, &request.path)
.map_err(|e| err!(Request(BadJson(debug_warn!("{e}")))))
}
fn into_http_request(request: &Request, body: Bytes) -> hyper::Request<Bytes> {
@ -141,7 +153,10 @@ fn into_http_request(request: &Request, body: Bytes) -> hyper::Request<Bytes> {
#[allow(clippy::needless_pass_by_value)]
fn take_body(
services: &Services, request: &mut Request, json_body: Option<&mut CanonicalJsonValue>, auth: &Auth,
services: &Services,
request: &mut Request,
json_body: Option<&mut CanonicalJsonValue>,
auth: &Auth,
) -> Bytes {
let Some(CanonicalJsonValue::Object(json_body)) = json_body else {
return mem::take(&mut request.body);

View file

@ -10,7 +10,9 @@ use ruma::{
client::{
directory::get_public_rooms,
error::ErrorKind,
profile::{get_avatar_url, get_display_name, get_profile, get_profile_key, get_timezone_key},
profile::{
get_avatar_url, get_display_name, get_profile, get_profile_key, get_timezone_key,
},
voip::get_turn_server_info,
},
federation::openid::get_openid_userinfo,
@ -42,12 +44,15 @@ pub(super) struct Auth {
}
pub(super) async fn auth(
services: &Services, request: &mut Request, json_body: Option<&CanonicalJsonValue>, metadata: &Metadata,
services: &Services,
request: &mut Request,
json_body: Option<&CanonicalJsonValue>,
metadata: &Metadata,
) -> Result<Auth> {
let bearer: Option<TypedHeader<Authorization<Bearer>>> = request.parts.extract().await?;
let token = match &bearer {
Some(TypedHeader(Authorization(bearer))) => Some(bearer.token()),
None => request.query.access_token.as_deref(),
| Some(TypedHeader(Authorization(bearer))) => Some(bearer.token()),
| None => request.query.access_token.as_deref(),
};
let token = if let Some(token) = token {
@ -64,56 +69,64 @@ pub(super) async fn auth(
if metadata.authentication == AuthScheme::None {
match metadata {
&get_public_rooms::v3::Request::METADATA => {
| &get_public_rooms::v3::Request::METADATA => {
if !services
.globals
.config
.allow_public_room_directory_without_auth
{
match token {
Token::Appservice(_) | Token::User(_) => {
| Token::Appservice(_) | Token::User(_) => {
// we should have validated the token above
// already
},
Token::None | Token::Invalid => {
return Err(Error::BadRequest(ErrorKind::MissingToken, "Missing or invalid access token."));
| Token::None | Token::Invalid => {
return Err(Error::BadRequest(
ErrorKind::MissingToken,
"Missing or invalid access token.",
));
},
}
}
},
&get_profile::v3::Request::METADATA
| &get_profile::v3::Request::METADATA
| &get_profile_key::unstable::Request::METADATA
| &get_display_name::v3::Request::METADATA
| &get_avatar_url::v3::Request::METADATA
| &get_timezone_key::unstable::Request::METADATA => {
if services.globals.config.require_auth_for_profile_requests {
match token {
Token::Appservice(_) | Token::User(_) => {
| Token::Appservice(_) | Token::User(_) => {
// we should have validated the token above
// already
},
Token::None | Token::Invalid => {
return Err(Error::BadRequest(ErrorKind::MissingToken, "Missing or invalid access token."));
| Token::None | Token::Invalid => {
return Err(Error::BadRequest(
ErrorKind::MissingToken,
"Missing or invalid access token.",
));
},
}
}
},
_ => {},
| _ => {},
};
}
match (metadata.authentication, token) {
(AuthScheme::AccessToken, Token::Appservice(info)) => Ok(auth_appservice(services, request, info).await?),
(AuthScheme::None | AuthScheme::AccessTokenOptional | AuthScheme::AppserviceToken, Token::Appservice(info)) => {
Ok(Auth {
| (AuthScheme::AccessToken, Token::Appservice(info)) =>
Ok(auth_appservice(services, request, info).await?),
| (
AuthScheme::None | AuthScheme::AccessTokenOptional | AuthScheme::AppserviceToken,
Token::Appservice(info),
) => Ok(Auth {
origin: None,
sender_user: None,
sender_device: None,
appservice_info: Some(*info),
})
},
(AuthScheme::AccessToken, Token::None) => match metadata {
&get_turn_server_info::v3::Request::METADATA => {
}),
| (AuthScheme::AccessToken, Token::None) => match metadata {
| &get_turn_server_info::v3::Request::METADATA => {
if services.globals.config.turn_allow_guests {
Ok(Auth {
origin: None,
@ -125,9 +138,9 @@ pub(super) async fn auth(
Err(Error::BadRequest(ErrorKind::MissingToken, "Missing access token."))
}
},
_ => Err(Error::BadRequest(ErrorKind::MissingToken, "Missing access token.")),
| _ => Err(Error::BadRequest(ErrorKind::MissingToken, "Missing access token.")),
},
(
| (
AuthScheme::AccessToken | AuthScheme::AccessTokenOptional | AuthScheme::None,
Token::User((user_id, device_id)),
) => Ok(Auth {
@ -136,26 +149,33 @@ pub(super) async fn auth(
sender_device: Some(device_id),
appservice_info: None,
}),
(AuthScheme::ServerSignatures, Token::None) => Ok(auth_server(services, request, json_body).await?),
(AuthScheme::None | AuthScheme::AppserviceToken | AuthScheme::AccessTokenOptional, Token::None) => Ok(Auth {
| (AuthScheme::ServerSignatures, Token::None) =>
Ok(auth_server(services, request, json_body).await?),
| (
AuthScheme::None | AuthScheme::AppserviceToken | AuthScheme::AccessTokenOptional,
Token::None,
) => Ok(Auth {
sender_user: None,
sender_device: None,
origin: None,
appservice_info: None,
}),
(AuthScheme::ServerSignatures, Token::Appservice(_) | Token::User(_)) => Err(Error::BadRequest(
| (AuthScheme::ServerSignatures, Token::Appservice(_) | Token::User(_)) =>
Err(Error::BadRequest(
ErrorKind::Unauthorized,
"Only server signatures should be used on this endpoint.",
)),
(AuthScheme::AppserviceToken, Token::User(_)) => Err(Error::BadRequest(
| (AuthScheme::AppserviceToken, Token::User(_)) => Err(Error::BadRequest(
ErrorKind::Unauthorized,
"Only appservice access tokens should be used on this endpoint.",
)),
(AuthScheme::None, Token::Invalid) => {
| (AuthScheme::None, Token::Invalid) => {
// OpenID federation endpoint uses a query param with the same name, drop this
// once query params for user auth are removed from the spec. This is
// required to make integration manager work.
if request.query.access_token.is_some() && metadata == &get_openid_userinfo::v1::Request::METADATA {
if request.query.access_token.is_some()
&& metadata == &get_openid_userinfo::v1::Request::METADATA
{
Ok(Auth {
origin: None,
sender_user: None,
@ -164,25 +184,29 @@ pub(super) async fn auth(
})
} else {
Err(Error::BadRequest(
ErrorKind::UnknownToken {
soft_logout: false,
},
ErrorKind::UnknownToken { soft_logout: false },
"Unknown access token.",
))
}
},
(_, Token::Invalid) => Err(Error::BadRequest(
ErrorKind::UnknownToken {
soft_logout: false,
},
| (_, Token::Invalid) => Err(Error::BadRequest(
ErrorKind::UnknownToken { soft_logout: false },
"Unknown access token.",
)),
}
}
async fn auth_appservice(services: &Services, request: &Request, info: Box<RegistrationInfo>) -> Result<Auth> {
let user_id_default =
|| UserId::parse_with_server_name(info.registration.sender_localpart.as_str(), services.globals.server_name());
async fn auth_appservice(
services: &Services,
request: &Request,
info: Box<RegistrationInfo>,
) -> Result<Auth> {
let user_id_default = || {
UserId::parse_with_server_name(
info.registration.sender_localpart.as_str(),
services.globals.server_name(),
)
};
let Ok(user_id) = request
.query
@ -205,7 +229,11 @@ async fn auth_appservice(services: &Services, request: &Request, info: Box<Regis
})
}
async fn auth_server(services: &Services, request: &mut Request, body: Option<&CanonicalJsonValue>) -> Result<Auth> {
async fn auth_server(
services: &Services,
request: &mut Request,
body: Option<&CanonicalJsonValue>,
) -> Result<Auth> {
type Member = (String, CanonicalJsonValue);
type Object = CanonicalJsonObject;
type Value = CanonicalJsonValue;
@ -222,7 +250,8 @@ async fn auth_server(services: &Services, request: &mut Request, body: Option<&C
.expect("all requests have a path")
.to_string();
let signature: [Member; 1] = [(x_matrix.key.as_str().into(), Value::String(x_matrix.sig.to_string()))];
let signature: [Member; 1] =
[(x_matrix.key.as_str().into(), Value::String(x_matrix.sig.to_string()))];
let signatures: [Member; 1] = [(origin.as_str().into(), Value::Object(signature.into()))];
@ -261,8 +290,8 @@ async fn auth_server(services: &Services, request: &mut Request, body: Option<&C
debug_error!("Failed to verify federation request from {origin}: {e}");
if request.parts.uri.to_string().contains('@') {
warn!(
"Request uri contained '@' character. Make sure your reverse proxy gives conduwuit the raw uri \
(apache: use nocanon)"
"Request uri contained '@' character. Make sure your reverse proxy gives \
conduwuit the raw uri (apache: use nocanon)"
);
}
@ -294,7 +323,9 @@ fn auth_server_checks(services: &Services, x_matrix: &XMatrix) -> Result<()> {
.forbidden_remote_server_names
.contains(origin)
{
return Err!(Request(Forbidden(debug_warn!("Federation requests from {origin} denied."))));
return Err!(Request(Forbidden(debug_warn!(
"Federation requests from {origin} denied."
))));
}
Ok(())
@ -307,9 +338,9 @@ async fn parse_x_matrix(request: &mut Request) -> Result<XMatrix> {
.await
.map_err(|e| {
let msg = match e.reason() {
TypedHeaderRejectionReason::Missing => "Missing Authorization header.",
TypedHeaderRejectionReason::Error(_) => "Invalid X-Matrix signatures.",
_ => "Unknown header-related error",
| TypedHeaderRejectionReason::Missing => "Missing Authorization header.",
| TypedHeaderRejectionReason::Error(_) => "Invalid X-Matrix signatures.",
| _ => "Unknown header-related error",
};
err!(Request(Forbidden(warn!("{msg}: {e}"))))

View file

@ -66,14 +66,14 @@ ruma_handler!(T1, T2, T3, T4);
const fn method_to_filter(method: &Method) -> MethodFilter {
match *method {
Method::DELETE => MethodFilter::DELETE,
Method::GET => MethodFilter::GET,
Method::HEAD => MethodFilter::HEAD,
Method::OPTIONS => MethodFilter::OPTIONS,
Method::PATCH => MethodFilter::PATCH,
Method::POST => MethodFilter::POST,
Method::PUT => MethodFilter::PUT,
Method::TRACE => MethodFilter::TRACE,
_ => panic!("Unsupported HTTP method"),
| Method::DELETE => MethodFilter::DELETE,
| Method::GET => MethodFilter::GET,
| Method::HEAD => MethodFilter::HEAD,
| Method::OPTIONS => MethodFilter::OPTIONS,
| Method::PATCH => MethodFilter::PATCH,
| Method::POST => MethodFilter::POST,
| Method::PUT => MethodFilter::PUT,
| Method::TRACE => MethodFilter::TRACE,
| _ => panic!("Unsupported HTTP method"),
}
}

View file

@ -20,14 +20,17 @@ pub(super) struct Request {
pub(super) parts: Parts,
}
pub(super) async fn from(services: &Services, request: hyper::Request<axum::body::Body>) -> Result<Request> {
pub(super) async fn from(
services: &Services,
request: hyper::Request<axum::body::Body>,
) -> Result<Request> {
let limited = request.with_limited_body();
let (mut parts, body) = limited.into_parts();
let path: Path<Vec<String>> = parts.extract().await?;
let query = parts.uri.query().unwrap_or_default();
let query =
serde_html_form::from_str(query).map_err(|e| err!(Request(Unknown("Failed to read query parameters: {e}"))))?;
let query = serde_html_form::from_str(query)
.map_err(|e| err!(Request(Unknown("Failed to read query parameters: {e}"))))?;
let max_body_size = services.globals.config.max_request_size;
@ -35,10 +38,5 @@ pub(super) async fn from(services: &Services, request: hyper::Request<axum::body
.await
.map_err(|e| err!(Request(TooLarge("Request body too large: {e}"))))?;
Ok(Request {
path,
query,
body,
parts,
})
Ok(Request { path, query, body, parts })
}

View file

@ -16,9 +16,7 @@ pub fn create(services: Arc<Services>) -> (State, Guard) {
services: Arc::into_raw(services.clone()),
};
let guard = Guard {
services,
};
let guard = Guard { services };
(state, guard)
}

View file

@ -16,7 +16,8 @@ use crate::Ruma;
/// Retrieves events from before the sender joined the room, if the room's
/// history visibility allows.
pub(crate) async fn get_backfill_route(
State(services): State<crate::State>, ref body: Ruma<get_backfill::v1::Request>,
State(services): State<crate::State>,
ref body: Ruma<get_backfill::v1::Request>,
) -> Result<get_backfill::v1::Response> {
AccessCheck {
services: &services,

View file

@ -12,7 +12,8 @@ use crate::Ruma;
/// - Only works if a user of this server is currently invited or joined the
/// room
pub(crate) async fn get_event_route(
State(services): State<crate::State>, body: Ruma<get_event::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_event::v1::Request>,
) -> Result<get_event::v1::Response> {
let event = services
.rooms

View file

@ -17,7 +17,8 @@ use crate::Ruma;
///
/// - This does not include the event itself
pub(crate) async fn get_event_authorization_route(
State(services): State<crate::State>, body: Ruma<get_event_authorization::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_event_authorization::v1::Request>,
) -> Result<get_event_authorization::v1::Response> {
AccessCheck {
services: &services,
@ -40,8 +41,8 @@ pub(crate) async fn get_event_authorization_route(
.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 in event in database."))?;
let room_id = <&RoomId>::try_from(room_id_str)
.map_err(|_| Error::bad_database("Invalid room_id in event in database."))?;
let auth_chain = services
.rooms
@ -53,7 +54,5 @@ pub(crate) async fn get_event_authorization_route(
.collect()
.await;
Ok(get_event_authorization::v1::Response {
auth_chain,
})
Ok(get_event_authorization::v1::Response { auth_chain })
}

View file

@ -12,7 +12,8 @@ use crate::Ruma;
///
/// Retrieves events that the sender is missing.
pub(crate) async fn get_missing_events_route(
State(services): State<crate::State>, body: Ruma<get_missing_events::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_missing_events::v1::Request>,
) -> Result<get_missing_events::v1::Response> {
AccessCheck {
services: &services,
@ -87,7 +88,5 @@ pub(crate) async fn get_missing_events_route(
i = i.saturating_add(1);
}
Ok(get_missing_events::v1::Response {
events,
})
Ok(get_missing_events::v1::Response { events })
}

View file

@ -8,7 +8,8 @@ use crate::{Error, Result, Ruma};
/// Gets the space tree in a depth-first manner to locate child rooms of a given
/// space.
pub(crate) async fn get_hierarchy_route(
State(services): State<crate::State>, body: Ruma<get_hierarchy::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_hierarchy::v1::Request>,
) -> Result<get_hierarchy::v1::Response> {
if services.rooms.metadata.exists(&body.room_id).await {
services

View file

@ -16,7 +16,8 @@ use crate::Ruma;
/// Invites a remote user to a room.
#[tracing::instrument(skip_all, fields(%client), name = "invite")]
pub(crate) async fn create_invite_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<create_invite::v2::Request>,
) -> Result<create_invite::v2::Response> {
// ACL check origin
@ -28,9 +29,7 @@ pub(crate) async fn create_invite_route(
if !services.server.supported_room_version(&body.room_version) {
return Err(Error::BadRequest(
ErrorKind::IncompatibleRoomVersion {
room_version: body.room_version.clone(),
},
ErrorKind::IncompatibleRoomVersion { room_version: body.room_version.clone() },
"Server does not support this room version.",
));
}
@ -102,11 +101,14 @@ pub(crate) async fn create_invite_route(
.try_into()
.map_err(|e| err!(Request(InvalidParam("Invalid sender property: {e}"))))?;
if services.rooms.metadata.is_banned(&body.room_id).await && !services.users.is_admin(&invited_user).await {
if services.rooms.metadata.is_banned(&body.room_id).await
&& !services.users.is_admin(&invited_user).await
{
return Err!(Request(Forbidden("This room is banned on this homeserver.")));
}
if services.globals.block_non_admin_invites() && !services.users.is_admin(&invited_user).await {
if services.globals.block_non_admin_invites() && !services.users.is_admin(&invited_user).await
{
return Err!(Request(Forbidden("This server does not allow room invites.")));
}

View file

@ -22,7 +22,9 @@ use ruma::{
/// this will be valid forever.
// Response type for this endpoint is Json because we need to calculate a
// signature for the response
pub(crate) async fn get_server_keys_route(State(services): State<crate::State>) -> Result<impl IntoResponse> {
pub(crate) async fn get_server_keys_route(
State(services): State<crate::State>,
) -> Result<impl IntoResponse> {
let server_name = services.globals.server_name();
let active_key_id = services.server_keys.active_key_id();
let mut all_keys = services.server_keys.verify_keys_for(server_name).await;
@ -72,6 +74,8 @@ fn expires_ts() -> MilliSecondsSinceUnixEpoch {
///
/// - Matrix does not support invalidating public keys, so the key returned by
/// this will be valid forever.
pub(crate) async fn get_server_keys_deprecated_route(State(services): State<crate::State>) -> impl IntoResponse {
pub(crate) async fn get_server_keys_deprecated_route(
State(services): State<crate::State>,
) -> impl IntoResponse {
get_server_keys_route(State(services)).await
}

View file

@ -23,7 +23,8 @@ use crate::{
///
/// Creates a join template.
pub(crate) async fn create_join_event_template_route(
State(services): State<crate::State>, body: Ruma<prepare_join_event::v1::Request>,
State(services): State<crate::State>,
body: Ruma<prepare_join_event::v1::Request>,
) -> Result<prepare_join_event::v1::Response> {
if !services.rooms.metadata.exists(&body.room_id).await {
return Err!(Request(NotFound("Room is unknown to this server.")));
@ -47,8 +48,8 @@ pub(crate) async fn create_join_event_template_route(
.contains(body.origin())
{
warn!(
"Server {} for remote user {} tried joining room ID {} which has a server name that is globally \
forbidden. Rejecting.",
"Server {} for remote user {} tried joining room ID {} which has a server name that \
is globally forbidden. Rejecting.",
body.origin(),
&body.user_id,
&body.room_id,
@ -72,9 +73,7 @@ pub(crate) async fn create_join_event_template_route(
let room_version_id = services.rooms.state.get_room_version(&body.room_id).await?;
if !body.ver.contains(&room_version_id) {
return Err(Error::BadRequest(
ErrorKind::IncompatibleRoomVersion {
room_version: room_version_id,
},
ErrorKind::IncompatibleRoomVersion { room_version: room_version_id },
"Room version not supported.",
));
}
@ -86,16 +85,25 @@ pub(crate) async fn create_join_event_template_route(
if matches!(room_version_id, V1 | V2 | V3 | V4 | V5 | V6 | V7) {
// room version does not support restricted join rules
None
} else if user_can_perform_restricted_join(&services, &body.user_id, &body.room_id, &room_version_id).await? {
} else if user_can_perform_restricted_join(
&services,
&body.user_id,
&body.room_id,
&room_version_id,
)
.await?
{
let Some(auth_user) = services
.rooms
.state_cache
.local_users_in_room(&body.room_id)
.filter(|user| {
services
.rooms
.state_accessor
.user_can_invite(&body.room_id, user, &body.user_id, &state_lock)
services.rooms.state_accessor.user_can_invite(
&body.room_id,
user,
&body.user_id,
&state_lock,
)
})
.boxed()
.next()
@ -116,13 +124,10 @@ pub(crate) async fn create_join_event_template_route(
.rooms
.timeline
.create_hash_and_sign_event(
PduBuilder::state(
body.user_id.to_string(),
&RoomMemberEventContent {
PduBuilder::state(body.user_id.to_string(), &RoomMemberEventContent {
join_authorized_via_users_server,
..RoomMemberEventContent::new(MembershipState::Join)
},
),
}),
&body.user_id,
&body.room_id,
&state_lock,
@ -142,7 +147,10 @@ pub(crate) async fn create_join_event_template_route(
/// Checks whether the given user can join the given room via a restricted join.
pub(crate) async fn user_can_perform_restricted_join(
services: &Services, user_id: &UserId, room_id: &RoomId, room_version_id: &RoomVersionId,
services: &Services,
user_id: &UserId,
room_id: &RoomId,
room_version_id: &RoomVersionId,
) -> Result<bool> {
use RoomVersionId::*;
@ -159,13 +167,19 @@ pub(crate) async fn user_can_perform_restricted_join(
let Ok(join_rules_event_content) = services
.rooms
.state_accessor
.room_state_get_content::<RoomJoinRulesEventContent>(room_id, &StateEventType::RoomJoinRules, "")
.room_state_get_content::<RoomJoinRulesEventContent>(
room_id,
&StateEventType::RoomJoinRules,
"",
)
.await
else {
return Ok(false);
};
let (JoinRule::Restricted(r) | JoinRule::KnockRestricted(r)) = join_rules_event_content.join_rule else {
let (JoinRule::Restricted(r) | JoinRule::KnockRestricted(r)) =
join_rules_event_content.join_rule
else {
return Ok(false);
};
@ -195,12 +209,15 @@ pub(crate) async fn user_can_perform_restricted_join(
}
}
pub(crate) fn maybe_strip_event_id(pdu_json: &mut CanonicalJsonObject, room_version_id: &RoomVersionId) -> Result {
pub(crate) fn maybe_strip_event_id(
pdu_json: &mut CanonicalJsonObject,
room_version_id: &RoomVersionId,
) -> Result {
use RoomVersionId::*;
match room_version_id {
V1 | V2 => Ok(()),
_ => {
| V1 | V2 => Ok(()),
| _ => {
pdu_json.remove("event_id");
Ok(())
},

View file

@ -13,7 +13,8 @@ use crate::{service::pdu::PduBuilder, Ruma};
///
/// Creates a leave template.
pub(crate) async fn create_leave_event_template_route(
State(services): State<crate::State>, body: Ruma<prepare_leave_event::v1::Request>,
State(services): State<crate::State>,
body: Ruma<prepare_leave_event::v1::Request>,
) -> Result<prepare_leave_event::v1::Response> {
if !services.rooms.metadata.exists(&body.room_id).await {
return Err!(Request(NotFound("Room is unknown to this server.")));
@ -37,7 +38,10 @@ pub(crate) async fn create_leave_event_template_route(
.rooms
.timeline
.create_hash_and_sign_event(
PduBuilder::state(body.user_id.to_string(), &RoomMemberEventContent::new(MembershipState::Leave)),
PduBuilder::state(
body.user_id.to_string(),
&RoomMemberEventContent::new(MembershipState::Leave),
),
&body.user_id,
&body.room_id,
&state_lock,

View file

@ -16,7 +16,8 @@ use crate::Ruma;
/// Load media from our server.
#[tracing::instrument(skip_all, fields(%client), name = "media_get")]
pub(crate) async fn get_content_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content::v1::Request>,
) -> Result<get_content::v1::Response> {
let mxc = Mxc {
@ -33,7 +34,8 @@ pub(crate) async fn get_content_route(
return Err!(Request(NotFound("Media not found.")));
};
let content_disposition = make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
let content_disposition =
make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
let content = Content {
file: content.expect("entire file contents"),
content_type: content_type.map(Into::into),
@ -51,7 +53,8 @@ pub(crate) async fn get_content_route(
/// Load media thumbnail from our server.
#[tracing::instrument(skip_all, fields(%client), name = "media_thumbnail_get")]
pub(crate) async fn get_content_thumbnail_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_content_thumbnail::v1::Request>,
) -> Result<get_content_thumbnail::v1::Response> {
let dim = Dim::from_ruma(body.width, body.height, body.method.clone())?;
@ -69,7 +72,8 @@ pub(crate) async fn get_content_thumbnail_route(
return Err!(Request(NotFound("Media not found.")));
};
let content_disposition = make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
let content_disposition =
make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
let content = Content {
file: content.expect("entire file contents"),
content_type: content_type.map(Into::into),

View file

@ -7,7 +7,8 @@ use crate::{Result, Ruma};
///
/// Get information about the user that generated the OpenID token.
pub(crate) async fn get_openid_userinfo_route(
State(services): State<crate::State>, body: Ruma<get_openid_userinfo::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_openid_userinfo::v1::Request>,
) -> Result<get_openid_userinfo::v1::Response> {
Ok(get_openid_userinfo::v1::Response::new(
services

View file

@ -15,7 +15,8 @@ use crate::{Error, Result, Ruma};
/// Lists the public rooms on this server.
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms")]
pub(crate) async fn get_public_rooms_filtered_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_public_rooms_filtered::v1::Request>,
) -> Result<get_public_rooms_filtered::v1::Response> {
if !services
@ -35,7 +36,9 @@ pub(crate) async fn get_public_rooms_filtered_route(
&body.room_network,
)
.await
.map_err(|_| Error::BadRequest(ErrorKind::Unknown, "Failed to return this server's public room list."))?;
.map_err(|_| {
Error::BadRequest(ErrorKind::Unknown, "Failed to return this server's public room list.")
})?;
Ok(get_public_rooms_filtered::v1::Response {
chunk: response.chunk,
@ -50,7 +53,8 @@ pub(crate) async fn get_public_rooms_filtered_route(
/// Lists the public rooms on this server.
#[tracing::instrument(skip_all, fields(%client), "publicrooms")]
pub(crate) async fn get_public_rooms_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<get_public_rooms::v1::Request>,
) -> Result<get_public_rooms::v1::Response> {
if !services
@ -69,7 +73,9 @@ pub(crate) async fn get_public_rooms_route(
&body.room_network,
)
.await
.map_err(|_| Error::BadRequest(ErrorKind::Unknown, "Failed to return this server's public room list."))?;
.map_err(|_| {
Error::BadRequest(ErrorKind::Unknown, "Failed to return this server's public room list.")
})?;
Ok(get_public_rooms::v1::Response {
chunk: response.chunk,

View file

@ -19,7 +19,8 @@ use crate::Ruma;
///
/// Resolve a room alias to a room id.
pub(crate) async fn get_room_information_route(
State(services): State<crate::State>, body: Ruma<get_room_information::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_room_information::v1::Request>,
) -> Result<get_room_information::v1::Response> {
let room_id = services
.rooms
@ -50,10 +51,7 @@ pub(crate) async fn get_room_information_route(
servers.insert(0, services.globals.server_name().to_owned());
}
Ok(get_room_information::v1::Response {
room_id,
servers,
})
Ok(get_room_information::v1::Response { room_id, servers })
}
/// # `GET /_matrix/federation/v1/query/profile`
@ -61,7 +59,8 @@ pub(crate) async fn get_room_information_route(
///
/// Gets information on a profile.
pub(crate) async fn get_profile_information_route(
State(services): State<crate::State>, body: Ruma<get_profile_information::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_profile_information::v1::Request>,
) -> Result<get_profile_information::v1::Response> {
if !services
.globals
@ -88,14 +87,14 @@ pub(crate) async fn get_profile_information_route(
let mut custom_profile_fields = BTreeMap::new();
match &body.field {
Some(ProfileField::DisplayName) => {
| Some(ProfileField::DisplayName) => {
displayname = services.users.displayname(&body.user_id).await.ok();
},
Some(ProfileField::AvatarUrl) => {
| Some(ProfileField::AvatarUrl) => {
avatar_url = services.users.avatar_url(&body.user_id).await.ok();
blurhash = services.users.blurhash(&body.user_id).await.ok();
},
Some(custom_field) => {
| Some(custom_field) => {
if let Ok(value) = services
.users
.profile_key(&body.user_id, custom_field.as_str())
@ -104,7 +103,7 @@ pub(crate) async fn get_profile_information_route(
custom_profile_fields.insert(custom_field.to_string(), value);
}
},
None => {
| None => {
displayname = services.users.displayname(&body.user_id).await.ok();
avatar_url = services.users.avatar_url(&body.user_id).await.ok();
blurhash = services.users.blurhash(&body.user_id).await.ok();

View file

@ -2,15 +2,18 @@ use std::{collections::BTreeMap, net::IpAddr, time::Instant};
use axum::extract::State;
use axum_client_ip::InsecureClientIp;
use conduwuit::{debug, debug_warn, err, error, result::LogErr, trace, utils::ReadyExt, warn, Err, Error, Result};
use conduwuit::{
debug, debug_warn, err, error, result::LogErr, trace, utils::ReadyExt, warn, Err, Error,
Result,
};
use futures::StreamExt;
use ruma::{
api::{
client::error::ErrorKind,
federation::transactions::{
edu::{
DeviceListUpdateContent, DirectDeviceContent, Edu, PresenceContent, ReceiptContent,
SigningKeyUpdateContent, TypingContent,
DeviceListUpdateContent, DirectDeviceContent, Edu, PresenceContent,
ReceiptContent, SigningKeyUpdateContent, TypingContent,
},
send_transaction_message,
},
@ -38,7 +41,8 @@ type ResolvedMap = BTreeMap<OwnedEventId, Result<()>>;
/// Push EDUs and PDUs to this server.
#[tracing::instrument(skip_all, fields(%client, origin = body.origin().as_str()), name = "send")]
pub(crate) async fn send_transaction_message_route(
State(services): State<crate::State>, InsecureClientIp(client): InsecureClientIp,
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<send_transaction_message::v1::Request>,
) -> Result<send_transaction_message::v1::Response> {
if body.origin() != body.body.origin {
@ -69,7 +73,8 @@ pub(crate) async fn send_transaction_message_route(
"Starting txn",
);
let resolved_map = handle_pdus(&services, &client, &body.pdus, body.origin(), &txn_start_time).await?;
let resolved_map =
handle_pdus(&services, &client, &body.pdus, body.origin(), &txn_start_time).await?;
handle_edus(&services, &client, &body.edus, body.origin()).await;
debug!(
@ -90,13 +95,17 @@ pub(crate) async fn send_transaction_message_route(
}
async fn handle_pdus(
services: &Services, _client: &IpAddr, pdus: &[Box<RawJsonValue>], origin: &ServerName, txn_start_time: &Instant,
services: &Services,
_client: &IpAddr,
pdus: &[Box<RawJsonValue>],
origin: &ServerName,
txn_start_time: &Instant,
) -> Result<ResolvedMap> {
let mut parsed_pdus = Vec::with_capacity(pdus.len());
for pdu in pdus {
parsed_pdus.push(match services.rooms.event_handler.parse_incoming_pdu(pdu).await {
Ok(t) => t,
Err(e) => {
| Ok(t) => t,
| Err(e) => {
debug_warn!("Could not parse PDU: {e}");
continue;
},
@ -145,26 +154,45 @@ async fn handle_pdus(
Ok(resolved_map)
}
async fn handle_edus(services: &Services, client: &IpAddr, edus: &[Raw<Edu>], origin: &ServerName) {
async fn handle_edus(
services: &Services,
client: &IpAddr,
edus: &[Raw<Edu>],
origin: &ServerName,
) {
for edu in edus
.iter()
.filter_map(|edu| serde_json::from_str::<Edu>(edu.json().get()).ok())
{
match edu {
Edu::Presence(presence) => handle_edu_presence(services, client, origin, presence).await,
Edu::Receipt(receipt) => handle_edu_receipt(services, client, origin, receipt).await,
Edu::Typing(typing) => handle_edu_typing(services, client, origin, typing).await,
Edu::DeviceListUpdate(content) => handle_edu_device_list_update(services, client, origin, content).await,
Edu::DirectToDevice(content) => handle_edu_direct_to_device(services, client, origin, content).await,
Edu::SigningKeyUpdate(content) => handle_edu_signing_key_update(services, client, origin, content).await,
Edu::_Custom(ref _custom) => {
| Edu::Presence(presence) => {
handle_edu_presence(services, client, origin, presence).await;
},
| Edu::Receipt(receipt) =>
handle_edu_receipt(services, client, origin, receipt).await,
| Edu::Typing(typing) => handle_edu_typing(services, client, origin, typing).await,
| Edu::DeviceListUpdate(content) => {
handle_edu_device_list_update(services, client, origin, content).await;
},
| Edu::DirectToDevice(content) => {
handle_edu_direct_to_device(services, client, origin, content).await;
},
| Edu::SigningKeyUpdate(content) => {
handle_edu_signing_key_update(services, client, origin, content).await;
},
| Edu::_Custom(ref _custom) => {
debug_warn!(?edus, "received custom/unknown EDU");
},
}
}
}
async fn handle_edu_presence(services: &Services, _client: &IpAddr, origin: &ServerName, presence: PresenceContent) {
async fn handle_edu_presence(
services: &Services,
_client: &IpAddr,
origin: &ServerName,
presence: PresenceContent,
) {
if !services.globals.allow_incoming_presence() {
return;
}
@ -193,7 +221,12 @@ async fn handle_edu_presence(services: &Services, _client: &IpAddr, origin: &Ser
}
}
async fn handle_edu_receipt(services: &Services, _client: &IpAddr, origin: &ServerName, receipt: ReceiptContent) {
async fn handle_edu_receipt(
services: &Services,
_client: &IpAddr,
origin: &ServerName,
receipt: ReceiptContent,
) {
if !services.globals.allow_incoming_read_receipts() {
return;
}
@ -230,7 +263,8 @@ async fn handle_edu_receipt(services: &Services, _client: &IpAddr, origin: &Serv
.await
{
for event_id in &user_updates.event_ids {
let user_receipts = BTreeMap::from([(user_id.clone(), user_updates.data.clone())]);
let user_receipts =
BTreeMap::from([(user_id.clone(), user_updates.data.clone())]);
let receipts = BTreeMap::from([(ReceiptType::Read, user_receipts)]);
let receipt_content = BTreeMap::from([(event_id.to_owned(), receipts)]);
let event = ReceiptEvent {
@ -255,7 +289,12 @@ async fn handle_edu_receipt(services: &Services, _client: &IpAddr, origin: &Serv
}
}
async fn handle_edu_typing(services: &Services, _client: &IpAddr, origin: &ServerName, typing: TypingContent) {
async fn handle_edu_typing(
services: &Services,
_client: &IpAddr,
origin: &ServerName,
typing: TypingContent,
) {
if !services.globals.config.allow_incoming_typing {
return;
}
@ -321,12 +360,12 @@ async fn handle_edu_typing(services: &Services, _client: &IpAddr, origin: &Serve
}
async fn handle_edu_device_list_update(
services: &Services, _client: &IpAddr, origin: &ServerName, content: DeviceListUpdateContent,
services: &Services,
_client: &IpAddr,
origin: &ServerName,
content: DeviceListUpdateContent,
) {
let DeviceListUpdateContent {
user_id,
..
} = content;
let DeviceListUpdateContent { user_id, .. } = content;
if user_id.server_name() != origin {
debug_warn!(
@ -340,14 +379,12 @@ async fn handle_edu_device_list_update(
}
async fn handle_edu_direct_to_device(
services: &Services, _client: &IpAddr, origin: &ServerName, content: DirectDeviceContent,
services: &Services,
_client: &IpAddr,
origin: &ServerName,
content: DirectDeviceContent,
) {
let DirectDeviceContent {
sender,
ev_type,
message_id,
messages,
} = content;
let DirectDeviceContent { sender, ev_type, message_id, messages } = content;
if sender.server_name() != origin {
debug_warn!(
@ -369,23 +406,28 @@ async fn handle_edu_direct_to_device(
for (target_user_id, map) in &messages {
for (target_device_id_maybe, event) in map {
let Ok(event) = event
.deserialize_as()
.map_err(|e| err!(Request(InvalidParam(error!("To-Device event is invalid: {e}")))))
else {
let Ok(event) = event.deserialize_as().map_err(|e| {
err!(Request(InvalidParam(error!("To-Device event is invalid: {e}"))))
}) else {
continue;
};
let ev_type = ev_type.to_string();
match target_device_id_maybe {
DeviceIdOrAllDevices::DeviceId(target_device_id) => {
| DeviceIdOrAllDevices::DeviceId(target_device_id) => {
services
.users
.add_to_device_event(&sender, target_user_id, target_device_id, &ev_type, event)
.add_to_device_event(
&sender,
target_user_id,
target_device_id,
&ev_type,
event,
)
.await;
},
DeviceIdOrAllDevices::AllDevices => {
| DeviceIdOrAllDevices::AllDevices => {
let (sender, ev_type, event) = (&sender, &ev_type, &event);
services
.users
@ -412,13 +454,12 @@ async fn handle_edu_direct_to_device(
}
async fn handle_edu_signing_key_update(
services: &Services, _client: &IpAddr, origin: &ServerName, content: SigningKeyUpdateContent,
services: &Services,
_client: &IpAddr,
origin: &ServerName,
content: SigningKeyUpdateContent,
) {
let SigningKeyUpdateContent {
user_id,
master_key,
self_signing_key,
} = content;
let SigningKeyUpdateContent { user_id, master_key, self_signing_key } = content;
if user_id.server_name() != origin {
debug_warn!(

View file

@ -16,7 +16,8 @@ use ruma::{
room::member::{MembershipState, RoomMemberEventContent},
StateEventType,
},
CanonicalJsonValue, OwnedEventId, OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName,
CanonicalJsonValue, OwnedEventId, OwnedRoomId, OwnedServerName, OwnedUserId, RoomId,
ServerName,
};
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
use service::Services;
@ -25,7 +26,10 @@ use crate::Ruma;
/// helper method for /send_join v1 and v2
async fn create_join_event(
services: &Services, origin: &ServerName, room_id: &RoomId, pdu: &RawJsonValue,
services: &Services,
origin: &ServerName,
room_id: &RoomId,
pdu: &RawJsonValue,
) -> Result<create_join_event::v1::RoomState> {
if !services.rooms.metadata.exists(room_id).await {
return Err!(Request(NotFound("Room is unknown to this server.")));
@ -146,7 +150,8 @@ async fn create_join_event(
if !services.globals.user_is_local(&authorising_user) {
return Err!(Request(InvalidParam(
"Cannot authorise membership event through {authorising_user} as they do not belong to this homeserver"
"Cannot authorise membership event through {authorising_user} as they do not \
belong to this homeserver"
)));
}
@ -157,12 +162,19 @@ async fn create_join_event(
.await
{
return Err!(Request(InvalidParam(
"Authorising user {authorising_user} is not in the room you are trying to join, they cannot authorise \
your join."
"Authorising user {authorising_user} is not in the room you are trying to join, \
they cannot authorise your join."
)));
}
if !super::user_can_perform_restricted_join(services, &state_key, room_id, &room_version_id).await? {
if !super::user_can_perform_restricted_join(
services,
&state_key,
room_id,
&room_version_id,
)
.await?
{
return Err!(Request(UnableToAuthorizeJoin(
"Joining user did not pass restricted room's rules."
)));
@ -228,7 +240,9 @@ async fn create_join_event(
.event_ids_iter(room_id, starting_events)
.await?
.map(Ok)
.broad_and_then(|event_id| async move { services.rooms.timeline.get_pdu_json(&event_id).await })
.broad_and_then(|event_id| async move {
services.rooms.timeline.get_pdu_json(&event_id).await
})
.broad_and_then(|pdu| {
services
.sending
@ -252,7 +266,8 @@ async fn create_join_event(
///
/// Submits a signed join event.
pub(crate) async fn create_join_event_v1_route(
State(services): State<crate::State>, body: Ruma<create_join_event::v1::Request>,
State(services): State<crate::State>,
body: Ruma<create_join_event::v1::Request>,
) -> Result<create_join_event::v1::Response> {
if services
.globals
@ -261,8 +276,8 @@ pub(crate) async fn create_join_event_v1_route(
.contains(body.origin())
{
warn!(
"Server {} tried joining room ID {} through us who has a server name that is globally forbidden. \
Rejecting.",
"Server {} tried joining room ID {} through us who has a server name that is \
globally forbidden. Rejecting.",
body.origin(),
&body.room_id,
);
@ -277,8 +292,8 @@ pub(crate) async fn create_join_event_v1_route(
.contains(&server.to_owned())
{
warn!(
"Server {} tried joining room ID {} through us which has a server name that is globally forbidden. \
Rejecting.",
"Server {} tried joining room ID {} through us which has a server name that is \
globally forbidden. Rejecting.",
body.origin(),
&body.room_id,
);
@ -292,16 +307,15 @@ pub(crate) async fn create_join_event_v1_route(
.boxed()
.await?;
Ok(create_join_event::v1::Response {
room_state,
})
Ok(create_join_event::v1::Response { room_state })
}
/// # `PUT /_matrix/federation/v2/send_join/{roomId}/{eventId}`
///
/// Submits a signed join event.
pub(crate) async fn create_join_event_v2_route(
State(services): State<crate::State>, body: Ruma<create_join_event::v2::Request>,
State(services): State<crate::State>,
body: Ruma<create_join_event::v2::Request>,
) -> Result<create_join_event::v2::Response> {
if services
.globals
@ -320,8 +334,8 @@ pub(crate) async fn create_join_event_v2_route(
.contains(&server.to_owned())
{
warn!(
"Server {} tried joining room ID {} through us which has a server name that is globally forbidden. \
Rejecting.",
"Server {} tried joining room ID {} through us which has a server name that is \
globally forbidden. Rejecting.",
body.origin(),
&body.room_id,
);
@ -331,11 +345,8 @@ pub(crate) async fn create_join_event_v2_route(
}
}
let create_join_event::v1::RoomState {
auth_chain,
state,
event,
} = create_join_event(&services, body.origin(), &body.room_id, &body.pdu)
let create_join_event::v1::RoomState { auth_chain, state, event } =
create_join_event(&services, body.origin(), &body.room_id, &body.pdu)
.boxed()
.await?;
let room_state = create_join_event::v2::RoomState {
@ -346,7 +357,5 @@ pub(crate) async fn create_join_event_v2_route(
servers_in_room: None,
};
Ok(create_join_event::v2::Response {
room_state,
})
Ok(create_join_event::v2::Response { room_state })
}

View file

@ -21,7 +21,8 @@ use crate::{
///
/// Submits a signed leave event.
pub(crate) async fn create_leave_event_v1_route(
State(services): State<crate::State>, body: Ruma<create_leave_event::v1::Request>,
State(services): State<crate::State>,
body: Ruma<create_leave_event::v1::Request>,
) -> Result<create_leave_event::v1::Response> {
create_leave_event(&services, body.origin(), &body.room_id, &body.pdu).await?;
@ -32,14 +33,20 @@ pub(crate) async fn create_leave_event_v1_route(
///
/// Submits a signed leave event.
pub(crate) async fn create_leave_event_v2_route(
State(services): State<crate::State>, body: Ruma<create_leave_event::v2::Request>,
State(services): State<crate::State>,
body: Ruma<create_leave_event::v2::Request>,
) -> Result<create_leave_event::v2::Response> {
create_leave_event(&services, body.origin(), &body.room_id, &body.pdu).await?;
Ok(create_leave_event::v2::Response::new())
}
async fn create_leave_event(services: &Services, origin: &ServerName, room_id: &RoomId, pdu: &RawJsonValue) -> Result {
async fn create_leave_event(
services: &Services,
origin: &ServerName,
room_id: &RoomId,
pdu: &RawJsonValue,
) -> Result {
if !services.rooms.metadata.exists(room_id).await {
return Err!(Request(NotFound("Room is unknown to this server.")));
}

View file

@ -12,7 +12,8 @@ use crate::Ruma;
///
/// Retrieves a snapshot of a room's state at a given event.
pub(crate) async fn get_room_state_route(
State(services): State<crate::State>, body: Ruma<get_room_state::v1::Request>,
State(services): State<crate::State>,
body: Ruma<get_room_state::v1::Request>,
) -> Result<get_room_state::v1::Response> {
AccessCheck {
services: &services,
@ -69,8 +70,5 @@ pub(crate) async fn get_room_state_route(
.try_collect()
.await?;
Ok(get_room_state::v1::Response {
auth_chain,
pdus,
})
Ok(get_room_state::v1::Response { auth_chain, pdus })
}

Some files were not shown because too many files have changed in this diff Show more