mirror of
https://gitlab.computer.surgery/matrix/grapevine.git
synced 2025-12-17 15:51:23 +01:00
change rustfmt configuration
This change is fully automated, except the `rustfmt.toml` changes and a few clippy directives to allow specific functions with too many lines because they are longer now.
This commit is contained in:
parent
40d6ce230d
commit
0afc1d2f50
123 changed files with 7881 additions and 4687 deletions
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)?,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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."));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
},
|
||||
)?;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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.")
|
||||
})
|
||||
},
|
||||
)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 {})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue