change rustfmt configuration

This change is fully automated, except the `rustfmt.toml` changes and
a few clippy directives to allow specific functions with too many lines
because they are longer now.
This commit is contained in:
Charles Hall 2024-05-16 01:19:04 -07:00
parent 40d6ce230d
commit 0afc1d2f50
No known key found for this signature in database
GPG key ID: 7B8E0645816E07CF
123 changed files with 7881 additions and 4687 deletions

View file

@ -1,14 +1,18 @@
use crate::{services, utils, Error, Result};
use std::{fmt::Debug, mem, time::Duration};
use bytes::BytesMut;
use ruma::api::{
appservice::Registration, IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken,
appservice::Registration, IncomingResponse, MatrixVersion, OutgoingRequest,
SendAccessToken,
};
use std::{fmt::Debug, mem, time::Duration};
use tracing::warn;
use crate::{services, utils, Error, Result};
/// Sends a request to an appservice
///
/// Only returns None if there is no url specified in the appservice registration file
/// Only returns None if there is no url specified in the appservice
/// registration file
#[tracing::instrument(skip(request))]
pub(crate) async fn send_request<T: OutgoingRequest>(
registration: Registration,
@ -45,7 +49,8 @@ where
.parse()
.unwrap(),
);
*http_request.uri_mut() = parts.try_into().expect("our manipulation is always valid");
*http_request.uri_mut() =
parts.try_into().expect("our manipulation is always valid");
let mut reqwest_request = reqwest::Request::try_from(http_request)?;
@ -70,9 +75,8 @@ where
// reqwest::Response -> http::Response conversion
let status = response.status();
let mut http_response_builder = http::Response::builder()
.status(status)
.version(response.version());
let mut http_response_builder =
http::Response::builder().status(status).version(response.version());
mem::swap(
response.headers_mut(),
http_response_builder

View file

@ -1,22 +1,25 @@
use super::{DEVICE_ID_LENGTH, SESSION_ID_LENGTH, TOKEN_LENGTH};
use crate::{api::client_server, services, utils, Error, Result, Ruma};
use register::RegistrationKind;
use ruma::{
api::client::{
account::{
change_password, 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},
},
events::{room::message::RoomMessageEventContent, GlobalAccountDataEventType},
events::{
room::message::RoomMessageEventContent, GlobalAccountDataEventType,
},
push, UserId,
};
use tracing::{info, warn};
use register::RegistrationKind;
use super::{DEVICE_ID_LENGTH, SESSION_ID_LENGTH, TOKEN_LENGTH};
use crate::{api::client_server, services, utils, Error, Result, Ruma};
const RANDOM_USER_ID_LENGTH: usize = 10;
@ -29,7 +32,8 @@ const RANDOM_USER_ID_LENGTH: usize = 10;
/// - The server name of the user id matches this server
/// - No user or appservice on this server already claimed this username
///
/// Note: This will not reserve the username, so the username might become invalid when trying to register
/// Note: This will not reserve the username, so the username might become
/// invalid when trying to register
pub(crate) async fn get_register_available_route(
body: Ruma<get_username_availability::v3::Request>,
) -> Result<get_username_availability::v3::Response> {
@ -40,7 +44,8 @@ pub(crate) async fn get_register_available_route(
)
.ok()
.filter(|user_id| {
!user_id.is_historical() && user_id.server_name() == services().globals.server_name()
!user_id.is_historical()
&& user_id.server_name() == services().globals.server_name()
})
.ok_or(Error::BadRequest(
ErrorKind::InvalidUsername,
@ -58,27 +63,35 @@ 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/r0/register`
///
/// Register an account on this homeserver.
///
/// You can use [`GET /_matrix/client/r0/register/available`](get_register_available_route)
/// You can use [`GET
/// /_matrix/client/r0/register/available`](get_register_available_route)
/// to check if the user id is valid and available.
///
/// - Only works if registration is enabled
/// - If type is guest: ignores all parameters except `initial_device_display_name`
/// - If type is guest: ignores all parameters except
/// `initial_device_display_name`
/// - If sender is not appservice: Requires UIAA (but we only use a dummy stage)
/// - If type is not guest and no username is given: Always fails after UIAA check
/// - If type is not guest and no username is given: Always fails after UIAA
/// check
/// - Creates a new account and populates it with default account data
/// - If `inhibit_login` is false: Creates a device and returns `device_id` and `access_token`
/// - If `inhibit_login` is false: Creates a device and returns `device_id` and
/// `access_token`
#[allow(clippy::too_many_lines)]
pub(crate) async fn register_route(
body: Ruma<register::v3::Request>,
) -> Result<register::v3::Response> {
if !services().globals.allow_registration() && body.appservice_info.is_none() {
if !services().globals.allow_registration()
&& body.appservice_info.is_none()
{
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"Registration has been disabled.",
@ -158,7 +171,8 @@ pub(crate) async fn register_route(
};
body.appservice_info.is_some()
} else {
// No registration token necessary, but clients must still go through the flow
// No registration token necessary, but clients must still go through
// the flow
uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
stages: vec![AuthType::Dummy],
@ -174,8 +188,11 @@ pub(crate) async fn register_route(
if !skip_auth {
if let Some(auth) = &body.auth {
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,
@ -187,8 +204,11 @@ 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,
@ -211,9 +231,7 @@ pub(crate) async fn register_route(
// Default to pretty displayname
let displayname = user_id.localpart().to_owned();
services()
.users
.set_displayname(&user_id, Some(displayname.clone()))?;
services().users.set_displayname(&user_id, Some(displayname.clone()))?;
// Initial account data
services().account_data.update(
@ -260,29 +278,24 @@ pub(crate) async fn register_route(
info!("New user {} registered on this server.", user_id);
if body.appservice_info.is_none() && !is_guest {
services()
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"New user {user_id} registered on this server."
)));
services().admin.send_message(RoomMessageEventContent::notice_plain(
format!("New user {user_id} registered on this server."),
));
}
// If this is the first real user, grant them admin privileges
// Note: the server user, @grapevine:servername, is generated first
if !is_guest {
if let Some(admin_room) = services().admin.get_admin_room()? {
if services()
.rooms
.state_cache
.room_joined_count(&admin_room)?
if services().rooms.state_cache.room_joined_count(&admin_room)?
== Some(1)
{
services()
.admin
.make_user_admin(&user_id, displayname)
.await?;
services().admin.make_user_admin(&user_id, displayname).await?;
warn!("Granting {} admin privileges as the first user", user_id);
warn!(
"Granting {} admin privileges as the first user",
user_id
);
}
}
}
@ -302,19 +315,23 @@ pub(crate) async fn register_route(
///
/// - Requires UIAA to verify user password
/// - Changes the password of the sender user
/// - The password hash is calculated using argon2 with 32 character salt, the plain password is
/// - The password hash is calculated using argon2 with 32 character salt, the
/// plain password is
/// not saved
///
/// If `logout_devices` is true it does the following for each device except the sender device:
/// If `logout_devices` is true it does the following for each device except the
/// sender device:
/// - Invalidates access token
/// - Deletes device metadata (device ID, device display name, last seen IP, last seen timestamp)
/// - Deletes device metadata (device ID, device display name, last seen IP,
/// last seen timestamp)
/// - Forgets to-device events
/// - Triggers device list updates
pub(crate) async fn change_password_route(
body: Ruma<change_password::v3::Request>,
) -> Result<change_password::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");
let sender_device =
body.sender_device.as_ref().expect("user is authenticated");
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
@ -327,27 +344,25 @@ pub(crate) async fn change_password_route(
};
if let Some(auth) = &body.auth {
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
let (worked, uiaainfo) = services().uiaa.try_auth(
sender_user,
sender_device,
auth,
&uiaainfo,
)?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
// Success!
} else if let Some(json) = body.json_body {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services()
.uiaa
.create(sender_user, sender_device, &uiaainfo, &json)?;
services().uiaa.create(sender_user, sender_device, &uiaainfo, &json)?;
return Err(Error::Uiaa(uiaainfo));
} else {
return Err(Error::BadRequest(ErrorKind::NotJson, "Not json."));
}
services()
.users
.set_password(sender_user, Some(&body.new_password))?;
services().users.set_password(sender_user, Some(&body.new_password))?;
if body.logout_devices {
// Logout all devices except the current one
@ -362,11 +377,9 @@ pub(crate) async fn change_password_route(
}
info!("User {} changed their password.", sender_user);
services()
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"User {sender_user} changed their password."
)));
services().admin.send_message(RoomMessageEventContent::notice_plain(
format!("User {sender_user} changed their password."),
));
Ok(change_password::v3::Response {})
}
@ -376,14 +389,17 @@ pub(crate) async fn change_password_route(
/// Get `user_id` of the sender user.
///
/// Note: Also works for Application Services
pub(crate) async fn whoami_route(body: Ruma<whoami::v3::Request>) -> Result<whoami::v3::Response> {
pub(crate) async fn whoami_route(
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.as_ref().cloned();
Ok(whoami::v3::Response {
user_id: sender_user.clone(),
device_id,
is_guest: services().users.is_deactivated(sender_user)? && body.appservice_info.is_none(),
is_guest: services().users.is_deactivated(sender_user)?
&& body.appservice_info.is_none(),
})
}
@ -393,7 +409,8 @@ pub(crate) async fn whoami_route(body: Ruma<whoami::v3::Request>) -> Result<whoa
///
/// - Leaves all rooms and rejects all invitations
/// - Invalidates all access tokens
/// - Deletes all device metadata (device id, device display name, last seen ip, last seen ts)
/// - Deletes all device metadata (device id, device display name, last seen ip,
/// last seen ts)
/// - Forgets all to-device events
/// - Triggers device list updates
/// - Removes ability to log in again
@ -401,7 +418,8 @@ pub(crate) async fn deactivate_route(
body: Ruma<deactivate::v3::Request>,
) -> Result<deactivate::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");
let sender_device =
body.sender_device.as_ref().expect("user is authenticated");
let mut uiaainfo = UiaaInfo {
flows: vec![AuthFlow {
@ -414,19 +432,19 @@ pub(crate) async fn deactivate_route(
};
if let Some(auth) = &body.auth {
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
let (worked, uiaainfo) = services().uiaa.try_auth(
sender_user,
sender_device,
auth,
&uiaainfo,
)?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
// Success!
} else if let Some(json) = body.json_body {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services()
.uiaa
.create(sender_user, sender_device, &uiaainfo, &json)?;
services().uiaa.create(sender_user, sender_device, &uiaainfo, &json)?;
return Err(Error::Uiaa(uiaainfo));
} else {
return Err(Error::BadRequest(ErrorKind::NotJson, "Not json."));
@ -439,11 +457,9 @@ pub(crate) async fn deactivate_route(
services().users.deactivate_account(sender_user)?;
info!("User {} deactivated their account.", sender_user);
services()
.admin
.send_message(RoomMessageEventContent::notice_plain(format!(
"User {sender_user} deactivated their account."
)));
services().admin.send_message(RoomMessageEventContent::notice_plain(
format!("User {sender_user} deactivated their account."),
));
Ok(deactivate::v3::Response {
id_server_unbind_result: ThirdPartyIdRemovalStatus::NoSupport,
@ -458,16 +474,19 @@ pub(crate) async fn deactivate_route(
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");
let _sender_user =
body.sender_user.as_ref().expect("user is authenticated");
Ok(get_3pids::v3::Response::new(Vec::new()))
}
/// # `POST /_matrix/client/v3/account/3pid/email/requestToken`
///
/// "This API should be used to request validation tokens when adding an email address to an account"
/// "This API should be used to request validation tokens when adding an email
/// address to an account"
///
/// - 403 signals that The homeserver does not allow the third party identifier as a contact option.
/// - 403 signals that The homeserver does not allow the third party identifier
/// as a contact option.
pub(crate) async fn request_3pid_management_token_via_email_route(
_body: Ruma<request_3pid_management_token_via_email::v3::Request>,
) -> Result<request_3pid_management_token_via_email::v3::Response> {
@ -479,9 +498,11 @@ pub(crate) async fn request_3pid_management_token_via_email_route(
/// # `POST /_matrix/client/v3/account/3pid/msisdn/requestToken`
///
/// "This API should be used to request validation tokens when adding an phone number to an account"
/// "This API should be used to request validation tokens when adding an phone
/// number to an account"
///
/// - 403 signals that The homeserver does not allow the third party identifier as a contact option.
/// - 403 signals that The homeserver does not allow the third party identifier
/// as a contact option.
pub(crate) async fn request_3pid_management_token_via_msisdn_route(
_body: Ruma<request_3pid_management_token_via_msisdn::v3::Request>,
) -> Result<request_3pid_management_token_via_msisdn::v3::Response> {

View file

@ -1,4 +1,3 @@
use crate::{services, Error, Result, Ruma};
use rand::seq::SliceRandom;
use ruma::{
api::{
@ -12,6 +11,8 @@ use ruma::{
OwnedRoomAliasId,
};
use crate::{services, Error, Result, Ruma};
/// # `PUT /_matrix/client/r0/directory/room/{roomAlias}`
///
/// Creates a new room alias on this server.
@ -32,30 +33,18 @@ pub(crate) async fn create_alias_route(
"Room alias is not in namespace.",
));
}
} else if services()
.appservice
.is_exclusive_alias(&body.room_alias)
.await
{
} else if services().appservice.is_exclusive_alias(&body.room_alias).await {
return Err(Error::BadRequest(
ErrorKind::Exclusive,
"Room alias reserved by appservice.",
));
}
if services()
.rooms
.alias
.resolve_local_alias(&body.room_alias)?
.is_some()
{
if services().rooms.alias.resolve_local_alias(&body.room_alias)?.is_some() {
return Err(Error::Conflict("Alias already exists."));
}
services()
.rooms
.alias
.set_alias(&body.room_alias, &body.room_id)?;
services().rooms.alias.set_alias(&body.room_alias, &body.room_id)?;
Ok(create_alias::v3::Response::new())
}
@ -83,11 +72,7 @@ pub(crate) async fn delete_alias_route(
"Room alias is not in namespace.",
));
}
} else if services()
.appservice
.is_exclusive_alias(&body.room_alias)
.await
{
} else if services().appservice.is_exclusive_alias(&body.room_alias).await {
return Err(Error::BadRequest(
ErrorKind::Exclusive,
"Room alias reserved by appservice.",
@ -157,7 +142,10 @@ pub(crate) async fn get_alias_helper(
.alias
.resolve_local_alias(&room_alias)?
.ok_or_else(|| {
Error::bad_config("Appservice lied to us. Room does not exist.")
Error::bad_config(
"Appservice lied to us. Room does not \
exist.",
)
})?,
);
break;

View file

@ -1,15 +1,16 @@
use crate::{services, Error, Result, Ruma};
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,
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,
},
error::ErrorKind,
};
use crate::{services, Error, Result, Ruma};
/// # `POST /_matrix/client/r0/room_keys/version`
///
/// Creates a new backup.
@ -17,23 +18,27 @@ pub(crate) async fn create_backup_version_route(
body: Ruma<create_backup_version::v3::Request>,
) -> Result<create_backup_version::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let version = services()
.key_backups
.create_backup(sender_user, &body.algorithm)?;
let version =
services().key_backups.create_backup(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}`
///
/// Update information about an existing backup. Only `auth_data` can be modified.
/// Update information about an existing backup. Only `auth_data` can be
/// modified.
pub(crate) async fn update_backup_version_route(
body: Ruma<update_backup_version::v3::Request>,
) -> Result<update_backup_version::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
services()
.key_backups
.update_backup(sender_user, &body.version, &body.algorithm)?;
services().key_backups.update_backup(
sender_user,
&body.version,
&body.algorithm,
)?;
Ok(update_backup_version::v3::Response {})
}
@ -88,9 +93,7 @@ pub(crate) async fn get_backup_info_route(
.count_keys(sender_user, &body.version)?
.try_into()
.expect("count should fit in UInt"),
etag: services()
.key_backups
.get_etag(sender_user, &body.version)?,
etag: services().key_backups.get_etag(sender_user, &body.version)?,
version: body.version.clone(),
})
}
@ -99,15 +102,14 @@ pub(crate) async fn get_backup_info_route(
///
/// Delete an existing key backup.
///
/// - Deletes both information about the backup, as well as all key data related to the backup
/// - Deletes both information about the backup, as well as all key data related
/// to the backup
pub(crate) async fn delete_backup_version_route(
body: Ruma<delete_backup_version::v3::Request>,
) -> Result<delete_backup_version::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
services()
.key_backups
.delete_backup(sender_user, &body.version)?;
services().key_backups.delete_backup(sender_user, &body.version)?;
Ok(delete_backup_version::v3::Response {})
}
@ -116,7 +118,8 @@ pub(crate) async fn delete_backup_version_route(
///
/// Add the received backup keys to the database.
///
/// - Only manipulating the most recently created version of the backup is allowed
/// - Only manipulating the most recently created version of the backup is
/// allowed
/// - 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(
@ -132,7 +135,8 @@ pub(crate) async fn add_backup_keys_route(
{
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"You may only manipulate the most recently created version of the backup.",
"You may only manipulate the most recently created version of the \
backup.",
));
}
@ -154,9 +158,7 @@ pub(crate) async fn add_backup_keys_route(
.count_keys(sender_user, &body.version)?
.try_into()
.expect("count should fit in UInt"),
etag: services()
.key_backups
.get_etag(sender_user, &body.version)?,
etag: services().key_backups.get_etag(sender_user, &body.version)?,
})
}
@ -164,7 +166,8 @@ pub(crate) async fn add_backup_keys_route(
///
/// Add the received backup keys to the database.
///
/// - Only manipulating the most recently created version of the backup is allowed
/// - Only manipulating the most recently created version of the backup is
/// allowed
/// - 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(
@ -180,7 +183,8 @@ pub(crate) async fn add_backup_keys_for_room_route(
{
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"You may only manipulate the most recently created version of the backup.",
"You may only manipulate the most recently created version of the \
backup.",
));
}
@ -200,9 +204,7 @@ pub(crate) async fn add_backup_keys_for_room_route(
.count_keys(sender_user, &body.version)?
.try_into()
.expect("count should fit in UInt"),
etag: services()
.key_backups
.get_etag(sender_user, &body.version)?,
etag: services().key_backups.get_etag(sender_user, &body.version)?,
})
}
@ -210,7 +212,8 @@ pub(crate) async fn add_backup_keys_for_room_route(
///
/// Add the received backup key to the database.
///
/// - Only manipulating the most recently created version of the backup is allowed
/// - Only manipulating the most recently created version of the backup is
/// allowed
/// - 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(
@ -226,7 +229,8 @@ pub(crate) async fn add_backup_keys_for_session_route(
{
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"You may only manipulate the most recently created version of the backup.",
"You may only manipulate the most recently created version of the \
backup.",
));
}
@ -244,9 +248,7 @@ pub(crate) async fn add_backup_keys_for_session_route(
.count_keys(sender_user, &body.version)?
.try_into()
.expect("count should fit in UInt"),
etag: services()
.key_backups
.get_etag(sender_user, &body.version)?,
etag: services().key_backups.get_etag(sender_user, &body.version)?,
})
}
@ -260,7 +262,9 @@ pub(crate) async fn get_backup_keys_route(
let rooms = services().key_backups.get_all(sender_user, &body.version)?;
Ok(get_backup_keys::v3::Response { rooms })
Ok(get_backup_keys::v3::Response {
rooms,
})
}
/// # `GET /_matrix/client/r0/room_keys/keys/{roomId}`
@ -271,11 +275,15 @@ pub(crate) async fn get_backup_keys_for_room_route(
) -> Result<get_backup_keys_for_room::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sessions = services()
.key_backups
.get_room(sender_user, &body.version, &body.room_id)?;
let sessions = services().key_backups.get_room(
sender_user,
&body.version,
&body.room_id,
)?;
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}`
@ -288,13 +296,20 @@ pub(crate) async fn get_backup_keys_for_session_route(
let key_data = services()
.key_backups
.get_session(sender_user, &body.version, &body.room_id, &body.session_id)?
.get_session(
sender_user,
&body.version,
&body.room_id,
&body.session_id,
)?
.ok_or(Error::BadRequest(
ErrorKind::NotFound,
"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`
@ -305,9 +320,7 @@ pub(crate) async fn delete_backup_keys_route(
) -> Result<delete_backup_keys::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
services()
.key_backups
.delete_all_keys(sender_user, &body.version)?;
services().key_backups.delete_all_keys(sender_user, &body.version)?;
Ok(delete_backup_keys::v3::Response {
count: services()
@ -315,9 +328,7 @@ pub(crate) async fn delete_backup_keys_route(
.count_keys(sender_user, &body.version)?
.try_into()
.expect("count should fit in UInt"),
etag: services()
.key_backups
.get_etag(sender_user, &body.version)?,
etag: services().key_backups.get_etag(sender_user, &body.version)?,
})
}
@ -329,9 +340,11 @@ pub(crate) async fn delete_backup_keys_for_room_route(
) -> Result<delete_backup_keys_for_room::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
services()
.key_backups
.delete_room_keys(sender_user, &body.version, &body.room_id)?;
services().key_backups.delete_room_keys(
sender_user,
&body.version,
&body.room_id,
)?;
Ok(delete_backup_keys_for_room::v3::Response {
count: services()
@ -339,9 +352,7 @@ pub(crate) async fn delete_backup_keys_for_room_route(
.count_keys(sender_user, &body.version)?
.try_into()
.expect("count should fit in UInt"),
etag: services()
.key_backups
.get_etag(sender_user, &body.version)?,
etag: services().key_backups.get_etag(sender_user, &body.version)?,
})
}
@ -366,8 +377,6 @@ pub(crate) async fn delete_backup_keys_for_session_route(
.count_keys(sender_user, &body.version)?
.try_into()
.expect("count should fit in UInt"),
etag: services()
.key_backups
.get_etag(sender_user, &body.version)?,
etag: services().key_backups.get_etag(sender_user, &body.version)?,
})
}

View file

@ -1,12 +1,15 @@
use crate::{services, Result, Ruma};
use std::collections::BTreeMap;
use ruma::api::client::discovery::get_capabilities::{
self, Capabilities, RoomVersionStability, RoomVersionsCapability,
};
use std::collections::BTreeMap;
use crate::{services, Result, Ruma};
/// # `GET /_matrix/client/r0/capabilities`
///
/// Get information on the supported feature set and other relevent capabilities of this server.
/// Get information on the supported feature set and other relevent capabilities
/// of this server.
pub(crate) async fn get_capabilities_route(
_body: Ruma<get_capabilities::v3::Request>,
) -> Result<get_capabilities::v3::Response> {
@ -24,5 +27,7 @@ pub(crate) async fn get_capabilities_route(
available,
};
Ok(get_capabilities::v3::Response { capabilities })
Ok(get_capabilities::v3::Response {
capabilities,
})
}

View file

@ -1,18 +1,21 @@
use crate::{services, Error, Result, Ruma};
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,
},
error::ErrorKind,
},
events::{AnyGlobalAccountDataEventContent, AnyRoomAccountDataEventContent},
events::{
AnyGlobalAccountDataEventContent, AnyRoomAccountDataEventContent,
},
serde::Raw,
};
use serde::Deserialize;
use serde_json::{json, value::RawValue as RawJsonValue};
use crate::{services, Error, Result, Ruma};
/// # `PUT /_matrix/client/r0/user/{userId}/account_data/{type}`
///
/// Sets some account data for the sender user.
@ -22,7 +25,9 @@ pub(crate) async fn set_global_account_data_route(
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let data: serde_json::Value = serde_json::from_str(body.data.json().get())
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Data is invalid."))?;
.map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Data is invalid.")
})?;
let event_type = body.event_type.to_string();
@ -48,7 +53,9 @@ pub(crate) async fn set_room_account_data_route(
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let data: serde_json::Value = serde_json::from_str(body.data.json().get())
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Data is invalid."))?;
.map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Data is invalid.")
})?;
let event_type = body.event_type.to_string();
@ -78,11 +85,16 @@ pub(crate) async fn get_global_account_data_route(
.get(None, sender_user, body.event_type.to_string().into())?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?;
let account_data = serde_json::from_str::<ExtractGlobalEventContent>(event.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))?
.content;
let account_data =
serde_json::from_str::<ExtractGlobalEventContent>(event.get())
.map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})?
.content;
Ok(get_global_account_data::v3::Response { account_data })
Ok(get_global_account_data::v3::Response {
account_data,
})
}
/// # `GET /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}`
@ -98,11 +110,16 @@ pub(crate) async fn get_room_account_data_route(
.get(Some(&body.room_id), sender_user, body.event_type.clone())?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?;
let account_data = serde_json::from_str::<ExtractRoomEventContent>(event.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))?
.content;
let account_data =
serde_json::from_str::<ExtractRoomEventContent>(event.get())
.map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})?
.content;
Ok(get_room_account_data::v3::Response { account_data })
Ok(get_room_account_data::v3::Response {
account_data,
})
}
#[derive(Deserialize)]

View file

@ -1,60 +1,57 @@
use crate::{services, Error, Result, Ruma};
use std::collections::HashSet;
use ruma::{
api::client::{context::get_context, error::ErrorKind, filter::LazyLoadOptions},
api::client::{
context::get_context, error::ErrorKind, filter::LazyLoadOptions,
},
events::StateEventType,
uint,
};
use std::collections::HashSet;
use tracing::error;
use crate::{services, Error, Result, Ruma};
/// # `GET /_matrix/client/r0/rooms/{roomId}/context`
///
/// Allows loading room history around an event.
///
/// - Only works if the user is joined (TODO: always allow, but only show events if the user was
/// - Only works if the user is joined (TODO: always allow, but only show events
/// if the user was
/// joined, depending on `history_visibility`)
#[allow(clippy::too_many_lines)]
pub(crate) async fn get_context_route(
body: Ruma<get_context::v3::Request>,
) -> Result<get_context::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");
let sender_device =
body.sender_device.as_ref().expect("user is authenticated");
let (lazy_load_enabled, lazy_load_send_redundant) = match &body.filter.lazy_load_options {
LazyLoadOptions::Enabled {
include_redundant_members,
} => (true, *include_redundant_members),
LazyLoadOptions::Disabled => (false, false),
};
let (lazy_load_enabled, lazy_load_send_redundant) =
match &body.filter.lazy_load_options {
LazyLoadOptions::Enabled {
include_redundant_members,
} => (true, *include_redundant_members),
LazyLoadOptions::Disabled => (false, false),
};
let mut lazy_loaded = HashSet::new();
let base_token = services()
.rooms
.timeline
.get_pdu_count(&body.event_id)?
.ok_or(Error::BadRequest(
ErrorKind::NotFound,
"Base event id not found.",
))?;
let base_token =
services().rooms.timeline.get_pdu_count(&body.event_id)?.ok_or(
Error::BadRequest(ErrorKind::NotFound, "Base event id not found."),
)?;
let base_event =
services()
.rooms
.timeline
.get_pdu(&body.event_id)?
.ok_or(Error::BadRequest(
ErrorKind::NotFound,
"Base event not found.",
))?;
let base_event = services().rooms.timeline.get_pdu(&body.event_id)?.ok_or(
Error::BadRequest(ErrorKind::NotFound, "Base event not found."),
)?;
let room_id = base_event.room_id.clone();
if !services()
.rooms
.state_accessor
.user_can_see_event(sender_user, &room_id, &body.event_id)?
{
if !services().rooms.state_accessor.user_can_see_event(
sender_user,
&room_id,
&body.event_id,
)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this event.",
@ -72,8 +69,8 @@ pub(crate) async fn get_context_route(
}
// Use limit with maximum 100
let half_limit =
usize::try_from(body.limit.min(uint!(100)) / uint!(2)).expect("0-50 should fit in usize");
let half_limit = usize::try_from(body.limit.min(uint!(100)) / uint!(2))
.expect("0-50 should fit in usize");
let base_event = base_event.to_room_event();
@ -108,10 +105,8 @@ pub(crate) async fn get_context_route(
.last()
.map_or_else(|| base_token.stringify(), |(count, _)| count.stringify());
let events_before: Vec<_> = events_before
.into_iter()
.map(|(_, pdu)| pdu.to_room_event())
.collect();
let events_before: Vec<_> =
events_before.into_iter().map(|(_, pdu)| pdu.to_room_event()).collect();
let events_after: Vec<_> = services()
.rooms
@ -140,41 +135,33 @@ pub(crate) async fn get_context_route(
}
}
let shortstatehash = match services().rooms.state_accessor.pdu_shortstatehash(
events_after
.last()
.map_or(&*body.event_id, |(_, e)| &*e.event_id),
)? {
Some(s) => s,
None => services()
.rooms
.state
.get_room_shortstatehash(&room_id)?
.expect("All rooms have state"),
};
let shortstatehash =
match services().rooms.state_accessor.pdu_shortstatehash(
events_after.last().map_or(&*body.event_id, |(_, e)| &*e.event_id),
)? {
Some(s) => s,
None => services()
.rooms
.state
.get_room_shortstatehash(&room_id)?
.expect("All rooms have state"),
};
let state_ids = services()
.rooms
.state_accessor
.state_full_ids(shortstatehash)
.await?;
let state_ids =
services().rooms.state_accessor.state_full_ids(shortstatehash).await?;
let end_token = events_after
.last()
.map_or_else(|| base_token.stringify(), |(count, _)| count.stringify());
let events_after: Vec<_> = events_after
.into_iter()
.map(|(_, pdu)| pdu.to_room_event())
.collect();
let events_after: Vec<_> =
events_after.into_iter().map(|(_, pdu)| pdu.to_room_event()).collect();
let mut state = Vec::new();
for (shortstatekey, id) in state_ids {
let (event_type, state_key) = services()
.rooms
.short
.get_statekey_from_short(shortstatekey)?;
let (event_type, state_key) =
services().rooms.short.get_statekey_from_short(shortstatekey)?;
if event_type != StateEventType::RoomMember {
let Some(pdu) = services().rooms.timeline.get_pdu(&id)? else {

View file

@ -1,11 +1,14 @@
use crate::{services, utils, Error, Result, Ruma};
use ruma::api::client::{
device::{self, delete_device, delete_devices, get_device, get_devices, update_device},
device::{
self, delete_device, delete_devices, get_device, get_devices,
update_device,
},
error::ErrorKind,
uiaa::{AuthFlow, AuthType, UiaaInfo},
};
use super::SESSION_ID_LENGTH;
use crate::{services, utils, Error, Result, Ruma};
/// # `GET /_matrix/client/r0/devices`
///
@ -21,7 +24,9 @@ pub(crate) async fn get_devices_route(
.filter_map(Result::ok)
.collect();
Ok(get_devices::v3::Response { devices })
Ok(get_devices::v3::Response {
devices,
})
}
/// # `GET /_matrix/client/r0/devices/{deviceId}`
@ -37,7 +42,9 @@ pub(crate) async fn get_device_route(
.get_device_metadata(sender_user, &body.body.device_id)?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Device not found."))?;
Ok(get_device::v3::Response { device })
Ok(get_device::v3::Response {
device,
})
}
/// # `PUT /_matrix/client/r0/devices/{deviceId}`
@ -55,9 +62,11 @@ pub(crate) async fn update_device_route(
device.display_name = body.display_name.clone();
services()
.users
.update_device_metadata(sender_user, &body.device_id, &device)?;
services().users.update_device_metadata(
sender_user,
&body.device_id,
&device,
)?;
Ok(update_device::v3::Response {})
}
@ -68,14 +77,16 @@ pub(crate) async fn update_device_route(
///
/// - Requires UIAA to verify user password
/// - Invalidates access token
/// - Deletes device metadata (device id, device display name, last seen ip, last seen ts)
/// - Deletes device metadata (device id, device display name, last seen ip,
/// last seen ts)
/// - Forgets to-device events
/// - Triggers device list updates
pub(crate) async fn delete_device_route(
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");
let sender_device =
body.sender_device.as_ref().expect("user is authenticated");
// UIAA
let mut uiaainfo = UiaaInfo {
@ -89,27 +100,25 @@ pub(crate) async fn delete_device_route(
};
if let Some(auth) = &body.auth {
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
let (worked, uiaainfo) = services().uiaa.try_auth(
sender_user,
sender_device,
auth,
&uiaainfo,
)?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
// Success!
} else if let Some(json) = body.json_body {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services()
.uiaa
.create(sender_user, sender_device, &uiaainfo, &json)?;
services().uiaa.create(sender_user, sender_device, &uiaainfo, &json)?;
return Err(Error::Uiaa(uiaainfo));
} else {
return Err(Error::BadRequest(ErrorKind::NotJson, "Not json."));
}
services()
.users
.remove_device(sender_user, &body.device_id)?;
services().users.remove_device(sender_user, &body.device_id)?;
Ok(delete_device::v3::Response {})
}
@ -122,14 +131,16 @@ pub(crate) async fn delete_device_route(
///
/// For each device:
/// - Invalidates access token
/// - Deletes device metadata (device id, device display name, last seen ip, last seen ts)
/// - Deletes device metadata (device id, device display name, last seen ip,
/// last seen ts)
/// - Forgets to-device events
/// - Triggers device list updates
pub(crate) async fn delete_devices_route(
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");
let sender_device =
body.sender_device.as_ref().expect("user is authenticated");
// UIAA
let mut uiaainfo = UiaaInfo {
@ -143,19 +154,19 @@ pub(crate) async fn delete_devices_route(
};
if let Some(auth) = &body.auth {
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
let (worked, uiaainfo) = services().uiaa.try_auth(
sender_user,
sender_device,
auth,
&uiaainfo,
)?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
// Success!
} else if let Some(json) = body.json_body {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services()
.uiaa
.create(sender_user, sender_device, &uiaainfo, &json)?;
services().uiaa.create(sender_user, sender_device, &uiaainfo, &json)?;
return Err(Error::Uiaa(uiaainfo));
} else {
return Err(Error::BadRequest(ErrorKind::NotJson, "Not json."));

View file

@ -1,10 +1,9 @@
use crate::{services, Error, Result, Ruma};
use ruma::{
api::{
client::{
directory::{
get_public_rooms, get_public_rooms_filtered, get_room_visibility,
set_room_visibility,
get_public_rooms, get_public_rooms_filtered,
get_room_visibility, set_room_visibility,
},
error::ErrorKind,
room,
@ -18,7 +17,9 @@ use ruma::{
canonical_alias::RoomCanonicalAliasEventContent,
create::RoomCreateEventContent,
guest_access::{GuestAccess, RoomGuestAccessEventContent},
history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
history_visibility::{
HistoryVisibility, RoomHistoryVisibilityEventContent,
},
join_rules::{JoinRule, RoomJoinRulesEventContent},
topic::RoomTopicEventContent,
},
@ -28,6 +29,8 @@ use ruma::{
};
use tracing::{error, info, warn};
use crate::{services, Error, Result, Ruma};
/// # `POST /_matrix/client/r0/publicRooms`
///
/// Lists the public rooms on this server.
@ -91,7 +94,9 @@ pub(crate) async fn set_room_visibility_route(
services().rooms.directory.set_public(&body.room_id)?;
info!("{} made {} public", sender_user, 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,
@ -115,7 +120,11 @@ pub(crate) async fn get_room_visibility_route(
}
Ok(get_room_visibility::v3::Response {
visibility: if services().rooms.directory.is_public_room(&body.room_id)? {
visibility: if services()
.rooms
.directory
.is_public_room(&body.room_id)?
{
room::Visibility::Public
} else {
room::Visibility::Private
@ -131,8 +140,8 @@ pub(crate) async fn get_public_rooms_filtered_helper(
filter: &Filter,
_network: &RoomNetwork,
) -> Result<get_public_rooms_filtered::v3::Response> {
if let Some(other_server) =
server.filter(|server| *server != services().globals.server_name().as_str())
if let Some(other_server) = server
.filter(|server| *server != services().globals.server_name().as_str())
{
let response = services()
.sending
@ -174,10 +183,9 @@ pub(crate) async fn get_public_rooms_filtered_helper(
}
};
num_since = characters
.collect::<String>()
.parse()
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `since` token."))?;
num_since = characters.collect::<String>().parse().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Invalid `since` token.")
})?;
if backwards {
num_since = num_since.saturating_sub(limit);
@ -195,12 +203,19 @@ pub(crate) async fn get_public_rooms_filtered_helper(
canonical_alias: services()
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomCanonicalAlias, "")?
.room_state_get(
&room_id,
&StateEventType::RoomCanonicalAlias,
"",
)?
.map_or(Ok(None), |s| {
serde_json::from_str(s.content.get())
.map(|c: RoomCanonicalAliasEventContent| c.alias)
.map_err(|_| {
Error::bad_database("Invalid canonical alias event in database.")
Error::bad_database(
"Invalid canonical alias event in \
database.",
)
})
})?,
name: services().rooms.state_accessor.get_name(&room_id)?,
@ -222,36 +237,55 @@ pub(crate) async fn get_public_rooms_filtered_helper(
serde_json::from_str(s.content.get())
.map(|c: RoomTopicEventContent| Some(c.topic))
.map_err(|_| {
error!("Invalid room topic event in database for room {}", room_id);
Error::bad_database("Invalid room topic event in database.")
error!(
"Invalid room topic event in database for \
room {}",
room_id
);
Error::bad_database(
"Invalid room topic event in database.",
)
})
})?,
world_readable: services()
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomHistoryVisibility, "")?
.room_state_get(
&room_id,
&StateEventType::RoomHistoryVisibility,
"",
)?
.map_or(Ok(false), |s| {
serde_json::from_str(s.content.get())
.map(|c: RoomHistoryVisibilityEventContent| {
c.history_visibility == HistoryVisibility::WorldReadable
c.history_visibility
== HistoryVisibility::WorldReadable
})
.map_err(|_| {
Error::bad_database(
"Invalid room history visibility event in database.",
"Invalid room history visibility event in \
database.",
)
})
})?,
guest_can_join: services()
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomGuestAccess, "")?
.room_state_get(
&room_id,
&StateEventType::RoomGuestAccess,
"",
)?
.map_or(Ok(false), |s| {
serde_json::from_str(s.content.get())
.map(|c: RoomGuestAccessEventContent| {
c.guest_access == GuestAccess::CanJoin
})
.map_err(|_| {
Error::bad_database("Invalid room guest access event in database.")
Error::bad_database(
"Invalid room guest access event in \
database.",
)
})
})?,
avatar_url: services()
@ -262,7 +296,9 @@ pub(crate) async fn get_public_rooms_filtered_helper(
serde_json::from_str(s.content.get())
.map(|c: RoomAvatarEventContent| c.url)
.map_err(|_| {
Error::bad_database("Invalid room avatar event in database.")
Error::bad_database(
"Invalid room avatar event in database.",
)
})
})
.transpose()?
@ -270,33 +306,59 @@ pub(crate) async fn get_public_rooms_filtered_helper(
join_rule: services()
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomJoinRules, "")?
.room_state_get(
&room_id,
&StateEventType::RoomJoinRules,
"",
)?
.map(|s| {
serde_json::from_str(s.content.get())
.map(|c: RoomJoinRulesEventContent| match c.join_rule {
JoinRule::Public => Some(PublicRoomJoinRule::Public),
JoinRule::Knock => Some(PublicRoomJoinRule::Knock),
_ => None,
.map(|c: RoomJoinRulesEventContent| {
match c.join_rule {
JoinRule::Public => {
Some(PublicRoomJoinRule::Public)
}
JoinRule::Knock => {
Some(PublicRoomJoinRule::Knock)
}
_ => None,
}
})
.map_err(|e| {
error!("Invalid room join rule event in database: {}", e);
Error::BadDatabase("Invalid room join rule event in database.")
error!(
"Invalid room join rule event in \
database: {}",
e
);
Error::BadDatabase(
"Invalid room join rule event in database.",
)
})
})
.transpose()?
.flatten()
.ok_or_else(|| Error::bad_database("Missing room join rule event for room."))?,
.ok_or_else(|| {
Error::bad_database(
"Missing room join rule event for room.",
)
})?,
room_type: services()
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomCreate, "")?
.map(|s| {
serde_json::from_str::<RoomCreateEventContent>(s.content.get()).map_err(
|e| {
error!("Invalid room create event in database: {}", e);
Error::BadDatabase("Invalid room create event in database.")
},
serde_json::from_str::<RoomCreateEventContent>(
s.content.get(),
)
.map_err(|e| {
error!(
"Invalid room create event in database: {}",
e
);
Error::BadDatabase(
"Invalid room create event in database.",
)
})
})
.transpose()?
.and_then(|e| e.room_type),
@ -306,10 +368,8 @@ pub(crate) async fn get_public_rooms_filtered_helper(
})
.filter_map(Result::<_>::ok)
.filter(|chunk| {
if let Some(query) = filter
.generic_search_term
.as_ref()
.map(|q| q.to_lowercase())
if let Some(query) =
filter.generic_search_term.as_ref().map(|q| q.to_lowercase())
{
if let Some(name) = &chunk.name {
if name.as_str().to_lowercase().contains(&query) {
@ -324,7 +384,8 @@ pub(crate) async fn get_public_rooms_filtered_helper(
}
if let Some(canonical_alias) = &chunk.canonical_alias {
if canonical_alias.as_str().to_lowercase().contains(&query) {
if canonical_alias.as_str().to_lowercase().contains(&query)
{
return true;
}
}
@ -339,7 +400,8 @@ pub(crate) async fn get_public_rooms_filtered_helper(
all_rooms.sort_by(|l, r| r.num_joined_members.cmp(&l.num_joined_members));
let total_room_count_estimate = all_rooms.len().try_into().unwrap_or(UInt::MAX);
let total_room_count_estimate =
all_rooms.len().try_into().unwrap_or(UInt::MAX);
let chunk: Vec<_> = all_rooms
.into_iter()
@ -353,11 +415,12 @@ pub(crate) async fn get_public_rooms_filtered_helper(
Some(format!("p{num_since}"))
};
let next_batch = if chunk.len() < limit.try_into().expect("UInt should fit in usize") {
None
} else {
Some(format!("n{}", num_since + limit))
};
let next_batch =
if chunk.len() < limit.try_into().expect("UInt should fit in usize") {
None
} else {
Some(format!("n{}", num_since + limit))
};
Ok(get_public_rooms_filtered::v3::Response {
chunk,

View file

@ -1,9 +1,10 @@
use crate::{services, Error, Result, Ruma};
use ruma::api::client::{
error::ErrorKind,
filter::{create_filter, get_filter},
};
use crate::{services, Error, Result, Ruma};
/// # `GET /_matrix/client/r0/user/{userId}/filter/{filterId}`
///
/// Loads a filter that was previously created.
@ -13,8 +14,13 @@ pub(crate) async fn get_filter_route(
body: Ruma<get_filter::v3::Request>,
) -> Result<get_filter::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let Some(filter) = services().users.get_filter(sender_user, &body.filter_id)? else {
return Err(Error::BadRequest(ErrorKind::NotFound, "Filter not found."));
let Some(filter) =
services().users.get_filter(sender_user, &body.filter_id)?
else {
return Err(Error::BadRequest(
ErrorKind::NotFound,
"Filter not found.",
));
};
Ok(get_filter::v3::Response::new(filter))

View file

@ -1,13 +1,16 @@
use super::SESSION_ID_LENGTH;
use crate::{services, utils, Error, Result, Ruma};
use std::{
collections::{hash_map, BTreeMap, HashMap, HashSet},
time::{Duration, Instant},
};
use futures_util::{stream::FuturesUnordered, StreamExt};
use ruma::{
api::{
client::{
error::ErrorKind,
keys::{
claim_keys, get_key_changes, get_keys, upload_keys, upload_signatures,
upload_signing_keys,
claim_keys, get_key_changes, get_keys, upload_keys,
upload_signatures, upload_signing_keys,
},
uiaa::{AuthFlow, AuthType, UiaaInfo},
},
@ -17,28 +20,32 @@ use ruma::{
DeviceKeyAlgorithm, OwnedDeviceId, OwnedUserId, UserId,
};
use serde_json::json;
use std::{
collections::{hash_map, BTreeMap, HashMap, HashSet},
time::{Duration, Instant},
};
use tracing::debug;
use super::SESSION_ID_LENGTH;
use crate::{services, utils, Error, Result, Ruma};
/// # `POST /_matrix/client/r0/keys/upload`
///
/// Publish end-to-end encryption keys for the sender device.
///
/// - Adds one time keys
/// - If there are no device keys yet: Adds device keys (TODO: merge with existing keys?)
/// - If there are no device keys yet: Adds device keys (TODO: merge with
/// existing keys?)
pub(crate) async fn upload_keys_route(
body: Ruma<upload_keys::v3::Request>,
) -> Result<upload_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");
let sender_device =
body.sender_device.as_ref().expect("user is authenticated");
for (key_key, key_value) in &body.one_time_keys {
services()
.users
.add_one_time_key(sender_user, sender_device, key_key, key_value)?;
services().users.add_one_time_key(
sender_user,
sender_device,
key_key,
key_value,
)?;
}
if let Some(device_keys) = &body.device_keys {
@ -49,9 +56,11 @@ pub(crate) async fn upload_keys_route(
.get_device_keys(sender_user, sender_device)?
.is_none()
{
services()
.users
.add_device_keys(sender_user, sender_device, device_keys)?;
services().users.add_device_keys(
sender_user,
sender_device,
device_keys,
)?;
}
}
@ -68,14 +77,17 @@ pub(crate) async fn upload_keys_route(
///
/// - Always fetches users from other servers over federation
/// - Gets master keys, self-signing keys, user signing keys and device keys.
/// - The master and self-signing keys contain signatures that the user is allowed to see
/// - The master and self-signing keys contain signatures that the user is
/// allowed to see
pub(crate) async fn get_keys_route(
body: Ruma<get_keys::v3::Request>,
) -> Result<get_keys::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let response =
get_keys_helper(Some(sender_user), &body.device_keys, |u| u == sender_user).await?;
let response = get_keys_helper(Some(sender_user), &body.device_keys, |u| {
u == sender_user
})
.await?;
Ok(response)
}
@ -100,7 +112,8 @@ pub(crate) async fn upload_signing_keys_route(
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");
let sender_device =
body.sender_device.as_ref().expect("user is authenticated");
// UIAA
let mut uiaainfo = UiaaInfo {
@ -114,19 +127,19 @@ pub(crate) async fn upload_signing_keys_route(
};
if let Some(auth) = &body.auth {
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
let (worked, uiaainfo) = services().uiaa.try_auth(
sender_user,
sender_device,
auth,
&uiaainfo,
)?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
// Success!
} else if let Some(json) = body.json_body {
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services()
.uiaa
.create(sender_user, sender_device, &uiaainfo, &json)?;
services().uiaa.create(sender_user, sender_device, &uiaainfo, &json)?;
return Err(Error::Uiaa(uiaainfo));
} else {
return Err(Error::BadRequest(ErrorKind::NotJson, "Not json."));
@ -156,8 +169,9 @@ pub(crate) async fn upload_signatures_route(
for (user_id, keys) in &body.signed_keys {
for (key_id, key) in keys {
let key = serde_json::to_value(key)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid key JSON"))?;
let key = serde_json::to_value(key).map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Invalid key JSON")
})?;
for signature in key
.get("signatures")
@ -189,9 +203,12 @@ pub(crate) async fn upload_signatures_route(
))?
.to_owned(),
);
services()
.users
.sign_key(user_id, key_id, signature, sender_user)?;
services().users.sign_key(
user_id,
key_id,
signature,
sender_user,
)?;
}
}
}
@ -204,7 +221,8 @@ pub(crate) async fn upload_signatures_route(
/// # `POST /_matrix/client/r0/keys/changes`
///
/// Gets a list of users who have updated their device identity keys since the previous sync token.
/// Gets a list of users who have updated their device identity keys since the
/// previous sync token.
///
/// - TODO: left users
pub(crate) async fn get_key_changes_route(
@ -219,14 +237,15 @@ pub(crate) async fn get_key_changes_route(
.users
.keys_changed(
sender_user.as_str(),
body.from
.parse()
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `from`."))?,
Some(
body.to
.parse()
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `to`."))?,
),
body.from.parse().map_err(|_| {
Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid `from`.",
)
})?,
Some(body.to.parse().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Invalid `to`.")
})?),
)
.filter_map(Result::ok),
);
@ -243,10 +262,16 @@ pub(crate) async fn get_key_changes_route(
.keys_changed(
room_id.as_ref(),
body.from.parse().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Invalid `from`.")
Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid `from`.",
)
})?,
Some(body.to.parse().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Invalid `to`.")
Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid `to`.",
)
})?),
)
.filter_map(Result::ok),
@ -287,16 +312,24 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
let mut container = BTreeMap::new();
for device_id in services().users.all_device_ids(user_id) {
let device_id = device_id?;
if let Some(mut keys) = services().users.get_device_keys(user_id, &device_id)? {
if let Some(mut keys) =
services().users.get_device_keys(user_id, &device_id)?
{
let metadata = services()
.users
.get_device_metadata(user_id, &device_id)?
.ok_or_else(|| {
Error::bad_database("all_device_keys contained nonexistent device.")
Error::bad_database(
"all_device_keys contained nonexistent device.",
)
})?;
add_unsigned_device_display_name(&mut keys, metadata)
.map_err(|_| Error::bad_database("invalid device keys in database"))?;
.map_err(|_| {
Error::bad_database(
"invalid device keys in database",
)
})?;
container.insert(device_id, keys);
}
}
@ -304,7 +337,9 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
} else {
for device_id in device_ids {
let mut container = BTreeMap::new();
if let Some(mut keys) = services().users.get_device_keys(user_id, device_id)? {
if let Some(mut keys) =
services().users.get_device_keys(user_id, device_id)?
{
let metadata = services()
.users
.get_device_metadata(user_id, device_id)?
@ -314,29 +349,35 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
))?;
add_unsigned_device_display_name(&mut keys, metadata)
.map_err(|_| Error::bad_database("invalid device keys in database"))?;
.map_err(|_| {
Error::bad_database(
"invalid device keys in database",
)
})?;
container.insert(device_id.to_owned(), keys);
}
device_keys.insert(user_id.to_owned(), container);
}
}
if let Some(master_key) =
services()
.users
.get_master_key(sender_user, user_id, &allowed_signatures)?
{
if let Some(master_key) = services().users.get_master_key(
sender_user,
user_id,
&allowed_signatures,
)? {
master_keys.insert(user_id.to_owned(), master_key);
}
if let Some(self_signing_key) =
services()
.users
.get_self_signing_key(sender_user, user_id, &allowed_signatures)?
{
if let Some(self_signing_key) = services().users.get_self_signing_key(
sender_user,
user_id,
&allowed_signatures,
)? {
self_signing_keys.insert(user_id.to_owned(), self_signing_key);
}
if Some(user_id) == sender_user {
if let Some(user_signing_key) = services().users.get_user_signing_key(user_id)? {
if let Some(user_signing_key) =
services().users.get_user_signing_key(user_id)?
{
user_signing_keys.insert(user_id.to_owned(), user_signing_key);
}
}
@ -345,17 +386,13 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
let mut failures = BTreeMap::new();
let back_off = |id| async {
match services()
.globals
.bad_query_ratelimiter
.write()
.await
.entry(id)
{
match services().globals.bad_query_ratelimiter.write().await.entry(id) {
hash_map::Entry::Vacant(e) => {
e.insert((Instant::now(), 1));
}
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
hash_map::Entry::Occupied(mut e) => {
*e.get_mut() = (Instant::now(), e.get().1 + 1);
}
}
};
@ -370,7 +407,8 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
.get(server)
{
// Exponential backoff
let mut min_elapsed_duration = Duration::from_secs(30) * (*tries) * (*tries);
let mut min_elapsed_duration =
Duration::from_secs(30) * (*tries) * (*tries);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
}
@ -379,7 +417,9 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
debug!("Backing off query from {:?}", server);
return (
server,
Err(Error::BadServerResponse("bad query, still backing off")),
Err(Error::BadServerResponse(
"bad query, still backing off",
)),
);
}
}
@ -417,15 +457,19 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
&user,
&allowed_signatures,
)? {
let (_, our_master_key) =
services().users.parse_master_key(&user, &our_master_key)?;
let (_, our_master_key) = services()
.users
.parse_master_key(&user, &our_master_key)?;
master_key.signatures.extend(our_master_key.signatures);
}
let json = serde_json::to_value(master_key).expect("to_value always works");
let raw = serde_json::from_value(json).expect("Raw::from_value always works");
let json = serde_json::to_value(master_key)
.expect("to_value always works");
let raw = serde_json::from_value(json)
.expect("Raw::from_value always works");
services().users.add_cross_signing_keys(
&user, &raw, &None, &None,
// Dont notify. A notification would trigger another key request resulting in an endless loop
// Dont notify. A notification would trigger another key
// request resulting in an endless loop
false,
)?;
master_keys.insert(user, raw);
@ -454,11 +498,13 @@ fn add_unsigned_device_display_name(
metadata: ruma::api::client::device::Device,
) -> serde_json::Result<()> {
if let Some(display_name) = metadata.display_name {
let mut object = keys.deserialize_as::<serde_json::Map<String, serde_json::Value>>()?;
let mut object = keys
.deserialize_as::<serde_json::Map<String, serde_json::Value>>()?;
let unsigned = object.entry("unsigned").or_insert_with(|| json!({}));
if let serde_json::Value::Object(unsigned_object) = unsigned {
unsigned_object.insert("device_display_name".to_owned(), display_name.into());
unsigned_object
.insert("device_display_name".to_owned(), display_name.into());
}
*keys = Raw::from_json(serde_json::value::to_raw_value(&object)?);
@ -468,7 +514,10 @@ fn add_unsigned_device_display_name(
}
pub(crate) async fn claim_keys_helper(
one_time_keys_input: &BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, DeviceKeyAlgorithm>>,
one_time_keys_input: &BTreeMap<
OwnedUserId,
BTreeMap<OwnedDeviceId, DeviceKeyAlgorithm>,
>,
) -> Result<claim_keys::v3::Response> {
let mut one_time_keys = BTreeMap::new();
@ -484,11 +533,11 @@ pub(crate) async fn claim_keys_helper(
let mut container = BTreeMap::new();
for (device_id, key_algorithm) in map {
if let Some(one_time_keys) =
services()
.users
.take_one_time_key(user_id, device_id, key_algorithm)?
{
if let Some(one_time_keys) = services().users.take_one_time_key(
user_id,
device_id,
key_algorithm,
)? {
let mut c = BTreeMap::new();
c.insert(one_time_keys.0, one_time_keys.1);
container.insert(device_id.clone(), c);

View file

@ -1,14 +1,15 @@
use std::time::Duration;
use crate::{service::media::FileMeta, services, utils, Error, Result, Ruma};
use ruma::api::client::{
error::ErrorKind,
media::{
create_content, get_content, get_content_as_filename, get_content_thumbnail,
get_media_config,
create_content, get_content, get_content_as_filename,
get_content_thumbnail, get_media_config,
},
};
use crate::{service::media::FileMeta, services, utils, Error, Result, Ruma};
const MXC_LENGTH: usize = 32;
/// # `GET /_matrix/media/r0/config`
@ -110,9 +111,12 @@ pub(crate) async fn get_content_route(
content_disposition,
cross_origin_resource_policy: Some("cross-origin".to_owned()),
})
} else if &*body.server_name != services().globals.server_name() && body.allow_remote {
} else if &*body.server_name != services().globals.server_name()
&& body.allow_remote
{
let remote_content_response =
get_remote_content(&mxc, &body.server_name, body.media_id.clone()).await?;
get_remote_content(&mxc, &body.server_name, body.media_id.clone())
.await?;
Ok(remote_content_response)
} else {
Err(Error::BadRequest(ErrorKind::NotFound, "Media not found."))
@ -130,21 +134,32 @@ pub(crate) async fn get_content_as_filename_route(
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
if let Some(FileMeta {
content_type, file, ..
content_type,
file,
..
}) = services().media.get(mxc.clone()).await?
{
Ok(get_content_as_filename::v3::Response {
file,
content_type,
content_disposition: Some(format!("inline; filename={}", body.filename)),
content_disposition: Some(format!(
"inline; filename={}",
body.filename
)),
cross_origin_resource_policy: Some("cross-origin".to_owned()),
})
} else if &*body.server_name != services().globals.server_name() && body.allow_remote {
} else if &*body.server_name != services().globals.server_name()
&& body.allow_remote
{
let remote_content_response =
get_remote_content(&mxc, &body.server_name, body.media_id.clone()).await?;
get_remote_content(&mxc, &body.server_name, body.media_id.clone())
.await?;
Ok(get_content_as_filename::v3::Response {
content_disposition: Some(format!("inline: filename={}", body.filename)),
content_disposition: Some(format!(
"inline: filename={}",
body.filename
)),
content_type: remote_content_response.content_type,
file: remote_content_response.file,
cross_origin_resource_policy: Some("cross-origin".to_owned()),
@ -165,17 +180,19 @@ pub(crate) async fn get_content_thumbnail_route(
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
if let Some(FileMeta {
content_type, file, ..
content_type,
file,
..
}) = services()
.media
.get_thumbnail(
mxc.clone(),
body.width
.try_into()
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Width is invalid."))?,
body.height
.try_into()
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Width is invalid."))?,
body.width.try_into().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Width is invalid.")
})?,
body.height.try_into().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Width is invalid.")
})?,
)
.await?
{
@ -184,7 +201,9 @@ pub(crate) async fn get_content_thumbnail_route(
content_type,
cross_origin_resource_policy: Some("cross-origin".to_owned()),
})
} else if &*body.server_name != services().globals.server_name() && body.allow_remote {
} else if &*body.server_name != services().globals.server_name()
&& body.allow_remote
{
let get_thumbnail_response = services()
.sending
.send_federation_request(

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,8 @@
use crate::{
service::{pdu::PduBuilder, rooms::timeline::PduCount},
services, utils, Error, Result, Ruma,
use std::{
collections::{BTreeMap, HashSet},
sync::Arc,
};
use ruma::{
api::client::{
error::ErrorKind,
@ -10,18 +11,21 @@ use ruma::{
events::{StateEventType, TimelineEventType},
uint,
};
use std::{
collections::{BTreeMap, HashSet},
sync::Arc,
use crate::{
service::{pdu::PduBuilder, rooms::timeline::PduCount},
services, utils, Error, Result, Ruma,
};
/// # `PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}`
///
/// Send a message event into the room.
///
/// - Is a NOOP if the txn id was already used before and returns the same event id again
/// - Is a NOOP if the txn id was already used before and returns the same event
/// id again
/// - The only requirement for the content is that it has to be valid json
/// - Tries to send the event into the room, auth rules will determine if it is allowed
/// - Tries to send the event into the room, auth rules will determine if it is
/// allowed
pub(crate) async fn send_message_event_route(
body: Ruma<send_message_event::v3::Request>,
) -> Result<send_message_event::v3::Response> {
@ -50,29 +54,37 @@ pub(crate) async fn send_message_event_route(
}
// Check if this is a new transaction id
if let Some(response) =
services()
.transaction_ids
.existing_txnid(sender_user, sender_device, &body.txn_id)?
{
if let Some(response) = services().transaction_ids.existing_txnid(
sender_user,
sender_device,
&body.txn_id,
)? {
// The client might have sent a txnid of the /sendToDevice endpoint
// This txnid has no response associated with it
if response.is_empty() {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Tried to use txn id already used for an incompatible endpoint.",
"Tried to use txn id already used for an incompatible \
endpoint.",
));
}
let event_id = utils::string_from_bytes(&response)
.map_err(|_| Error::bad_database("Invalid txnid bytes in database."))?
.map_err(|_| {
Error::bad_database("Invalid txnid bytes in database.")
})?
.try_into()
.map_err(|_| Error::bad_database("Invalid event id in txnid data."))?;
return Ok(send_message_event::v3::Response { event_id });
.map_err(|_| {
Error::bad_database("Invalid event id in txnid data.")
})?;
return Ok(send_message_event::v3::Response {
event_id,
});
}
let mut unsigned = BTreeMap::new();
unsigned.insert("transaction_id".to_owned(), body.txn_id.to_string().into());
unsigned
.insert("transaction_id".to_owned(), body.txn_id.to_string().into());
let event_id = services()
.rooms
@ -81,7 +93,12 @@ pub(crate) async fn send_message_event_route(
PduBuilder {
event_type: body.event_type.to_string().into(),
content: serde_json::from_str(body.body.body.json().get())
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?,
.map_err(|_| {
Error::BadRequest(
ErrorKind::BadJson,
"Invalid JSON body.",
)
})?,
unsigned: Some(unsigned),
state_key: None,
redacts: None,
@ -101,23 +118,23 @@ pub(crate) async fn send_message_event_route(
drop(state_lock);
Ok(send_message_event::v3::Response::new(
(*event_id).to_owned(),
))
Ok(send_message_event::v3::Response::new((*event_id).to_owned()))
}
/// # `GET /_matrix/client/r0/rooms/{roomId}/messages`
///
/// Allows paginating through room history.
///
/// - Only works if the user is joined (TODO: always allow, but only show events where the user was
/// - Only works if the user is joined (TODO: always allow, but only show events
/// where the user was
/// joined, depending on `history_visibility`)
#[allow(clippy::too_many_lines)]
pub(crate) async fn get_message_events_route(
body: Ruma<get_message_events::v3::Request>,
) -> Result<get_message_events::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");
let sender_device =
body.sender_device.as_ref().expect("user is authenticated");
let from = match body.from.clone() {
Some(from) => PduCount::try_from_string(&from)?,
@ -127,15 +144,17 @@ pub(crate) async fn get_message_events_route(
},
};
let to = body
.to
.as_ref()
.and_then(|t| PduCount::try_from_string(t).ok());
let to = body.to.as_ref().and_then(|t| PduCount::try_from_string(t).ok());
services()
.rooms
.lazy_loading
.lazy_load_confirm_delivery(sender_user, sender_device, &body.room_id, from)
.lazy_load_confirm_delivery(
sender_user,
sender_device,
&body.room_id,
from,
)
.await?;
let limit = body
@ -162,7 +181,11 @@ pub(crate) async fn get_message_events_route(
services()
.rooms
.state_accessor
.user_can_see_event(sender_user, &body.room_id, &pdu.event_id)
.user_can_see_event(
sender_user,
&body.room_id,
&pdu.event_id,
)
.unwrap_or(false)
})
.take_while(|&(k, _)| Some(k) != to)
@ -214,7 +237,11 @@ pub(crate) async fn get_message_events_route(
services()
.rooms
.state_accessor
.user_can_see_event(sender_user, &body.room_id, &pdu.event_id)
.user_can_see_event(
sender_user,
&body.room_id,
&pdu.event_id,
)
.unwrap_or(false)
})
.take_while(|&(k, _)| Some(k) != to)
@ -254,11 +281,13 @@ pub(crate) async fn get_message_events_route(
resp.state = Vec::new();
for ll_id in &lazy_loaded {
if let Some(member_event) = services().rooms.state_accessor.room_state_get(
&body.room_id,
&StateEventType::RoomMember,
ll_id.as_str(),
)? {
if let Some(member_event) =
services().rooms.state_accessor.room_state_get(
&body.room_id,
&StateEventType::RoomMember,
ll_id.as_str(),
)?
{
resp.state.push(member_event.to_state_event());
}
}

View file

@ -1,20 +1,25 @@
use crate::{service::pdu::PduBuilder, services, Error, Result, Ruma};
use std::sync::Arc;
use ruma::{
api::{
client::{
error::ErrorKind,
profile::{
get_avatar_url, get_display_name, get_profile, set_avatar_url, set_display_name,
get_avatar_url, get_display_name, get_profile, set_avatar_url,
set_display_name,
},
},
federation::{self, query::get_profile_information::v1::ProfileField},
},
events::{room::member::RoomMemberEventContent, StateEventType, TimelineEventType},
events::{
room::member::RoomMemberEventContent, StateEventType, TimelineEventType,
},
};
use serde_json::value::to_raw_value;
use std::sync::Arc;
use tracing::warn;
use crate::{service::pdu::PduBuilder, services, Error, Result, Ruma};
/// # `PUT /_matrix/client/r0/profile/{userId}/displayname`
///
/// Updates the displayname.
@ -25,9 +30,7 @@ pub(crate) async fn set_displayname_route(
) -> Result<set_display_name::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
services()
.users
.set_displayname(sender_user, body.displayname.clone())?;
services().users.set_displayname(sender_user, body.displayname.clone())?;
// Send a new membership event and presence update into all joined rooms
let all_rooms_joined: Vec<_> = services()
@ -53,14 +56,18 @@ pub(crate) async fn set_displayname_route(
)?
.ok_or_else(|| {
Error::bad_database(
"Tried to send displayname update for user not in the \
room.",
"Tried to send displayname update for \
user not in the room.",
)
})?
.content
.get(),
)
.map_err(|_| Error::bad_database("Database contains invalid PDU."))?
.map_err(|_| {
Error::bad_database(
"Database contains invalid PDU.",
)
})?
})
.expect("event is valid, we just created it"),
unsigned: None,
@ -88,7 +95,12 @@ pub(crate) async fn set_displayname_route(
if let Err(error) = services()
.rooms
.timeline
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
.build_and_append_pdu(
pdu_builder,
sender_user,
&room_id,
&state_lock,
)
.await
{
warn!(%error, "failed to add PDU");
@ -138,13 +150,9 @@ pub(crate) async fn set_avatar_url_route(
) -> Result<set_avatar_url::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
services()
.users
.set_avatar_url(sender_user, body.avatar_url.clone())?;
services().users.set_avatar_url(sender_user, body.avatar_url.clone())?;
services()
.users
.set_blurhash(sender_user, body.blurhash.clone())?;
services().users.set_blurhash(sender_user, body.blurhash.clone())?;
// Send a new membership event and presence update into all joined rooms
let all_joined_rooms: Vec<_> = services()
@ -170,14 +178,18 @@ pub(crate) async fn set_avatar_url_route(
)?
.ok_or_else(|| {
Error::bad_database(
"Tried to send displayname update for user not in the \
room.",
"Tried to send displayname update for \
user not in the room.",
)
})?
.content
.get(),
)
.map_err(|_| Error::bad_database("Database contains invalid PDU."))?
.map_err(|_| {
Error::bad_database(
"Database contains invalid PDU.",
)
})?
})
.expect("event is valid, we just created it"),
unsigned: None,
@ -205,7 +217,12 @@ pub(crate) async fn set_avatar_url_route(
if let Err(error) = services()
.rooms
.timeline
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
.build_and_append_pdu(
pdu_builder,
sender_user,
&room_id,
&state_lock,
)
.await
{
warn!(%error, "failed to add PDU");
@ -219,7 +236,8 @@ pub(crate) async fn set_avatar_url_route(
///
/// Returns the `avatar_url` and `blurhash` of the user.
///
/// - If user is on another server: Fetches `avatar_url` and `blurhash` over federation
/// - If user is on another server: Fetches `avatar_url` and `blurhash` over
/// federation
pub(crate) async fn get_avatar_url_route(
body: Ruma<get_avatar_url::v3::Request>,
) -> Result<get_avatar_url::v3::Response> {

View file

@ -1,17 +1,18 @@
use crate::{services, Error, Result, Ruma};
use ruma::{
api::client::{
error::ErrorKind,
push::{
delete_pushrule, get_pushers, get_pushrule, get_pushrule_actions, get_pushrule_enabled,
get_pushrules_all, set_pusher, set_pushrule, set_pushrule_actions,
set_pushrule_enabled, RuleScope,
delete_pushrule, get_pushers, get_pushrule, get_pushrule_actions,
get_pushrule_enabled, get_pushrules_all, set_pusher, set_pushrule,
set_pushrule_actions, set_pushrule_enabled, RuleScope,
},
},
events::{push_rules::PushRulesEvent, GlobalAccountDataEventType},
push::{AnyPushRuleRef, InsertPushRuleError, RemovePushRuleError},
};
use crate::{services, Error, Result, Ruma};
/// # `GET /_matrix/client/r0/pushrules`
///
/// Retrieves the push rules event for this user.
@ -71,12 +72,11 @@ 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.",
))
Err(Error::BadRequest(ErrorKind::NotFound, "Push rule not found."))
}
}
@ -109,7 +109,9 @@ pub(crate) async fn set_pushrule_route(
))?;
let mut account_data = serde_json::from_str::<PushRulesEvent>(event.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))?;
.map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})?;
if let Err(error) = account_data.content.global.insert(
body.rule.clone(),
@ -119,16 +121,20 @@ pub(crate) async fn set_pushrule_route(
let err = match error {
InsertPushRuleError::ServerDefaultRuleId => Error::BadRequest(
ErrorKind::InvalidParam,
"Rule IDs starting with a dot are reserved for server-default rules.",
"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(
ErrorKind::InvalidParam,
"Can't place a push rule relatively to a server-default rule.",
),
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.",
@ -147,7 +153,8 @@ pub(crate) async fn set_pushrule_route(
None,
sender_user,
GlobalAccountDataEventType::PushRules.to_string().into(),
&serde_json::to_value(account_data).expect("to json value always works"),
&serde_json::to_value(account_data)
.expect("to json value always works"),
)?;
Ok(set_pushrule::v3::Response {})
@ -193,7 +200,9 @@ pub(crate) async fn get_pushrule_actions_route(
"Push rule not found.",
))?;
Ok(get_pushrule_actions::v3::Response { actions })
Ok(get_pushrule_actions::v3::Response {
actions,
})
}
/// # `PUT /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/actions`
@ -224,7 +233,9 @@ pub(crate) async fn set_pushrule_actions_route(
))?;
let mut account_data = serde_json::from_str::<PushRulesEvent>(event.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))?;
.map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})?;
if account_data
.content
@ -242,7 +253,8 @@ pub(crate) async fn set_pushrule_actions_route(
None,
sender_user,
GlobalAccountDataEventType::PushRules.to_string().into(),
&serde_json::to_value(account_data).expect("to json value always works"),
&serde_json::to_value(account_data)
.expect("to json value always works"),
)?;
Ok(set_pushrule_actions::v3::Response {})
@ -276,7 +288,9 @@ pub(crate) async fn get_pushrule_enabled_route(
))?;
let account_data = serde_json::from_str::<PushRulesEvent>(event.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))?;
.map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})?;
let global = account_data.content.global;
let enabled = global
@ -287,7 +301,9 @@ pub(crate) async fn get_pushrule_enabled_route(
"Push rule not found.",
))?;
Ok(get_pushrule_enabled::v3::Response { enabled })
Ok(get_pushrule_enabled::v3::Response {
enabled,
})
}
/// # `PUT /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/enabled`
@ -318,7 +334,9 @@ pub(crate) async fn set_pushrule_enabled_route(
))?;
let mut account_data = serde_json::from_str::<PushRulesEvent>(event.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))?;
.map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})?;
if account_data
.content
@ -336,7 +354,8 @@ pub(crate) async fn set_pushrule_enabled_route(
None,
sender_user,
GlobalAccountDataEventType::PushRules.to_string().into(),
&serde_json::to_value(account_data).expect("to json value always works"),
&serde_json::to_value(account_data)
.expect("to json value always works"),
)?;
Ok(set_pushrule_enabled::v3::Response {})
@ -370,12 +389,12 @@ pub(crate) async fn delete_pushrule_route(
))?;
let mut account_data = serde_json::from_str::<PushRulesEvent>(event.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))?;
.map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})?;
if let Err(error) = account_data
.content
.global
.remove(body.kind.clone(), &body.rule_id)
if let Err(error) =
account_data.content.global.remove(body.kind.clone(), &body.rule_id)
{
let err = match error {
RemovePushRuleError::ServerDefault => Error::BadRequest(
@ -395,7 +414,8 @@ pub(crate) async fn delete_pushrule_route(
None,
sender_user,
GlobalAccountDataEventType::PushRules.to_string().into(),
&serde_json::to_value(account_data).expect("to json value always works"),
&serde_json::to_value(account_data)
.expect("to json value always works"),
)?;
Ok(delete_pushrule::v3::Response {})
@ -424,9 +444,7 @@ pub(crate) async fn set_pushers_route(
) -> Result<set_pusher::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
services()
.pusher
.set_pusher(sender_user, body.action.clone())?;
services().pusher.set_pusher(sender_user, body.action.clone())?;
Ok(set_pusher::v3::Response::default())
}

View file

@ -1,20 +1,27 @@
use crate::{service::rooms::timeline::PduCount, services, Error, Result, Ruma};
use std::collections::BTreeMap;
use ruma::{
api::client::{error::ErrorKind, read_marker::set_read_marker, receipt::create_receipt},
api::client::{
error::ErrorKind, read_marker::set_read_marker, receipt::create_receipt,
},
events::{
receipt::{ReceiptThread, ReceiptType},
RoomAccountDataEventType,
},
MilliSecondsSinceUnixEpoch,
};
use std::collections::BTreeMap;
use crate::{
service::rooms::timeline::PduCount, services, Error, Result, Ruma,
};
/// # `POST /_matrix/client/r0/rooms/{roomId}/read_markers`
///
/// Sets different types of read markers.
///
/// - Updates fully-read account data event to `fully_read`
/// - If `read_receipt` is set: Update private marker and public read receipt EDU
/// - If `read_receipt` is set: Update private marker and public read receipt
/// EDU
pub(crate) async fn set_read_marker_route(
body: Ruma<set_read_marker::v3::Request>,
) -> Result<set_read_marker::v3::Response> {
@ -30,7 +37,8 @@ pub(crate) async fn set_read_marker_route(
Some(&body.room_id),
sender_user,
RoomAccountDataEventType::FullyRead,
&serde_json::to_value(fully_read_event).expect("to json value always works"),
&serde_json::to_value(fully_read_event)
.expect("to json value always works"),
)?;
}
@ -42,14 +50,9 @@ pub(crate) async fn set_read_marker_route(
}
if let Some(event) = &body.private_read_receipt {
let count = services()
.rooms
.timeline
.get_pdu_count(event)?
.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Event does not exist.",
))?;
let count = services().rooms.timeline.get_pdu_count(event)?.ok_or(
Error::BadRequest(ErrorKind::InvalidParam, "Event does not exist."),
)?;
let count = match count {
PduCount::Backfilled(_) => {
return Err(Error::BadRequest(
@ -59,11 +62,11 @@ pub(crate) async fn set_read_marker_route(
}
PduCount::Normal(c) => c,
};
services()
.rooms
.edus
.read_receipt
.private_read_set(&body.room_id, sender_user, count)?;
services().rooms.edus.read_receipt.private_read_set(
&body.room_id,
sender_user,
count,
)?;
}
if let Some(event) = &body.read_receipt {
@ -86,7 +89,9 @@ pub(crate) async fn set_read_marker_route(
sender_user,
&body.room_id,
ruma::events::receipt::ReceiptEvent {
content: ruma::events::receipt::ReceiptEventContent(receipt_content),
content: ruma::events::receipt::ReceiptEventContent(
receipt_content,
),
room_id: body.room_id.clone(),
},
)?;
@ -105,7 +110,8 @@ pub(crate) async fn create_receipt_route(
if matches!(
&body.receipt_type,
create_receipt::v3::ReceiptType::Read | create_receipt::v3::ReceiptType::ReadPrivate
create_receipt::v3::ReceiptType::Read
| create_receipt::v3::ReceiptType::ReadPrivate
) {
services()
.rooms
@ -124,7 +130,8 @@ pub(crate) async fn create_receipt_route(
Some(&body.room_id),
sender_user,
RoomAccountDataEventType::FullyRead,
&serde_json::to_value(fully_read_event).expect("to json value always works"),
&serde_json::to_value(fully_read_event)
.expect("to json value always works"),
)?;
}
create_receipt::v3::ReceiptType::Read => {
@ -146,7 +153,9 @@ pub(crate) async fn create_receipt_route(
sender_user,
&body.room_id,
ruma::events::receipt::ReceiptEvent {
content: ruma::events::receipt::ReceiptEventContent(receipt_content),
content: ruma::events::receipt::ReceiptEventContent(
receipt_content,
),
room_id: body.room_id.clone(),
},
)?;

View file

@ -1,13 +1,13 @@
use std::sync::Arc;
use crate::{service::pdu::PduBuilder, services, Result, Ruma};
use ruma::{
api::client::redact::redact_event,
events::{room::redaction::RoomRedactionEventContent, TimelineEventType},
};
use serde_json::value::to_raw_value;
use crate::{service::pdu::PduBuilder, services, Result, Ruma};
/// # `PUT /_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}`
///
/// Tries to send a redaction event into the room.
@ -54,5 +54,7 @@ pub(crate) async fn redact_event_route(
drop(state_lock);
let event_id = (*event_id).to_owned();
Ok(redact_event::v3::Response { event_id })
Ok(redact_event::v3::Response {
event_id,
})
}

View file

@ -23,10 +23,7 @@ pub(crate) async fn get_relating_events_with_rel_type_and_event_type_route(
},
};
let to = body
.to
.as_ref()
.and_then(|t| PduCount::try_from_string(t).ok());
let to = body.to.as_ref().and_then(|t| PduCount::try_from_string(t).ok());
// Use limit or else 10, with maximum 100
let limit = body
@ -36,27 +33,22 @@ pub(crate) async fn get_relating_events_with_rel_type_and_event_type_route(
.try_into()
.expect("0-100 should fit in usize");
let res = services()
.rooms
.pdu_metadata
.paginate_relations_with_filter(
sender_user,
&body.room_id,
&body.event_id,
Some(&body.event_type),
Some(&body.rel_type),
from,
to,
limit,
)?;
let res = services().rooms.pdu_metadata.paginate_relations_with_filter(
sender_user,
&body.room_id,
&body.event_id,
Some(&body.event_type),
Some(&body.rel_type),
from,
to,
limit,
)?;
Ok(
get_relating_events_with_rel_type_and_event_type::v1::Response {
chunk: res.chunk,
next_batch: res.next_batch,
prev_batch: res.prev_batch,
},
)
Ok(get_relating_events_with_rel_type_and_event_type::v1::Response {
chunk: res.chunk,
next_batch: res.next_batch,
prev_batch: res.prev_batch,
})
}
/// # `GET /_matrix/client/r0/rooms/{roomId}/relations/{eventId}/{relType}`
@ -74,10 +66,7 @@ pub(crate) async fn get_relating_events_with_rel_type_route(
},
};
let to = body
.to
.as_ref()
.and_then(|t| PduCount::try_from_string(t).ok());
let to = body.to.as_ref().and_then(|t| PduCount::try_from_string(t).ok());
// Use limit or else 10, with maximum 100
let limit = body
@ -87,19 +76,16 @@ pub(crate) async fn get_relating_events_with_rel_type_route(
.try_into()
.expect("0-100 should fit in usize");
let res = services()
.rooms
.pdu_metadata
.paginate_relations_with_filter(
sender_user,
&body.room_id,
&body.event_id,
None,
Some(&body.rel_type),
from,
to,
limit,
)?;
let res = services().rooms.pdu_metadata.paginate_relations_with_filter(
sender_user,
&body.room_id,
&body.event_id,
None,
Some(&body.rel_type),
from,
to,
limit,
)?;
Ok(get_relating_events_with_rel_type::v1::Response {
chunk: res.chunk,
@ -123,10 +109,7 @@ pub(crate) async fn get_relating_events_route(
},
};
let to = body
.to
.as_ref()
.and_then(|t| PduCount::try_from_string(t).ok());
let to = body.to.as_ref().and_then(|t| PduCount::try_from_string(t).ok());
// Use limit or else 10, with maximum 100
let limit = body
@ -136,17 +119,14 @@ pub(crate) async fn get_relating_events_route(
.try_into()
.expect("0-100 should fit in usize");
services()
.rooms
.pdu_metadata
.paginate_relations_with_filter(
sender_user,
&body.room_id,
&body.event_id,
None,
None,
from,
to,
limit,
)
services().rooms.pdu_metadata.paginate_relations_with_filter(
sender_user,
&body.room_id,
&body.event_id,
None,
None,
from,
to,
limit,
)
}

View file

@ -1,14 +1,14 @@
use crate::{services, Error, Result, Ruma};
use ruma::{
api::client::{error::ErrorKind, room::report_content},
events::room::message,
int,
};
use crate::{services, Error, Result, Ruma};
/// # `POST /_matrix/client/r0/rooms/{roomId}/report/{eventId}`
///
/// Reports an inappropriate event to homeserver admins
///
pub(crate) async fn report_event_route(
body: Ruma<report_content::v3::Request>,
) -> Result<report_content::v3::Response> {

View file

@ -1,6 +1,5 @@
use crate::{
api::client_server::invite_helper, service::pdu::PduBuilder, services, Error, Result, Ruma,
};
use std::{cmp::max, collections::BTreeMap, sync::Arc};
use ruma::{
api::client::{
error::ErrorKind,
@ -11,7 +10,9 @@ use ruma::{
canonical_alias::RoomCanonicalAliasEventContent,
create::RoomCreateEventContent,
guest_access::{GuestAccess, RoomGuestAccessEventContent},
history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
history_visibility::{
HistoryVisibility, RoomHistoryVisibilityEventContent,
},
join_rules::{JoinRule, RoomJoinRulesEventContent},
member::{MembershipState, RoomMemberEventContent},
name::RoomNameEventContent,
@ -26,9 +27,13 @@ use ruma::{
CanonicalJsonObject, OwnedRoomAliasId, RoomAliasId, RoomId, RoomVersionId,
};
use serde_json::{json, value::to_raw_value};
use std::{cmp::max, collections::BTreeMap, sync::Arc};
use tracing::{info, warn};
use crate::{
api::client_server::invite_helper, service::pdu::PduBuilder, services,
Error, Result, Ruma,
};
/// # `POST /_matrix/client/r0/createRoom`
///
/// Creates a new room.
@ -79,32 +84,27 @@ pub(crate) async fn create_room_route(
}
let alias: Option<OwnedRoomAliasId> =
body.room_alias_name
.as_ref()
.map_or(Ok(None), |localpart| {
// TODO: Check for invalid characters and maximum length
let alias = RoomAliasId::parse(format!(
"#{}:{}",
localpart,
services().globals.server_name()
))
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid alias."))?;
if services()
.rooms
.alias
.resolve_local_alias(&alias)?
.is_some()
{
Err(Error::BadRequest(
ErrorKind::RoomInUse,
"Room alias already exists.",
))
} else {
Ok(Some(alias))
}
body.room_alias_name.as_ref().map_or(Ok(None), |localpart| {
// TODO: Check for invalid characters and maximum length
let alias = RoomAliasId::parse(format!(
"#{}:{}",
localpart,
services().globals.server_name()
))
.map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Invalid alias.")
})?;
if services().rooms.alias.resolve_local_alias(&alias)?.is_some() {
Err(Error::BadRequest(
ErrorKind::RoomInUse,
"Room alias already exists.",
))
} else {
Ok(Some(alias))
}
})?;
if let Some(alias) = &alias {
if let Some(info) = &body.appservice_info {
if !info.aliases.is_match(alias.as_str()) {
@ -159,7 +159,10 @@ pub(crate) async fn create_room_route(
content.insert(
"creator".into(),
json!(&sender_user).try_into().map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid creation content")
Error::BadRequest(
ErrorKind::BadJson,
"Invalid creation content",
)
})?,
);
}
@ -171,7 +174,10 @@ pub(crate) async fn create_room_route(
content.insert(
"room_version".into(),
json!(room_version.as_str()).try_into().map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid creation content")
Error::BadRequest(
ErrorKind::BadJson,
"Invalid creation content",
)
})?,
);
content
@ -187,20 +193,30 @@ pub(crate) async fn create_room_route(
| RoomVersionId::V7
| RoomVersionId::V8
| RoomVersionId::V9
| RoomVersionId::V10 => RoomCreateEventContent::new_v1(sender_user.clone()),
| RoomVersionId::V10 => {
RoomCreateEventContent::new_v1(sender_user.clone())
}
RoomVersionId::V11 => RoomCreateEventContent::new_v11(),
_ => unreachable!("Validity of room version already checked"),
};
let mut content = serde_json::from_str::<CanonicalJsonObject>(
to_raw_value(&content)
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid creation content"))?
.map_err(|_| {
Error::BadRequest(
ErrorKind::BadJson,
"Invalid creation content",
)
})?
.get(),
)
.unwrap();
content.insert(
"room_version".into(),
json!(room_version.as_str()).try_into().map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Invalid creation content")
Error::BadRequest(
ErrorKind::BadJson,
"Invalid creation content",
)
})?,
);
content
@ -209,9 +225,7 @@ pub(crate) async fn create_room_route(
// Validate creation content
let de_result = serde_json::from_str::<CanonicalJsonObject>(
to_raw_value(&content)
.expect("Invalid creation content")
.get(),
to_raw_value(&content).expect("Invalid creation content").get(),
);
if de_result.is_err() {
@ -228,7 +242,8 @@ pub(crate) async fn create_room_route(
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomCreate,
content: to_raw_value(&content).expect("event is valid, we just created it"),
content: to_raw_value(&content)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(String::new()),
redacts: None,
@ -285,17 +300,24 @@ pub(crate) async fn create_room_route(
}
}
let mut power_levels_content = serde_json::to_value(RoomPowerLevelsEventContent {
users,
..Default::default()
})
.expect("event is valid, we just created it");
let mut power_levels_content =
serde_json::to_value(RoomPowerLevelsEventContent {
users,
..Default::default()
})
.expect("event is valid, we just created it");
if let Some(power_level_content_override) = &body.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.")
})?;
if let Some(power_level_content_override) =
&body.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.",
)
})?;
for (key, value) in json {
power_levels_content[key] = value;
@ -353,11 +375,13 @@ pub(crate) async fn create_room_route(
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomJoinRules,
content: to_raw_value(&RoomJoinRulesEventContent::new(match preset {
RoomPreset::PublicChat => JoinRule::Public,
// according to spec "invite" is the default
_ => JoinRule::Invite,
}))
content: to_raw_value(&RoomJoinRulesEventContent::new(
match preset {
RoomPreset::PublicChat => JoinRule::Public,
// according to spec "invite" is the default
_ => JoinRule::Invite,
},
))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(String::new()),
@ -397,10 +421,12 @@ pub(crate) async fn create_room_route(
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomGuestAccess,
content: to_raw_value(&RoomGuestAccessEventContent::new(match preset {
RoomPreset::PublicChat => GuestAccess::Forbidden,
_ => GuestAccess::CanJoin,
}))
content: to_raw_value(&RoomGuestAccessEventContent::new(
match preset {
RoomPreset::PublicChat => GuestAccess::Forbidden,
_ => GuestAccess::CanJoin,
},
))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(String::new()),
@ -414,10 +440,14 @@ pub(crate) async fn create_room_route(
// 6. Events listed in initial_state
for event in &body.initial_state {
let mut pdu_builder = event.deserialize_as::<PduBuilder>().map_err(|e| {
warn!("Invalid initial state event: {:?}", e);
Error::BadRequest(ErrorKind::InvalidParam, "Invalid initial state event.")
})?;
let mut pdu_builder =
event.deserialize_as::<PduBuilder>().map_err(|e| {
warn!("Invalid initial state event: {:?}", e);
Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid initial state event.",
)
})?;
// Implicit state key defaults to ""
pdu_builder.state_key.get_or_insert_with(String::new);
@ -432,7 +462,12 @@ pub(crate) async fn create_room_route(
services()
.rooms
.timeline
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
.build_and_append_pdu(
pdu_builder,
sender_user,
&room_id,
&state_lock,
)
.await?;
}
@ -444,8 +479,10 @@ pub(crate) async fn create_room_route(
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomName,
content: to_raw_value(&RoomNameEventContent::new(name.clone()))
.expect("event is valid, we just created it"),
content: to_raw_value(&RoomNameEventContent::new(
name.clone(),
))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(String::new()),
redacts: None,
@ -483,7 +520,8 @@ pub(crate) async fn create_room_route(
drop(state_lock);
for user_id in &body.invite {
if let Err(error) =
invite_helper(sender_user, user_id, &room_id, None, body.is_direct).await
invite_helper(sender_user, user_id, &room_id, None, body.is_direct)
.await
{
warn!(%error, "invite helper failed");
};
@ -507,20 +545,19 @@ pub(crate) async fn create_room_route(
///
/// Gets a single event.
///
/// - You have to currently be joined to the room (TODO: Respect history visibility)
/// - You have to currently be joined to the room (TODO: Respect history
/// visibility)
pub(crate) async fn get_room_event_route(
body: Ruma<get_room_event::v3::Request>,
) -> Result<get_room_event::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let event = services()
.rooms
.timeline
.get_pdu(&body.event_id)?
.ok_or_else(|| {
let event = services().rooms.timeline.get_pdu(&body.event_id)?.ok_or_else(
|| {
warn!("Event not found, event ID: {:?}", &body.event_id);
Error::BadRequest(ErrorKind::NotFound, "Event not found.")
})?;
},
)?;
if !services().rooms.state_accessor.user_can_see_event(
sender_user,
@ -545,17 +582,14 @@ pub(crate) async fn get_room_event_route(
///
/// Lists all aliases of the room.
///
/// - Only users joined to the room are allowed to call this TODO: Allow any user to call it if `history_visibility` is world readable
/// - Only users joined to the room are allowed to call this TODO: Allow any
/// user to call it if `history_visibility` is world readable
pub(crate) async fn get_room_aliases_route(
body: Ruma<aliases::v3::Request>,
) -> Result<aliases::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
if !services()
.rooms
.state_cache
.is_joined(sender_user, &body.room_id)?
{
if !services().rooms.state_cache.is_joined(sender_user, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
@ -588,10 +622,7 @@ pub(crate) async fn upgrade_room_route(
) -> Result<upgrade_room::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
if !services()
.globals
.supported_room_versions()
.contains(&body.new_version)
if !services().globals.supported_room_versions().contains(&body.new_version)
{
return Err(Error::BadRequest(
ErrorKind::UnsupportedRoomVersion,
@ -601,10 +632,7 @@ pub(crate) async fn upgrade_room_route(
// Create a replacement room
let replacement_room = RoomId::new(services().globals.server_name());
services()
.rooms
.short
.get_or_create_shortroomid(&replacement_room)?;
services().rooms.short.get_or_create_shortroomid(&replacement_room)?;
let mutex_state = Arc::clone(
services()
@ -617,8 +645,9 @@ pub(crate) async fn upgrade_room_route(
);
let state_lock = mutex_state.lock().await;
// Send a m.room.tombstone event to the old room to indicate that it is not intended to be used any further
// Fail if the sender does not have the required permissions
// Send a m.room.tombstone event to the old room to indicate that it is not
// intended to be used any further Fail if the sender does not have the
// required permissions
let tombstone_event_id = services()
.rooms
.timeline
@ -659,7 +688,9 @@ pub(crate) async fn upgrade_room_route(
.rooms
.state_accessor
.room_state_get(&body.room_id, &StateEventType::RoomCreate, "")?
.ok_or_else(|| Error::bad_database("Found room without m.room.create event."))?
.ok_or_else(|| {
Error::bad_database("Found room without m.room.create event.")
})?
.content
.get(),
)
@ -671,7 +702,8 @@ pub(crate) async fn upgrade_room_route(
(*tombstone_event_id).to_owned(),
));
// Send a m.room.create event containing a predecessor field and the applicable room_version
// Send a m.room.create event containing a predecessor field and the
// applicable room_version
match body.new_version {
RoomVersionId::V1
| RoomVersionId::V2
@ -686,7 +718,10 @@ pub(crate) async fn upgrade_room_route(
create_event_content.insert(
"creator".into(),
json!(&sender_user).try_into().map_err(|_| {
Error::BadRequest(ErrorKind::BadJson, "Error forming creation event")
Error::BadRequest(
ErrorKind::BadJson,
"Error forming creation event",
)
})?,
);
}
@ -698,15 +733,21 @@ pub(crate) async fn upgrade_room_route(
}
create_event_content.insert(
"room_version".into(),
json!(&body.new_version)
.try_into()
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"))?,
json!(&body.new_version).try_into().map_err(|_| {
Error::BadRequest(
ErrorKind::BadJson,
"Error forming creation event",
)
})?,
);
create_event_content.insert(
"predecessor".into(),
json!(predecessor)
.try_into()
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Error forming creation event"))?,
json!(predecessor).try_into().map_err(|_| {
Error::BadRequest(
ErrorKind::BadJson,
"Error forming creation event",
)
})?,
);
// Validate creation event content
@ -784,16 +825,15 @@ pub(crate) async fn upgrade_room_route(
// Replicate transferable state events to the new room
for event_type in transferable_state_events {
let event_content =
match services()
.rooms
.state_accessor
.room_state_get(&body.room_id, &event_type, "")?
{
Some(v) => v.content.clone(),
// Skipping missing events.
None => continue,
};
let event_content = match services()
.rooms
.state_accessor
.room_state_get(&body.room_id, &event_type, "")?
{
Some(v) => v.content.clone(),
// Skipping missing events.
None => continue,
};
services()
.rooms
@ -820,30 +860,39 @@ pub(crate) async fn upgrade_room_route(
.local_aliases_for_room(&body.room_id)
.filter_map(Result::ok)
{
services()
.rooms
.alias
.set_alias(&alias, &replacement_room)?;
services().rooms.alias.set_alias(&alias, &replacement_room)?;
}
// Get the old room power levels
let mut power_levels_event_content: RoomPowerLevelsEventContent = serde_json::from_str(
services()
.rooms
.state_accessor
.room_state_get(&body.room_id, &StateEventType::RoomPowerLevels, "")?
.ok_or_else(|| Error::bad_database("Found room without m.room.create event."))?
.content
.get(),
)
.map_err(|_| Error::bad_database("Invalid room event in database."))?;
let mut power_levels_event_content: RoomPowerLevelsEventContent =
serde_json::from_str(
services()
.rooms
.state_accessor
.room_state_get(
&body.room_id,
&StateEventType::RoomPowerLevels,
"",
)?
.ok_or_else(|| {
Error::bad_database(
"Found room without m.room.create event.",
)
})?
.content
.get(),
)
.map_err(|_| Error::bad_database("Invalid room event in database."))?;
// Setting events_default and invite to the greater of 50 and users_default + 1
let new_level = max(int!(50), power_levels_event_content.users_default + int!(1));
// Setting events_default and invite to the greater of 50 and users_default
// + 1
let new_level =
max(int!(50), power_levels_event_content.users_default + int!(1));
power_levels_event_content.events_default = new_level;
power_levels_event_content.invite = new_level;
// Modify the power levels in the old room to prevent sending of events and inviting new users
// Modify the power levels in the old room to prevent sending of events and
// inviting new users
let _ = services()
.rooms
.timeline
@ -865,5 +914,7 @@ 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

@ -1,22 +1,27 @@
use crate::{services, Error, Result, Ruma};
use std::collections::BTreeMap;
use ruma::{
api::client::{
error::ErrorKind,
search::search_events::{
self,
v3::{EventContextResult, ResultCategories, ResultRoomEvents, SearchResult},
v3::{
EventContextResult, ResultCategories, ResultRoomEvents,
SearchResult,
},
},
},
uint,
};
use std::collections::BTreeMap;
use crate::{services, Error, Result, Ruma};
/// # `POST /_matrix/client/r0/search`
///
/// Searches rooms for messages.
///
/// - Only works if the user is currently joined to the room (TODO: Respect history visibility)
/// - Only works if the user is currently joined to the room (TODO: Respect
/// history visibility)
#[allow(clippy::too_many_lines)]
pub(crate) async fn search_events_route(
body: Ruma<search_events::v3::Request>,
@ -46,11 +51,7 @@ pub(crate) async fn search_events_route(
let mut searches = Vec::new();
for room_id in room_ids {
if !services()
.rooms
.state_cache
.is_joined(sender_user, &room_id)?
{
if !services().rooms.state_cache.is_joined(sender_user, &room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
@ -102,7 +103,11 @@ pub(crate) async fn search_events_route(
services()
.rooms
.state_accessor
.user_can_see_event(sender_user, &pdu.room_id, &pdu.event_id)
.user_can_see_event(
sender_user,
&pdu.room_id,
&pdu.event_id,
)
.unwrap_or(false)
})
.map(|pdu| pdu.to_room_event())

View file

@ -1,5 +1,3 @@
use super::{DEVICE_ID_LENGTH, TOKEN_LENGTH};
use crate::{services, utils, Error, Result, Ruma};
use ruma::{
api::client::{
error::ErrorKind,
@ -17,6 +15,9 @@ use ruma::{
use serde::Deserialize;
use tracing::{info, warn};
use super::{DEVICE_ID_LENGTH, TOKEN_LENGTH};
use crate::{services, utils, Error, Result, Ruma};
#[derive(Debug, Deserialize)]
struct Claims {
sub: String,
@ -24,30 +25,36 @@ struct Claims {
/// # `GET /_matrix/client/r0/login`
///
/// Get the supported login types of this server. One of these should be used as the `type` field
/// when logging in.
/// Get the supported login types of this server. One of these should be used as
/// the `type` field when logging in.
pub(crate) async fn get_login_types_route(
_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()),
get_login_types::v3::LoginType::ApplicationService(ApplicationServiceLoginType::default()),
get_login_types::v3::LoginType::ApplicationService(
ApplicationServiceLoginType::default(),
),
]))
}
/// # `POST /_matrix/client/r0/login`
///
/// Authenticates the user and returns an access token it can use in subsequent requests.
/// Authenticates the user and returns an access token it can use in subsequent
/// requests.
///
/// - The user needs to authenticate using their password (or if enabled using a json web token)
/// - The user needs to authenticate using their password (or if enabled using a
/// json web token)
/// - If `device_id` is known: invalidates old access token of that device
/// - If `device_id` is unknown: creates a new device
/// - Returns access token that is associated with the user and device
///
/// Note: You can use [`GET /_matrix/client/r0/login`](get_login_types_route) to see
/// supported login types.
/// Note: You can use [`GET /_matrix/client/r0/login`](get_login_types_route) to
/// see supported login types.
#[allow(clippy::too_many_lines)]
pub(crate) async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Response> {
pub(crate) async fn login_route(
body: Ruma<login::v3::Request>,
) -> Result<login::v3::Response> {
// To allow deprecated login methods
#![allow(deprecated)]
// Validate login method
@ -59,18 +66,29 @@ pub(crate) async fn login_route(body: Ruma<login::v3::Request>) -> Result<login:
user,
..
}) => {
let user_id = if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
UserId::parse_with_server_name(
user_id.to_lowercase(),
services().globals.server_name(),
)
} else if let Some(user) = user {
UserId::parse(user)
} else {
warn!("Bad login type: {:?}", &body.login_info);
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
}
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
let user_id =
if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) =
identifier
{
UserId::parse_with_server_name(
user_id.to_lowercase(),
services().globals.server_name(),
)
} else if let Some(user) = user {
UserId::parse(user)
} else {
warn!("Bad login type: {:?}", &body.login_info);
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"Bad login type.",
));
}
.map_err(|_| {
Error::BadRequest(
ErrorKind::InvalidUsername,
"Username is invalid.",
)
})?;
if services().appservice.is_exclusive_user_id(&user_id).await {
return Err(Error::BadRequest(
@ -79,13 +97,12 @@ pub(crate) async fn login_route(body: Ruma<login::v3::Request>) -> Result<login:
));
}
let hash = services()
.users
.password_hash(&user_id)?
.ok_or(Error::BadRequest(
let hash = services().users.password_hash(&user_id)?.ok_or(
Error::BadRequest(
ErrorKind::Forbidden,
"Wrong username or password.",
))?;
),
)?;
if hash.is_empty() {
return Err(Error::BadRequest(
@ -94,7 +111,9 @@ pub(crate) async fn login_route(body: Ruma<login::v3::Request>) -> Result<login:
));
}
let hash_matches = argon2::verify_encoded(&hash, password.as_bytes()).unwrap_or(false);
let hash_matches =
argon2::verify_encoded(&hash, password.as_bytes())
.unwrap_or(false);
if !hash_matches {
return Err(Error::BadRequest(
@ -105,20 +124,34 @@ pub(crate) async fn login_route(body: Ruma<login::v3::Request>) -> Result<login:
user_id
}
login::v3::LoginInfo::Token(login::v3::Token { token }) => {
if let Some(jwt_decoding_key) = services().globals.jwt_decoding_key() {
login::v3::LoginInfo::Token(login::v3::Token {
token,
}) => {
if let Some(jwt_decoding_key) =
services().globals.jwt_decoding_key()
{
let token = jsonwebtoken::decode::<Claims>(
token,
jwt_decoding_key,
&jsonwebtoken::Validation::default(),
)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Token is invalid."))?;
.map_err(|_| {
Error::BadRequest(
ErrorKind::InvalidUsername,
"Token is invalid.",
)
})?;
let username = token.claims.sub.to_lowercase();
let user_id =
UserId::parse_with_server_name(username, services().globals.server_name())
.map_err(|_| {
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
})?;
let user_id = UserId::parse_with_server_name(
username,
services().globals.server_name(),
)
.map_err(|_| {
Error::BadRequest(
ErrorKind::InvalidUsername,
"Username is invalid.",
)
})?;
if services().appservice.is_exclusive_user_id(&user_id).await {
return Err(Error::BadRequest(
@ -131,26 +164,40 @@ pub(crate) async fn login_route(body: Ruma<login::v3::Request>) -> Result<login:
} else {
return Err(Error::BadRequest(
ErrorKind::Unknown,
"Token login is not supported (server has no jwt decoding key).",
"Token login is not supported (server has no jwt decoding \
key).",
));
}
}
login::v3::LoginInfo::ApplicationService(login::v3::ApplicationService {
identifier,
user,
}) => {
let user_id = if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
UserId::parse_with_server_name(
user_id.to_lowercase(),
services().globals.server_name(),
)
} else if let Some(user) = user {
UserId::parse(user)
} else {
warn!("Bad login type: {:?}", &body.login_info);
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
}
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
login::v3::LoginInfo::ApplicationService(
login::v3::ApplicationService {
identifier,
user,
},
) => {
let user_id =
if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) =
identifier
{
UserId::parse_with_server_name(
user_id.to_lowercase(),
services().globals.server_name(),
)
} else if let Some(user) = user {
UserId::parse(user)
} else {
warn!("Bad login type: {:?}", &body.login_info);
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"Bad login type.",
));
}
.map_err(|_| {
Error::BadRequest(
ErrorKind::InvalidUsername,
"Username is invalid.",
)
})?;
if let Some(info) = &body.appservice_info {
if !info.is_user_match(&user_id) {
@ -225,12 +272,16 @@ pub(crate) async fn login_route(body: Ruma<login::v3::Request>) -> Result<login:
/// Log out the current device.
///
/// - Invalidates access token
/// - Deletes device metadata (device id, device display name, last seen ip, last seen ts)
/// - Deletes device metadata (device id, device display name, last seen ip,
/// last seen ts)
/// - Forgets to-device events
/// - Triggers device list updates
pub(crate) async fn logout_route(body: Ruma<logout::v3::Request>) -> Result<logout::v3::Response> {
pub(crate) async fn logout_route(
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");
let sender_device =
body.sender_device.as_ref().expect("user is authenticated");
if let Some(info) = &body.appservice_info {
if !info.is_user_match(sender_user) {
@ -251,12 +302,13 @@ pub(crate) async fn logout_route(body: Ruma<logout::v3::Request>) -> Result<logo
/// Log out all devices of this user.
///
/// - Invalidates all access tokens
/// - Deletes all device metadata (device id, device display name, last seen ip, last seen ts)
/// - Deletes all device metadata (device id, device display name, last seen ip,
/// last seen ts)
/// - Forgets all to-device events
/// - Triggers device list updates
///
/// Note: This is equivalent to calling [`GET /_matrix/client/r0/logout`](logout_route)
/// from each device of this user.
/// Note: This is equivalent to calling [`GET
/// /_matrix/client/r0/logout`](logout_route) from each device of this user.
pub(crate) async fn logout_all_route(
body: Ruma<logout_all::v3::Request>,
) -> Result<logout_all::v3::Response> {

View file

@ -1,19 +1,18 @@
use crate::{services, Result, Ruma};
use ruma::{api::client::space::get_hierarchy, uint};
use crate::{services, Result, Ruma};
/// # `GET /_matrix/client/v1/rooms/{room_id}/hierarchy`
///
/// Paginates over the space tree in a depth-first manner to locate child rooms of a given space.
/// 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(
body: Ruma<get_hierarchy::v1::Request>,
) -> Result<get_hierarchy::v1::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let skip = body
.from
.as_ref()
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(0);
let skip =
body.from.as_ref().and_then(|s| s.parse::<usize>().ok()).unwrap_or(0);
let limit = body
.limit
@ -23,8 +22,10 @@ pub(crate) async fn get_hierarchy_route(
.expect("0-100 should fit in usize");
// Plus one to skip the space room itself
let max_depth = usize::try_from(body.max_depth.map(|x| x.min(uint!(10))).unwrap_or(uint!(3)))
.expect("0-10 should fit in usize")
let max_depth = usize::try_from(
body.max_depth.map(|x| x.min(uint!(10))).unwrap_or(uint!(3)),
)
.expect("0-10 should fit in usize")
+ 1;
services()

View file

@ -1,25 +1,30 @@
use std::sync::Arc;
use crate::{service::pdu::PduBuilder, services, Error, Result, Ruma, RumaResponse};
use ruma::{
api::client::{
error::ErrorKind,
state::{get_state_events, get_state_events_for_key, send_state_event},
},
events::{
room::canonical_alias::RoomCanonicalAliasEventContent, AnyStateEventContent, StateEventType,
room::canonical_alias::RoomCanonicalAliasEventContent,
AnyStateEventContent, StateEventType,
},
serde::Raw,
EventId, RoomId, UserId,
};
use tracing::log::warn;
use crate::{
service::pdu::PduBuilder, services, Error, Result, Ruma, RumaResponse,
};
/// # `PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}`
///
/// Sends a state event into the room.
///
/// - The only requirement for the content is that it has to be valid json
/// - Tries to send the event into the room, auth rules will determine if it is allowed
/// - Tries to send the event into the room, auth rules will determine if it is
/// allowed
/// - If event is new `canonical_alias`: Rejects if alias is incorrect
pub(crate) async fn send_state_event_for_key_route(
body: Ruma<send_state_event::v3::Request>,
@ -37,7 +42,9 @@ pub(crate) async fn send_state_event_for_key_route(
.await?;
let event_id = (*event_id).to_owned();
Ok(send_state_event::v3::Response { event_id })
Ok(send_state_event::v3::Response {
event_id,
})
}
/// # `PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}`
@ -45,7 +52,8 @@ pub(crate) async fn send_state_event_for_key_route(
/// Sends a state event into the room.
///
/// - The only requirement for the content is that it has to be valid json
/// - Tries to send the event into the room, auth rules will determine if it is allowed
/// - Tries to send the event into the room, auth rules will determine if it is
/// allowed
/// - If event is new `canonical_alias`: Rejects if alias is incorrect
pub(crate) async fn send_state_event_for_empty_key_route(
body: Ruma<send_state_event::v3::Request>,
@ -53,7 +61,9 @@ pub(crate) async fn send_state_event_for_empty_key_route(
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
// Forbid m.room.encryption if encryption is disabled
if body.event_type == StateEventType::RoomEncryption && !services().globals.allow_encryption() {
if body.event_type == StateEventType::RoomEncryption
&& !services().globals.allow_encryption()
{
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"Encryption has been disabled",
@ -70,14 +80,18 @@ pub(crate) async fn send_state_event_for_empty_key_route(
.await?;
let event_id = (*event_id).to_owned();
Ok(send_state_event::v3::Response { event_id }.into())
Ok(send_state_event::v3::Response {
event_id,
}
.into())
}
/// # `GET /_matrix/client/r0/rooms/{roomid}/state`
///
/// Get all state events for a room.
///
/// - If not joined: Only works if current room history visibility is world readable
/// - If not joined: Only works if current room history visibility is world
/// readable
pub(crate) async fn get_state_events_route(
body: Ruma<get_state_events::v3::Request>,
) -> Result<get_state_events::v3::Response> {
@ -110,7 +124,8 @@ pub(crate) async fn get_state_events_route(
///
/// Get single state event of a room.
///
/// - If not joined: Only works if current room history visibility is world readable
/// - If not joined: Only works if current room history visibility is world
/// readable
pub(crate) async fn get_state_events_for_key_route(
body: Ruma<get_state_events_for_key::v3::Request>,
) -> Result<get_state_events_for_key::v3::Response> {
@ -140,8 +155,9 @@ pub(crate) async fn get_state_events_for_key_route(
})?;
Ok(get_state_events_for_key::v3::Response {
content: serde_json::from_str(event.content.get())
.map_err(|_| Error::bad_database("Invalid event content in database"))?,
content: serde_json::from_str(event.content.get()).map_err(|_| {
Error::bad_database("Invalid event content in database")
})?,
})
}
@ -149,7 +165,8 @@ pub(crate) async fn get_state_events_for_key_route(
///
/// Get single state event of a room.
///
/// - If not joined: Only works if current room history visibility is world readable
/// - If not joined: Only works if current room history visibility is world
/// readable
pub(crate) async fn get_state_events_for_empty_key_route(
body: Ruma<get_state_events_for_key::v3::Request>,
) -> Result<RumaResponse<get_state_events_for_key::v3::Response>> {
@ -179,8 +196,9 @@ pub(crate) async fn get_state_events_for_empty_key_route(
})?;
Ok(get_state_events_for_key::v3::Response {
content: serde_json::from_str(event.content.get())
.map_err(|_| Error::bad_database("Invalid event content in database"))?,
content: serde_json::from_str(event.content.get()).map_err(|_| {
Error::bad_database("Invalid event content in database")
})?,
}
.into())
}
@ -194,10 +212,11 @@ async fn send_state_event_for_key_helper(
) -> Result<Arc<EventId>> {
let sender_user = sender;
// TODO: Review this check, error if event is unparsable, use event type, allow alias if it
// previously existed
if let Ok(canonical_alias) =
serde_json::from_str::<RoomCanonicalAliasEventContent>(json.json().get())
// TODO: Review this check, error if event is unparsable, use event type,
// allow alias if it previously existed
if let Ok(canonical_alias) = serde_json::from_str::<
RoomCanonicalAliasEventContent,
>(json.json().get())
{
let mut aliases = canonical_alias.alt_aliases.clone();
@ -216,8 +235,8 @@ async fn send_state_event_for_key_helper(
{
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You are only allowed to send canonical_alias \
events when it's aliases already exists",
"You are only allowed to send canonical_alias events when \
it's aliases already exists",
));
}
}
@ -240,7 +259,8 @@ async fn send_state_event_for_key_helper(
.build_and_append_pdu(
PduBuilder {
event_type: event_type.to_string().into(),
content: serde_json::from_str(json.json().get()).expect("content is valid json"),
content: serde_json::from_str(json.json().get())
.expect("content is valid json"),
unsigned: None,
state_key: Some(state_key),
redacts: None,

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
use crate::{services, Error, Result, Ruma};
use std::collections::BTreeMap;
use ruma::{
api::client::tag::{create_tag, delete_tag, get_tags},
events::{
@ -6,7 +7,8 @@ use ruma::{
RoomAccountDataEventType,
},
};
use std::collections::BTreeMap;
use crate::{services, Error, Result, Ruma};
/// # `PUT /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}`
///
@ -33,8 +35,9 @@ pub(crate) async fn update_tag_route(
})
},
|e| {
serde_json::from_str(e.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))
serde_json::from_str(e.get()).map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})
},
)?;
@ -78,8 +81,9 @@ pub(crate) async fn delete_tag_route(
})
},
|e| {
serde_json::from_str(e.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))
serde_json::from_str(e.get()).map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})
},
)?;
@ -120,8 +124,9 @@ pub(crate) async fn get_tags_route(
})
},
|e| {
serde_json::from_str(e.get())
.map_err(|_| Error::bad_database("Invalid account data event in db."))
serde_json::from_str(e.get()).map_err(|_| {
Error::bad_database("Invalid account data event in db.")
})
},
)?;

View file

@ -1,7 +1,8 @@
use crate::{Result, Ruma};
use std::collections::BTreeMap;
use ruma::api::client::thirdparty::get_protocols;
use std::collections::BTreeMap;
use crate::{Result, Ruma};
/// # `GET /_matrix/client/r0/thirdparty/protocols`
///

View file

@ -9,11 +9,8 @@ pub(crate) async fn get_threads_route(
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
// Use limit or else 10, with maximum 100
let limit = body
.limit
.and_then(|l| l.try_into().ok())
.unwrap_or(10)
.min(100);
let limit =
body.limit.and_then(|l| l.try_into().ok()).unwrap_or(10).min(100);
let from = if let Some(from) = &body.from {
from.parse()

View file

@ -1,6 +1,5 @@
use std::collections::BTreeMap;
use crate::{services, Error, Result, Ruma};
use ruma::{
api::{
client::{error::ErrorKind, to_device::send_event_to_device},
@ -9,6 +8,8 @@ use ruma::{
to_device::DeviceIdOrAllDevices,
};
use crate::{services, Error, Result, Ruma};
/// # `PUT /_matrix/client/r0/sendToDevice/{eventType}/{txnId}`
///
/// Send a to-device event to a set of client devices.
@ -29,7 +30,8 @@ pub(crate) async fn send_event_to_device_route(
for (target_user_id, map) in &body.messages {
for (target_device_id_maybe, event) in map {
if target_user_id.server_name() != services().globals.server_name() {
if target_user_id.server_name() != services().globals.server_name()
{
let mut map = BTreeMap::new();
map.insert(target_device_id_maybe.clone(), event.clone());
let mut messages = BTreeMap::new();
@ -38,14 +40,16 @@ pub(crate) async fn send_event_to_device_route(
services().sending.send_reliable_edu(
target_user_id.server_name(),
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,
},
))
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"),
count,
)?;
@ -61,20 +65,28 @@ pub(crate) async fn send_event_to_device_route(
target_device_id,
&body.event_type.to_string(),
event.deserialize_as().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid")
Error::BadRequest(
ErrorKind::InvalidParam,
"Event is invalid",
)
})?,
)?;
}
DeviceIdOrAllDevices::AllDevices => {
for target_device_id in services().users.all_device_ids(target_user_id) {
for target_device_id in
services().users.all_device_ids(target_user_id)
{
services().users.add_to_device_event(
sender_user,
target_user_id,
&target_device_id?,
&body.event_type.to_string(),
event.deserialize_as().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid")
Error::BadRequest(
ErrorKind::InvalidParam,
"Event is invalid",
)
})?,
)?;
}
@ -84,9 +96,12 @@ pub(crate) async fn send_event_to_device_route(
}
// Save transaction id with empty data
services()
.transaction_ids
.add_txnid(sender_user, sender_device, &body.txn_id, &[])?;
services().transaction_ids.add_txnid(
sender_user,
sender_device,
&body.txn_id,
&[],
)?;
Ok(send_event_to_device::v3::Response {})
}

View file

@ -1,6 +1,7 @@
use crate::{services, utils, Error, Result, Ruma};
use ruma::api::client::{error::ErrorKind, typing::create_typing_event};
use crate::{services, utils, Error, Result, Ruma};
/// # `PUT /_matrix/client/r0/rooms/{roomId}/typing/{userId}`
///
/// Sets the typing state of the sender user.
@ -11,11 +12,7 @@ pub(crate) async fn create_typing_event_route(
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
if !services()
.rooms
.state_cache
.is_joined(sender_user, &body.room_id)?
{
if !services().rooms.state_cache.is_joined(sender_user, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You are not in this room.",

View file

@ -6,14 +6,16 @@ use crate::{Result, Ruma};
/// # `GET /_matrix/client/versions`
///
/// Get the versions of the specification and unstable features supported by this server.
/// Get the versions of the specification and unstable features supported by
/// this server.
///
/// - Versions take the form MAJOR.MINOR.PATCH
/// - Only the latest PATCH release will be reported for each MAJOR.MINOR value
/// - Unstable features are namespaced and may include version information in their name
/// - Unstable features are namespaced and may include version information in
/// their name
///
/// Note: Unstable features are used while developing new features. Clients should avoid using
/// unstable features in their stable releases
/// Note: Unstable features are used while developing new features. Clients
/// should avoid using unstable features in their stable releases
pub(crate) async fn get_supported_versions_route(
_body: Ruma<get_supported_versions::Request>,
) -> Result<get_supported_versions::Response> {
@ -27,7 +29,10 @@ pub(crate) async fn get_supported_versions_route(
"v1.4".to_owned(),
"v1.5".to_owned(),
],
unstable_features: BTreeMap::from_iter([("org.matrix.e2e_cross_signing".to_owned(), true)]),
unstable_features: BTreeMap::from_iter([(
"org.matrix.e2e_cross_signing".to_owned(),
true,
)]),
};
Ok(resp)

View file

@ -1,4 +1,3 @@
use crate::{services, Result, Ruma};
use ruma::{
api::client::user_directory::search_users,
events::{
@ -7,11 +6,14 @@ use ruma::{
},
};
use crate::{services, Result, Ruma};
/// # `POST /_matrix/client/r0/user_directory/search`
///
/// Searches all known users for a match.
///
/// - Hides any local users that aren't in any public rooms (i.e. those that have the join rule set to public)
/// - 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(
body: Ruma<search_users::v3::Request>,
@ -38,8 +40,7 @@ pub(crate) async fn search_users_route(
.display_name
.as_ref()
.filter(|name| {
name.to_lowercase()
.contains(&body.search_term.to_lowercase())
name.to_lowercase().contains(&body.search_term.to_lowercase())
})
.is_some();
@ -62,10 +63,12 @@ pub(crate) async fn search_users_route(
.room_state_get(&room, &StateEventType::RoomJoinRules, "")
.map_or(false, |event| {
event.map_or(false, |event| {
serde_json::from_str(event.content.get())
.map_or(false, |r: RoomJoinRulesEventContent| {
serde_json::from_str(event.content.get()).map_or(
false,
|r: RoomJoinRulesEventContent| {
r.join_rule == JoinRule::Public
})
},
)
})
})
});
@ -96,5 +99,8 @@ pub(crate) async fn search_users_route(
let results = users.by_ref().take(limit).collect();
let limited = users.next().is_some();
Ok(search_users::v3::Response { results, limited })
Ok(search_users::v3::Response {
results,
limited,
})
}

View file

@ -1,9 +1,11 @@
use crate::{services, Result, Ruma};
use std::time::{Duration, SystemTime};
use base64::{engine::general_purpose, Engine as _};
use hmac::{Hmac, Mac};
use ruma::{api::client::voip::get_turn_server_info, SecondsSinceUnixEpoch};
use sha1::Sha1;
use std::time::{Duration, SystemTime};
use crate::{services, Result, Ruma};
type HmacSha1 = Hmac<Sha1>;
@ -24,7 +26,8 @@ pub(crate) async fn turn_server_route(
)
} else {
let expiry = SecondsSinceUnixEpoch::from_system_time(
SystemTime::now() + Duration::from_secs(services().globals.turn_ttl()),
SystemTime::now()
+ Duration::from_secs(services().globals.turn_ttl()),
)
.expect("time is valid");
@ -34,7 +37,8 @@ pub(crate) async fn turn_server_route(
.expect("HMAC can take key of any size");
mac.update(username.as_bytes());
let password: String = general_purpose::STANDARD.encode(mac.finalize().into_bytes());
let password: String =
general_purpose::STANDARD.encode(mac.finalize().into_bytes());
(username, password)
};

View file

@ -1,10 +1,12 @@
use crate::{service::appservice::RegistrationInfo, Error};
use ruma::{
api::client::uiaa::UiaaResponse, CanonicalJsonValue, OwnedDeviceId, OwnedServerName,
OwnedUserId,
};
use std::ops::Deref;
use ruma::{
api::client::uiaa::UiaaResponse, CanonicalJsonValue, OwnedDeviceId,
OwnedServerName, OwnedUserId,
};
use crate::{service::appservice::RegistrationInfo, Error};
mod axum;
/// Extractor for Ruma request structs

View file

@ -3,7 +3,9 @@ use std::{collections::BTreeMap, iter::FromIterator, str};
use axum::{
async_trait,
body::{Full, HttpBody},
extract::{rejection::TypedHeaderRejectionReason, FromRequest, Path, TypedHeader},
extract::{
rejection::TypedHeaderRejectionReason, FromRequest, Path, TypedHeader,
},
headers::{
authorization::{Bearer, Credentials},
Authorization,
@ -14,7 +16,9 @@ use axum::{
use bytes::{Buf, BufMut, Bytes, BytesMut};
use http::{Request, StatusCode};
use ruma::{
api::{client::error::ErrorKind, AuthScheme, IncomingRequest, OutgoingResponse},
api::{
client::error::ErrorKind, AuthScheme, IncomingRequest, OutgoingResponse,
},
CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
};
use serde::Deserialize;
@ -41,7 +45,10 @@ where
type Rejection = Error;
#[allow(clippy::too_many_lines)]
async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
async fn from_request(
req: Request<B>,
_state: &S,
) -> Result<Self, Self::Rejection> {
#[derive(Deserialize)]
struct QueryParams {
access_token: Option<String>,
@ -51,22 +58,23 @@ where
let (mut parts, mut body) = match req.with_limited_body() {
Ok(limited_req) => {
let (parts, body) = limited_req.into_parts();
let body = to_bytes(body)
.await
.map_err(|_| Error::BadRequest(ErrorKind::MissingToken, "Missing token."))?;
let body = to_bytes(body).await.map_err(|_| {
Error::BadRequest(ErrorKind::MissingToken, "Missing token.")
})?;
(parts, body)
}
Err(original_req) => {
let (parts, body) = original_req.into_parts();
let body = to_bytes(body)
.await
.map_err(|_| Error::BadRequest(ErrorKind::MissingToken, "Missing token."))?;
let body = to_bytes(body).await.map_err(|_| {
Error::BadRequest(ErrorKind::MissingToken, "Missing token.")
})?;
(parts, body)
}
};
let metadata = T::METADATA;
let auth_header: Option<TypedHeader<Authorization<Bearer>>> = parts.extract().await?;
let auth_header: Option<TypedHeader<Authorization<Bearer>>> =
parts.extract().await?;
let path_params: Path<Vec<String>> = parts.extract().await?;
let query = parts.uri.query().unwrap_or_default();
@ -87,9 +95,13 @@ where
};
let token = if let Some(token) = token {
if let Some(reg_info) = services().appservice.find_from_token(token).await {
if let Some(reg_info) =
services().appservice.find_from_token(token).await
{
Token::Appservice(Box::new(reg_info.clone()))
} else if let Some((user_id, device_id)) = services().users.find_from_token(token)? {
} else if let Some((user_id, device_id)) =
services().users.find_from_token(token)?
{
Token::User((user_id, OwnedDeviceId::from(device_id)))
} else {
Token::Invalid
@ -98,13 +110,16 @@ where
Token::None
};
let mut json_body = serde_json::from_slice::<CanonicalJsonValue>(&body).ok();
let mut json_body =
serde_json::from_slice::<CanonicalJsonValue>(&body).ok();
let (sender_user, sender_device, sender_servername, appservice_info) =
match (metadata.authentication, token) {
(_, Token::Invalid) => {
return Err(Error::BadRequest(
ErrorKind::UnknownToken { soft_logout: false },
ErrorKind::UnknownToken {
soft_logout: false,
},
"Unknown access token.",
))
}
@ -121,7 +136,10 @@ where
UserId::parse,
)
.map_err(|_| {
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
Error::BadRequest(
ErrorKind::InvalidUsername,
"Username is invalid.",
)
})?;
if !info.is_user_match(&user_id) {
@ -153,7 +171,9 @@ where
));
}
(
AuthScheme::AccessToken | AuthScheme::AccessTokenOptional | AuthScheme::None,
AuthScheme::AccessToken
| AuthScheme::AccessTokenOptional
| AuthScheme::None,
Token::User((user_id, device_id)),
) => (Some(user_id), Some(device_id), None, None),
(AuthScheme::ServerSignatures, Token::None) => {
@ -161,7 +181,10 @@ where
.extract::<TypedHeader<Authorization<XMatrix>>>()
.await
.map_err(|e| {
warn!("Missing or invalid Authorization header: {}", e);
warn!(
"Missing or invalid Authorization header: {}",
e
);
let msg = match e.reason() {
TypedHeaderRejectionReason::Missing => {
@ -189,7 +212,9 @@ where
let mut request_map = BTreeMap::from_iter([
(
"method".to_owned(),
CanonicalJsonValue::String(parts.method.to_string()),
CanonicalJsonValue::String(
parts.method.to_string(),
),
),
(
"uri".to_owned(),
@ -197,12 +222,18 @@ where
),
(
"origin".to_owned(),
CanonicalJsonValue::String(x_matrix.origin.as_str().to_owned()),
CanonicalJsonValue::String(
x_matrix.origin.as_str().to_owned(),
),
),
(
"destination".to_owned(),
CanonicalJsonValue::String(
services().globals.server_name().as_str().to_owned(),
services()
.globals
.server_name()
.as_str()
.to_owned(),
),
),
(
@ -212,13 +243,17 @@ where
]);
if let Some(json_body) = &json_body {
request_map.insert("content".to_owned(), json_body.clone());
request_map
.insert("content".to_owned(), json_body.clone());
};
let keys_result = services()
.rooms
.event_handler
.fetch_signing_keys(&x_matrix.origin, vec![x_matrix.key.clone()])
.fetch_signing_keys(
&x_matrix.origin,
vec![x_matrix.key.clone()],
)
.await;
let keys = match keys_result {
@ -232,22 +267,29 @@ where
}
};
let pub_key_map =
BTreeMap::from_iter([(x_matrix.origin.as_str().to_owned(), keys)]);
let pub_key_map = BTreeMap::from_iter([(
x_matrix.origin.as_str().to_owned(),
keys,
)]);
match ruma::signatures::verify_json(&pub_key_map, &request_map) {
match ruma::signatures::verify_json(
&pub_key_map,
&request_map,
) {
Ok(()) => (None, None, Some(x_matrix.origin), None),
Err(e) => {
warn!(
"Failed to verify json request from {}: {}\n{:?}",
"Failed to verify json request from {}: \
{}\n{:?}",
x_matrix.origin, e, request_map
);
if parts.uri.to_string().contains('@') {
warn!(
"Request uri contained '@' character. Make sure your \
reverse proxy gives Grapevine the raw uri (apache: use \
nocanon)"
"Request uri contained '@' character. \
Make sure your reverse proxy gives \
Grapevine the raw uri (apache: use \
nocanon)"
);
}
@ -264,27 +306,36 @@ where
| AuthScheme::AccessTokenOptional,
Token::None,
) => (None, None, None, None),
(AuthScheme::ServerSignatures, Token::Appservice(_) | Token::User(_)) => {
(
AuthScheme::ServerSignatures,
Token::Appservice(_) | Token::User(_),
) => {
return Err(Error::BadRequest(
ErrorKind::Unauthorized,
"Only server signatures should be used on this endpoint.",
"Only server signatures should be used on this \
endpoint.",
));
}
(AuthScheme::AppserviceToken, Token::User(_)) => {
return Err(Error::BadRequest(
ErrorKind::Unauthorized,
"Only appservice access tokens should be used on this endpoint.",
"Only appservice access tokens should be used on this \
endpoint.",
));
}
};
let mut http_request = http::Request::builder().uri(parts.uri).method(parts.method);
let mut http_request =
http::Request::builder().uri(parts.uri).method(parts.method);
*http_request.headers_mut().unwrap() = parts.headers;
if let Some(CanonicalJsonValue::Object(json_body)) = &mut json_body {
let user_id = sender_user.clone().unwrap_or_else(|| {
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")
});
let uiaa_request = json_body
@ -300,14 +351,17 @@ where
)
});
if let Some(CanonicalJsonValue::Object(initial_request)) = uiaa_request {
if let Some(CanonicalJsonValue::Object(initial_request)) =
uiaa_request
{
for (key, value) in initial_request {
json_body.entry(key).or_insert(value);
}
}
let mut buf = BytesMut::new().writer();
serde_json::to_writer(&mut buf, json_body).expect("value serialization can't fail");
serde_json::to_writer(&mut buf, json_body)
.expect("value serialization can't fail");
body = buf.into_inner().freeze();
}
@ -315,11 +369,15 @@ where
debug!("{:?}", http_request);
let body = T::try_from_http_request(http_request, &path_params).map_err(|e| {
warn!("try_from_http_request failed: {:?}", e);
debug!("JSON body: {:?}", json_body);
Error::BadRequest(ErrorKind::BadJson, "Failed to deserialize request.")
})?;
let body = T::try_from_http_request(http_request, &path_params)
.map_err(|e| {
warn!("try_from_http_request failed: {:?}", e);
debug!("JSON body: {:?}", json_body);
Error::BadRequest(
ErrorKind::BadJson,
"Failed to deserialize request.",
)
})?;
Ok(Ruma {
body,
@ -345,7 +403,8 @@ impl Credentials for XMatrix {
fn decode(value: &http::HeaderValue) -> Option<Self> {
debug_assert!(
value.as_bytes().starts_with(b"X-Matrix "),
"HeaderValue to decode should start with \"X-Matrix ..\", received = {value:?}",
"HeaderValue to decode should start with \"X-Matrix ..\", \
received = {value:?}",
);
let parameters = str::from_utf8(&value.as_bytes()["X-Matrix ".len()..])
@ -359,8 +418,9 @@ impl Credentials for XMatrix {
for entry in parameters.split_terminator(',') {
let (name, value) = entry.split_once('=')?;
// It's not at all clear why some fields are quoted and others not in the spec,
// let's simply accept either form for every field.
// It's not at all clear why some fields are quoted and others not
// in the spec, let's simply accept either form for
// every field.
let value = value
.strip_prefix('"')
.and_then(|rest| rest.strip_suffix('"'))

File diff suppressed because it is too large Load diff