use chain_width 60
Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
parent
9d6b070f35
commit
868976a149
98 changed files with 4836 additions and 1767 deletions
|
@ -36,7 +36,11 @@ where
|
|||
"?"
|
||||
};
|
||||
|
||||
parts.path_and_query = Some((old_path_and_query + symbol + "access_token=" + hs_token).parse().unwrap());
|
||||
parts.path_and_query = Some(
|
||||
(old_path_and_query + symbol + "access_token=" + hs_token)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
*http_request.uri_mut() = parts.try_into().expect("our manipulation is always valid");
|
||||
|
||||
let mut reqwest_request =
|
||||
|
@ -64,7 +68,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let mut response = match services().globals.client.appservice.execute(reqwest_request).await {
|
||||
let mut response = match services()
|
||||
.globals
|
||||
.client
|
||||
.appservice
|
||||
.execute(reqwest_request)
|
||||
.await
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
|
@ -77,10 +87,14 @@ where
|
|||
|
||||
// reqwest::Response -> http::Response conversion
|
||||
let status = response.status();
|
||||
let mut http_response_builder = http::Response::builder().status(status).version(response.version());
|
||||
let mut http_response_builder = http::Response::builder()
|
||||
.status(status)
|
||||
.version(response.version());
|
||||
mem::swap(
|
||||
response.headers_mut(),
|
||||
http_response_builder.headers_mut().expect("http::response::Builder is usable"),
|
||||
http_response_builder
|
||||
.headers_mut()
|
||||
.expect("http::response::Builder is usable"),
|
||||
);
|
||||
|
||||
let body = response.bytes().await.unwrap_or_else(|e| {
|
||||
|
@ -99,7 +113,9 @@ where
|
|||
}
|
||||
|
||||
let response = T::IncomingResponse::try_from_http_response(
|
||||
http_response_builder.body(body).expect("reqwest body is valid http body"),
|
||||
http_response_builder
|
||||
.body(body)
|
||||
.expect("reqwest body is valid http body"),
|
||||
);
|
||||
|
||||
Some(response.map_err(|_| {
|
||||
|
|
|
@ -47,7 +47,11 @@ pub async fn get_register_available_route(
|
|||
return Err(Error::BadRequest(ErrorKind::UserInUse, "Desired user ID is already taken."));
|
||||
}
|
||||
|
||||
if services().globals.forbidden_usernames().is_match(user_id.localpart()) {
|
||||
if services()
|
||||
.globals
|
||||
.forbidden_usernames()
|
||||
.is_match(user_id.localpart())
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Unknown, "Username is forbidden."));
|
||||
}
|
||||
|
||||
|
@ -129,7 +133,11 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
return Err(Error::BadRequest(ErrorKind::UserInUse, "Desired user ID is already taken."));
|
||||
}
|
||||
|
||||
if services().globals.forbidden_usernames().is_match(proposed_user_id.localpart()) {
|
||||
if services()
|
||||
.globals
|
||||
.forbidden_usernames()
|
||||
.is_match(proposed_user_id.localpart())
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Unknown, "Username is forbidden."));
|
||||
}
|
||||
|
||||
|
@ -220,7 +228,10 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
displayname.push_str(&(" ".to_owned() + services().globals.new_user_displayname_suffix()));
|
||||
}
|
||||
|
||||
services().users.set_displayname(&user_id, Some(displayname.clone())).await?;
|
||||
services()
|
||||
.users
|
||||
.set_displayname(&user_id, Some(displayname.clone()))
|
||||
.await?;
|
||||
|
||||
// Initial account data
|
||||
services().account_data.update(
|
||||
|
@ -258,31 +269,45 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
let token = utils::random_string(TOKEN_LENGTH);
|
||||
|
||||
// Create device for this account
|
||||
services().users.create_device(&user_id, &device_id, &token, body.initial_device_display_name.clone())?;
|
||||
services()
|
||||
.users
|
||||
.create_device(&user_id, &device_id, &token, body.initial_device_display_name.clone())?;
|
||||
|
||||
info!("New user \"{}\" registered on this server.", user_id);
|
||||
|
||||
// log in conduit admin channel if a non-guest user registered
|
||||
if !body.from_appservice && !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."
|
||||
)));
|
||||
}
|
||||
|
||||
// log in conduit admin channel if a guest registered
|
||||
if !body.from_appservice && is_guest {
|
||||
services().admin.send_message(RoomMessageEventContent::notice_plain(format!(
|
||||
"Guest user \"{user_id}\" with device display name `{:?}` registered on this server.",
|
||||
body.initial_device_display_name
|
||||
)));
|
||||
services()
|
||||
.admin
|
||||
.send_message(RoomMessageEventContent::notice_plain(format!(
|
||||
"Guest user \"{user_id}\" with device display name `{:?}` registered on this server.",
|
||||
body.initial_device_display_name
|
||||
)));
|
||||
}
|
||||
|
||||
// If this is the first real user, grant them admin privileges except for guest
|
||||
// users Note: the server user, @conduit:servername, is generated first
|
||||
if !is_guest {
|
||||
if let Some(admin_room) = service::admin::Service::get_admin_room()? {
|
||||
if services().rooms.state_cache.room_joined_count(&admin_room)? == Some(1) {
|
||||
services().admin.make_user_admin(&user_id, displayname).await?;
|
||||
if services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_joined_count(&admin_room)?
|
||||
== Some(1)
|
||||
{
|
||||
services()
|
||||
.admin
|
||||
.make_user_admin(&user_id, displayname)
|
||||
.await?;
|
||||
|
||||
warn!("Granting {} admin privileges as the first user", user_id);
|
||||
}
|
||||
|
@ -291,7 +316,11 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
|
||||
if !services().globals.config.auto_join_rooms.is_empty() {
|
||||
for room in &services().globals.config.auto_join_rooms {
|
||||
if !services().rooms.state_cache.server_in_room(services().globals.server_name(), room)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(services().globals.server_name(), room)?
|
||||
{
|
||||
warn!("Skipping room {room} to automatically join as we have never joined before.");
|
||||
continue;
|
||||
}
|
||||
|
@ -359,32 +388,45 @@ pub async fn change_password_route(body: Ruma<change_password::v3::Request>) ->
|
|||
};
|
||||
|
||||
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
|
||||
for id in services().users.all_device_ids(sender_user).filter_map(Result::ok).filter(|id| id != sender_device) {
|
||||
for id in services()
|
||||
.users
|
||||
.all_device_ids(sender_user)
|
||||
.filter_map(Result::ok)
|
||||
.filter(|id| id != sender_device)
|
||||
{
|
||||
services().users.remove_device(sender_user, &id)?;
|
||||
}
|
||||
}
|
||||
|
||||
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 {})
|
||||
}
|
||||
|
@ -431,14 +473,18 @@ pub async fn deactivate_route(body: Ruma<deactivate::v3::Request>) -> Result<dea
|
|||
};
|
||||
|
||||
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."));
|
||||
|
@ -451,9 +497,11 @@ pub async fn deactivate_route(body: Ruma<deactivate::v3::Request>) -> Result<dea
|
|||
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,
|
||||
|
|
|
@ -21,15 +21,29 @@ pub async fn create_alias_route(body: Ruma<create_alias::v3::Request>) -> Result
|
|||
return Err(Error::BadRequest(ErrorKind::InvalidParam, "Alias is from another server."));
|
||||
}
|
||||
|
||||
if services().globals.forbidden_alias_names().is_match(body.room_alias.alias()) {
|
||||
if services()
|
||||
.globals
|
||||
.forbidden_alias_names()
|
||||
.is_match(body.room_alias.alias())
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Unknown, "Room alias is forbidden."));
|
||||
}
|
||||
|
||||
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."));
|
||||
}
|
||||
|
||||
if services().rooms.alias.set_alias(&body.room_alias, &body.room_id).is_err() {
|
||||
if services()
|
||||
.rooms
|
||||
.alias
|
||||
.set_alias(&body.room_alias, &body.room_id)
|
||||
.is_err()
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Invalid room alias. Alias must be in the form of '#localpart:server_name'",
|
||||
|
@ -50,11 +64,21 @@ pub async fn delete_alias_route(body: Ruma<delete_alias::v3::Request>) -> Result
|
|||
return Err(Error::BadRequest(ErrorKind::InvalidParam, "Alias is from another server."));
|
||||
}
|
||||
|
||||
if services().rooms.alias.resolve_local_alias(&body.room_alias)?.is_none() {
|
||||
if services()
|
||||
.rooms
|
||||
.alias
|
||||
.resolve_local_alias(&body.room_alias)?
|
||||
.is_none()
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Alias does not exist."));
|
||||
}
|
||||
|
||||
if services().rooms.alias.remove_alias(&body.room_alias).is_err() {
|
||||
if services()
|
||||
.rooms
|
||||
.alias
|
||||
.remove_alias(&body.room_alias)
|
||||
.is_err()
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Invalid room alias. Alias must be in the form of '#localpart:server_name'",
|
||||
|
@ -90,13 +114,20 @@ pub(crate) async fn get_alias_helper(room_alias: OwnedRoomAliasId) -> Result<get
|
|||
let mut servers = response.servers;
|
||||
|
||||
// find active servers in room state cache to suggest
|
||||
for extra_servers in services().rooms.state_cache.room_servers(&room_id).filter_map(Result::ok) {
|
||||
for extra_servers in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_servers(&room_id)
|
||||
.filter_map(Result::ok)
|
||||
{
|
||||
servers.push(extra_servers);
|
||||
}
|
||||
|
||||
// insert our server as the very first choice if in list
|
||||
if let Some(server_index) =
|
||||
servers.clone().into_iter().position(|server| server == services().globals.server_name())
|
||||
if let Some(server_index) = servers
|
||||
.clone()
|
||||
.into_iter()
|
||||
.position(|server| server == services().globals.server_name())
|
||||
{
|
||||
servers.remove(server_index);
|
||||
servers.insert(0, services().globals.server_name().to_owned());
|
||||
|
@ -151,13 +182,20 @@ pub(crate) async fn get_alias_helper(room_alias: OwnedRoomAliasId) -> Result<get
|
|||
let mut servers: Vec<OwnedServerName> = Vec::new();
|
||||
|
||||
// find active servers in room state cache to suggest
|
||||
for extra_servers in services().rooms.state_cache.room_servers(&room_id).filter_map(Result::ok) {
|
||||
for extra_servers in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_servers(&room_id)
|
||||
.filter_map(Result::ok)
|
||||
{
|
||||
servers.push(extra_servers);
|
||||
}
|
||||
|
||||
// insert our server as the very first choice if in list
|
||||
if let Some(server_index) =
|
||||
servers.clone().into_iter().position(|server| server == services().globals.server_name())
|
||||
if let Some(server_index) = servers
|
||||
.clone()
|
||||
.into_iter()
|
||||
.position(|server| server == services().globals.server_name())
|
||||
{
|
||||
servers.remove(server_index);
|
||||
servers.insert(0, services().globals.server_name().to_owned());
|
||||
|
|
|
@ -17,7 +17,9 @@ pub 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,
|
||||
|
@ -32,7 +34,9 @@ pub 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 {})
|
||||
}
|
||||
|
@ -70,8 +74,13 @@ pub async fn get_backup_info_route(body: Ruma<get_backup_info::v3::Request>) ->
|
|||
|
||||
Ok(get_backup_info::v3::Response {
|
||||
algorithm,
|
||||
count: (services().key_backups.count_keys(sender_user, &body.version)? as u32).into(),
|
||||
etag: services().key_backups.get_etag(sender_user, &body.version)?,
|
||||
count: (services()
|
||||
.key_backups
|
||||
.count_keys(sender_user, &body.version)? as u32)
|
||||
.into(),
|
||||
etag: services()
|
||||
.key_backups
|
||||
.get_etag(sender_user, &body.version)?,
|
||||
version: body.version.clone(),
|
||||
})
|
||||
}
|
||||
|
@ -87,7 +96,9 @@ pub async fn delete_backup_version_route(
|
|||
) -> 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 {})
|
||||
}
|
||||
|
@ -103,7 +114,12 @@ pub async fn delete_backup_version_route(
|
|||
pub async fn add_backup_keys_route(body: Ruma<add_backup_keys::v3::Request>) -> Result<add_backup_keys::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if Some(&body.version) != services().key_backups.get_latest_backup_version(sender_user)?.as_ref() {
|
||||
if Some(&body.version)
|
||||
!= services()
|
||||
.key_backups
|
||||
.get_latest_backup_version(sender_user)?
|
||||
.as_ref()
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"You may only manipulate the most recently created version of the backup.",
|
||||
|
@ -112,13 +128,20 @@ pub async fn add_backup_keys_route(body: Ruma<add_backup_keys::v3::Request>) ->
|
|||
|
||||
for (room_id, room) in &body.rooms {
|
||||
for (session_id, key_data) in &room.sessions {
|
||||
services().key_backups.add_key(sender_user, &body.version, room_id, session_id, key_data)?;
|
||||
services()
|
||||
.key_backups
|
||||
.add_key(sender_user, &body.version, room_id, session_id, key_data)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(add_backup_keys::v3::Response {
|
||||
count: (services().key_backups.count_keys(sender_user, &body.version)? as u32).into(),
|
||||
etag: services().key_backups.get_etag(sender_user, &body.version)?,
|
||||
count: (services()
|
||||
.key_backups
|
||||
.count_keys(sender_user, &body.version)? as u32)
|
||||
.into(),
|
||||
etag: services()
|
||||
.key_backups
|
||||
.get_etag(sender_user, &body.version)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -135,7 +158,12 @@ pub async fn add_backup_keys_for_room_route(
|
|||
) -> Result<add_backup_keys_for_room::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if Some(&body.version) != services().key_backups.get_latest_backup_version(sender_user)?.as_ref() {
|
||||
if Some(&body.version)
|
||||
!= services()
|
||||
.key_backups
|
||||
.get_latest_backup_version(sender_user)?
|
||||
.as_ref()
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"You may only manipulate the most recently created version of the backup.",
|
||||
|
@ -143,12 +171,19 @@ pub async fn add_backup_keys_for_room_route(
|
|||
}
|
||||
|
||||
for (session_id, key_data) in &body.sessions {
|
||||
services().key_backups.add_key(sender_user, &body.version, &body.room_id, session_id, key_data)?;
|
||||
services()
|
||||
.key_backups
|
||||
.add_key(sender_user, &body.version, &body.room_id, session_id, key_data)?;
|
||||
}
|
||||
|
||||
Ok(add_backup_keys_for_room::v3::Response {
|
||||
count: (services().key_backups.count_keys(sender_user, &body.version)? as u32).into(),
|
||||
etag: services().key_backups.get_etag(sender_user, &body.version)?,
|
||||
count: (services()
|
||||
.key_backups
|
||||
.count_keys(sender_user, &body.version)? as u32)
|
||||
.into(),
|
||||
etag: services()
|
||||
.key_backups
|
||||
.get_etag(sender_user, &body.version)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -165,18 +200,30 @@ pub async fn add_backup_keys_for_session_route(
|
|||
) -> Result<add_backup_keys_for_session::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if Some(&body.version) != services().key_backups.get_latest_backup_version(sender_user)?.as_ref() {
|
||||
if Some(&body.version)
|
||||
!= services()
|
||||
.key_backups
|
||||
.get_latest_backup_version(sender_user)?
|
||||
.as_ref()
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"You may only manipulate the most recently created version of the backup.",
|
||||
));
|
||||
}
|
||||
|
||||
services().key_backups.add_key(sender_user, &body.version, &body.room_id, &body.session_id, &body.session_data)?;
|
||||
services()
|
||||
.key_backups
|
||||
.add_key(sender_user, &body.version, &body.room_id, &body.session_id, &body.session_data)?;
|
||||
|
||||
Ok(add_backup_keys_for_session::v3::Response {
|
||||
count: (services().key_backups.count_keys(sender_user, &body.version)? as u32).into(),
|
||||
etag: services().key_backups.get_etag(sender_user, &body.version)?,
|
||||
count: (services()
|
||||
.key_backups
|
||||
.count_keys(sender_user, &body.version)? as u32)
|
||||
.into(),
|
||||
etag: services()
|
||||
.key_backups
|
||||
.get_etag(sender_user, &body.version)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -201,7 +248,9 @@ pub 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,
|
||||
|
@ -216,10 +265,13 @@ pub async fn get_backup_keys_for_session_route(
|
|||
) -> Result<get_backup_keys_for_session::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
let key_data =
|
||||
services().key_backups.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."),
|
||||
)?;
|
||||
let key_data = services()
|
||||
.key_backups
|
||||
.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,
|
||||
|
@ -234,11 +286,18 @@ pub 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().key_backups.count_keys(sender_user, &body.version)? as u32).into(),
|
||||
etag: services().key_backups.get_etag(sender_user, &body.version)?,
|
||||
count: (services()
|
||||
.key_backups
|
||||
.count_keys(sender_user, &body.version)? as u32)
|
||||
.into(),
|
||||
etag: services()
|
||||
.key_backups
|
||||
.get_etag(sender_user, &body.version)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -250,11 +309,18 @@ pub 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().key_backups.count_keys(sender_user, &body.version)? as u32).into(),
|
||||
etag: services().key_backups.get_etag(sender_user, &body.version)?,
|
||||
count: (services()
|
||||
.key_backups
|
||||
.count_keys(sender_user, &body.version)? as u32)
|
||||
.into(),
|
||||
etag: services()
|
||||
.key_backups
|
||||
.get_etag(sender_user, &body.version)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -266,10 +332,17 @@ pub async fn delete_backup_keys_for_session_route(
|
|||
) -> Result<delete_backup_keys_for_session::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
services().key_backups.delete_room_key(sender_user, &body.version, &body.room_id, &body.session_id)?;
|
||||
services()
|
||||
.key_backups
|
||||
.delete_room_key(sender_user, &body.version, &body.room_id, &body.session_id)?;
|
||||
|
||||
Ok(delete_backup_keys_for_session::v3::Response {
|
||||
count: (services().key_backups.count_keys(sender_user, &body.version)? as u32).into(),
|
||||
etag: services().key_backups.get_etag(sender_user, &body.version)?,
|
||||
count: (services()
|
||||
.key_backups
|
||||
.count_keys(sender_user, &body.version)? as u32)
|
||||
.into(),
|
||||
etag: services()
|
||||
.key_backups
|
||||
.get_etag(sender_user, &body.version)?,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -42,7 +42,11 @@ pub async fn get_context_route(body: Ruma<get_context::v3::Request>) -> Result<g
|
|||
|
||||
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.",
|
||||
|
@ -91,9 +95,14 @@ pub async fn get_context_route(body: Ruma<get_context::v3::Request>) -> Result<g
|
|||
}
|
||||
}
|
||||
|
||||
let start_token = events_before.last().map_or_else(|| base_token.stringify(), |(count, _)| count.stringify());
|
||||
let start_token = events_before
|
||||
.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
|
||||
|
@ -122,25 +131,41 @@ pub async fn get_context_route(body: Ruma<get_context::v3::Request>) -> Result<g
|
|||
}
|
||||
}
|
||||
|
||||
let shortstatehash = match services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.pdu_shortstatehash(events_after.last().map_or(&*body.event_id, |(_, e)| &*e.event_id))?
|
||||
{
|
||||
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"),
|
||||
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 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 {
|
||||
|
|
|
@ -53,7 +53,9 @@ pub async fn update_device_route(body: Ruma<update_device::v3::Request>) -> Resu
|
|||
|
||||
device.display_name.clone_from(&body.display_name);
|
||||
|
||||
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 {})
|
||||
}
|
||||
|
@ -84,20 +86,26 @@ pub async fn delete_device_route(body: Ruma<delete_device::v3::Request>) -> Resu
|
|||
};
|
||||
|
||||
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 {})
|
||||
}
|
||||
|
@ -130,14 +138,18 @@ pub async fn delete_devices_route(body: Ruma<delete_devices::v3::Request>) -> Re
|
|||
};
|
||||
|
||||
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."));
|
||||
|
|
|
@ -34,7 +34,11 @@ use crate::{services, Error, Result, Ruma};
|
|||
pub async fn get_public_rooms_filtered_route(
|
||||
body: Ruma<get_public_rooms_filtered::v3::Request>,
|
||||
) -> Result<get_public_rooms_filtered::v3::Response> {
|
||||
if !services().globals.config.allow_public_room_directory_without_auth {
|
||||
if !services()
|
||||
.globals
|
||||
.config
|
||||
.allow_public_room_directory_without_auth
|
||||
{
|
||||
let _sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
}
|
||||
|
||||
|
@ -56,7 +60,11 @@ pub async fn get_public_rooms_filtered_route(
|
|||
pub async fn get_public_rooms_route(
|
||||
body: Ruma<get_public_rooms::v3::Request>,
|
||||
) -> Result<get_public_rooms::v3::Response> {
|
||||
if !services().globals.config.allow_public_room_directory_without_auth {
|
||||
if !services()
|
||||
.globals
|
||||
.config
|
||||
.allow_public_room_directory_without_auth
|
||||
{
|
||||
let _sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
}
|
||||
|
||||
|
@ -325,7 +333,11 @@ pub(crate) async fn get_public_rooms_filtered_helper(
|
|||
|
||||
let total_room_count_estimate = (all_rooms.len() as u32).into();
|
||||
|
||||
let chunk: Vec<_> = all_rooms.into_iter().skip(num_since as usize).take(limit as usize).collect();
|
||||
let chunk: Vec<_> = all_rooms
|
||||
.into_iter()
|
||||
.skip(num_since as usize)
|
||||
.take(limit as usize)
|
||||
.collect();
|
||||
|
||||
let prev_batch = if num_since == 0 {
|
||||
None
|
||||
|
|
|
@ -34,19 +34,29 @@ pub async fn upload_keys_route(body: Ruma<upload_keys::v3::Request>) -> Result<u
|
|||
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 {
|
||||
// TODO: merge this and the existing event?
|
||||
// This check is needed to assure that signatures are kept
|
||||
if services().users.get_device_keys(sender_user, sender_device)?.is_none() {
|
||||
services().users.add_device_keys(sender_user, sender_device, device_keys)?;
|
||||
if services()
|
||||
.users
|
||||
.get_device_keys(sender_user, sender_device)?
|
||||
.is_none()
|
||||
{
|
||||
services()
|
||||
.users
|
||||
.add_device_keys(sender_user, sender_device, device_keys)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(upload_keys::v3::Response {
|
||||
one_time_key_counts: services().users.count_one_time_keys(sender_user, sender_device)?,
|
||||
one_time_key_counts: services()
|
||||
.users
|
||||
.count_one_time_keys(sender_user, sender_device)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -104,14 +114,18 @@ pub 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."));
|
||||
|
@ -161,7 +175,9 @@ pub async fn upload_signatures_route(
|
|||
.ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Invalid signature value."))?
|
||||
.to_owned(),
|
||||
);
|
||||
services().users.sign_key(user_id, key_id, signature, sender_user)?;
|
||||
services()
|
||||
.users
|
||||
.sign_key(user_id, key_id, signature, sender_user)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,20 +203,37 @@ pub async fn get_key_changes_route(body: Ruma<get_key_changes::v3::Request>) ->
|
|||
.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),
|
||||
);
|
||||
|
||||
for room_id in services().rooms.state_cache.rooms_joined(sender_user).filter_map(Result::ok) {
|
||||
for room_id in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.rooms_joined(sender_user)
|
||||
.filter_map(Result::ok)
|
||||
{
|
||||
device_list_updates.extend(
|
||||
services()
|
||||
.users
|
||||
.keys_changed(
|
||||
room_id.as_ref(),
|
||||
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),
|
||||
);
|
||||
|
@ -226,7 +259,10 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
let user_id: &UserId = user_id;
|
||||
|
||||
if user_id.server_name() != services().globals.server_name() {
|
||||
get_over_federation.entry(user_id.server_name()).or_insert_with(Vec::new).push((user_id, device_ids));
|
||||
get_over_federation
|
||||
.entry(user_id.server_name())
|
||||
.or_insert_with(Vec::new)
|
||||
.push((user_id, device_ids));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -251,9 +287,13 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
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)? {
|
||||
let metadata = services().users.get_device_metadata(user_id, device_id)?.ok_or(
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Tried to get keys for nonexistent device."),
|
||||
)?;
|
||||
let metadata = services()
|
||||
.users
|
||||
.get_device_metadata(user_id, device_id)?
|
||||
.ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Tried to get keys for nonexistent device.",
|
||||
))?;
|
||||
|
||||
add_unsigned_device_display_name(&mut keys, metadata, include_display_names)
|
||||
.map_err(|_| Error::bad_database("invalid device keys in database"))?;
|
||||
|
@ -263,11 +303,16 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
}
|
||||
}
|
||||
|
||||
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)?
|
||||
services()
|
||||
.users
|
||||
.get_self_signing_key(sender_user, user_id, &allowed_signatures)?
|
||||
{
|
||||
self_signing_keys.insert(user_id.to_owned(), self_signing_key);
|
||||
}
|
||||
|
@ -281,7 +326,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));
|
||||
},
|
||||
|
@ -292,7 +343,13 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
let mut futures: FuturesUnordered<_> = get_over_federation
|
||||
.into_iter()
|
||||
.map(|(server, vec)| async move {
|
||||
if let Some((time, tries)) = services().globals.bad_query_ratelimiter.read().await.get(server) {
|
||||
if let Some((time, tries)) = services()
|
||||
.globals
|
||||
.bad_query_ratelimiter
|
||||
.read()
|
||||
.await
|
||||
.get(server)
|
||||
{
|
||||
// Exponential backoff
|
||||
let mut min_elapsed_duration = Duration::from_secs(5 * 60) * (*tries) * (*tries);
|
||||
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
|
||||
|
@ -336,7 +393,9 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
let (master_key_id, mut master_key) = services().users.parse_master_key(&user, &masterkey)?;
|
||||
|
||||
if let Some(our_master_key) =
|
||||
services().users.get_key(&master_key_id, sender_user, &user, &allowed_signatures)?
|
||||
services()
|
||||
.users
|
||||
.get_key(&master_key_id, sender_user, &user, &allowed_signatures)?
|
||||
{
|
||||
let (_, our_master_key) = services().users.parse_master_key(&user, &our_master_key)?;
|
||||
master_key.signatures.extend(our_master_key.signatures);
|
||||
|
@ -404,12 +463,18 @@ pub(crate) async fn claim_keys_helper(
|
|||
|
||||
for (user_id, map) in one_time_keys_input {
|
||||
if user_id.server_name() != services().globals.server_name() {
|
||||
get_over_federation.entry(user_id.server_name()).or_insert_with(Vec::new).push((user_id, map));
|
||||
get_over_federation
|
||||
.entry(user_id.server_name())
|
||||
.or_insert_with(Vec::new)
|
||||
.push((user_id, map));
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -152,7 +152,10 @@ pub async fn create_content_route(body: Ruma<create_content::v3::Request>) -> Re
|
|||
.create(
|
||||
Some(sender_user.clone()),
|
||||
mxc.clone(),
|
||||
body.filename.as_ref().map(|filename| "inline; filename=".to_owned() + filename).as_deref(),
|
||||
body.filename
|
||||
.as_ref()
|
||||
.map(|filename| "inline; filename=".to_owned() + filename)
|
||||
.as_deref(),
|
||||
body.content_type.as_deref(),
|
||||
&body.file,
|
||||
)
|
||||
|
@ -192,7 +195,10 @@ pub async fn create_content_v1_route(
|
|||
.create(
|
||||
Some(sender_user.clone()),
|
||||
mxc.clone(),
|
||||
body.filename.as_ref().map(|filename| "inline; filename=".to_owned() + filename).as_deref(),
|
||||
body.filename
|
||||
.as_ref()
|
||||
.map(|filename| "inline; filename=".to_owned() + filename)
|
||||
.as_deref(),
|
||||
body.content_type.as_deref(),
|
||||
&body.file,
|
||||
)
|
||||
|
@ -213,7 +219,11 @@ pub async fn get_remote_content(
|
|||
) -> Result<get_content::v3::Response, Error> {
|
||||
// we'll lie to the client and say the blocked server's media was not found and
|
||||
// log. the client has no way of telling anyways so this is a security bonus.
|
||||
if services().globals.prevent_media_downloads_from().contains(&server_name.to_owned()) {
|
||||
if services()
|
||||
.globals
|
||||
.prevent_media_downloads_from()
|
||||
.contains(&server_name.to_owned())
|
||||
{
|
||||
info!(
|
||||
"Received request for remote media `{}` but server is in our media server blocklist. Returning 404.",
|
||||
mxc
|
||||
|
@ -451,8 +461,12 @@ pub async fn get_content_thumbnail_route(
|
|||
.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, "Height 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, "Height is invalid."))?,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
|
@ -464,7 +478,11 @@ pub async fn get_content_thumbnail_route(
|
|||
} else if &*body.server_name != services().globals.server_name() && body.allow_remote {
|
||||
// we'll lie to the client and say the blocked server's media was not found and
|
||||
// log. the client has no way of telling anyways so this is a security bonus.
|
||||
if services().globals.prevent_media_downloads_from().contains(&body.server_name.clone()) {
|
||||
if services()
|
||||
.globals
|
||||
.prevent_media_downloads_from()
|
||||
.contains(&body.server_name.clone())
|
||||
{
|
||||
info!(
|
||||
"Received request for remote media `{}` but server is in our media server blocklist. Returning 404.",
|
||||
mxc
|
||||
|
@ -533,8 +551,12 @@ pub async fn get_content_thumbnail_v1_route(
|
|||
.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, "Height 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, "Height is invalid."))?,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
|
@ -547,7 +569,11 @@ pub async fn get_content_thumbnail_v1_route(
|
|||
} else if &*body.server_name != services().globals.server_name() && body.allow_remote {
|
||||
// we'll lie to the client and say the blocked server's media was not found and
|
||||
// log. the client has no way of telling anyways so this is a security bonus.
|
||||
if services().globals.prevent_media_downloads_from().contains(&body.server_name.clone()) {
|
||||
if services()
|
||||
.globals
|
||||
.prevent_media_downloads_from()
|
||||
.contains(&body.server_name.clone())
|
||||
{
|
||||
info!(
|
||||
"Received request for remote media `{}` but server is in our media server blocklist. Returning 404.",
|
||||
mxc
|
||||
|
@ -599,7 +625,10 @@ async fn download_image(client: &reqwest::Client, url: &str) -> Result<UrlPrevie
|
|||
utils::random_string(MXC_LENGTH)
|
||||
);
|
||||
|
||||
services().media.create(None, mxc.clone(), None, None, &image).await?;
|
||||
services()
|
||||
.media
|
||||
.create(None, mxc.clone(), None, None, &image)
|
||||
.await?;
|
||||
|
||||
let (width, height) = match ImgReader::new(Cursor::new(&image)).with_guessed_format() {
|
||||
Err(_) => (None, None),
|
||||
|
@ -749,14 +778,21 @@ async fn request_url_preview(url: &str) -> Result<UrlPreviewData> {
|
|||
}
|
||||
}
|
||||
|
||||
if !response.remote_addr().map_or(false, |a| url_request_allowed(&a.ip())) {
|
||||
if !response
|
||||
.remote_addr()
|
||||
.map_or(false, |a| url_request_allowed(&a.ip()))
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Requesting from this address is forbidden",
|
||||
));
|
||||
}
|
||||
|
||||
let content_type = match response.headers().get(reqwest::header::CONTENT_TYPE).and_then(|x| x.to_str().ok()) {
|
||||
let content_type = match response
|
||||
.headers()
|
||||
.get(reqwest::header::CONTENT_TYPE)
|
||||
.and_then(|x| x.to_str().ok())
|
||||
{
|
||||
Some(ct) => ct,
|
||||
None => return Err(Error::BadRequest(ErrorKind::Unknown, "Unknown Content-Type")),
|
||||
};
|
||||
|
@ -777,7 +813,15 @@ async fn get_url_preview(url: &str) -> Result<UrlPreviewData> {
|
|||
}
|
||||
|
||||
// ensure that only one request is made per URL
|
||||
let mutex_request = Arc::clone(services().media.url_preview_mutex.write().await.entry(url.to_owned()).or_default());
|
||||
let mutex_request = Arc::clone(
|
||||
services()
|
||||
.media
|
||||
.url_preview_mutex
|
||||
.write()
|
||||
.await
|
||||
.entry(url.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let _request_lock = mutex_request.lock().await;
|
||||
|
||||
match services().media.get_url_preview(url).await {
|
||||
|
@ -795,7 +839,10 @@ fn url_preview_allowed(url_str: &str) -> bool {
|
|||
},
|
||||
};
|
||||
|
||||
if ["http", "https"].iter().all(|&scheme| scheme != url.scheme().to_lowercase()) {
|
||||
if ["http", "https"]
|
||||
.iter()
|
||||
.all(|&scheme| scheme != url.scheme().to_lowercase())
|
||||
{
|
||||
debug!("Ignoring non-HTTP/HTTPS URL to preview: {}", url);
|
||||
return false;
|
||||
}
|
||||
|
@ -826,12 +873,18 @@ fn url_preview_allowed(url_str: &str) -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
if allowlist_domain_contains.iter().any(|domain_s| domain_s.contains(&host.clone())) {
|
||||
if allowlist_domain_contains
|
||||
.iter()
|
||||
.any(|domain_s| domain_s.contains(&host.clone()))
|
||||
{
|
||||
debug!("Host {} is allowed by url_preview_domain_contains_allowlist (check 2/3)", &host);
|
||||
return true;
|
||||
}
|
||||
|
||||
if allowlist_url_contains.iter().any(|url_s| url.to_string().contains(&url_s.to_string())) {
|
||||
if allowlist_url_contains
|
||||
.iter()
|
||||
.any(|url_s| url.to_string().contains(&url_s.to_string()))
|
||||
{
|
||||
debug!("URL {} is allowed by url_preview_url_contains_allowlist (check 3/3)", &host);
|
||||
return true;
|
||||
}
|
||||
|
@ -850,7 +903,10 @@ fn url_preview_allowed(url_str: &str) -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
if allowlist_domain_contains.iter().any(|domain_s| domain_s.contains(&root_domain.to_owned())) {
|
||||
if allowlist_domain_contains
|
||||
.iter()
|
||||
.any(|domain_s| domain_s.contains(&root_domain.to_owned()))
|
||||
{
|
||||
debug!(
|
||||
"Root domain {} is allowed by url_preview_domain_contains_allowlist (check 2/3)",
|
||||
&root_domain
|
||||
|
|
|
@ -242,8 +242,15 @@ pub async fn kick_user_route(body: Ruma<kick_user::v3::Request>) -> Result<kick_
|
|||
event.membership = MembershipState::Leave;
|
||||
event.reason.clone_from(&body.reason);
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(body.room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
services()
|
||||
|
@ -293,8 +300,14 @@ pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_use
|
|||
serde_json::from_str(event.content.get())
|
||||
.map(|event: RoomMemberEventContent| RoomMemberEventContent {
|
||||
membership: MembershipState::Ban,
|
||||
displayname: services().users.displayname(&body.user_id).unwrap_or_default(),
|
||||
avatar_url: services().users.avatar_url(&body.user_id).unwrap_or_default(),
|
||||
displayname: services()
|
||||
.users
|
||||
.displayname(&body.user_id)
|
||||
.unwrap_or_default(),
|
||||
avatar_url: services()
|
||||
.users
|
||||
.avatar_url(&body.user_id)
|
||||
.unwrap_or_default(),
|
||||
blurhash: services().users.blurhash(&body.user_id).unwrap_or_default(),
|
||||
reason: body.reason.clone(),
|
||||
..event
|
||||
|
@ -303,8 +316,15 @@ pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_use
|
|||
},
|
||||
)?;
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(body.room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
services()
|
||||
|
@ -349,8 +369,15 @@ pub async fn unban_user_route(body: Ruma<unban_user::v3::Request>) -> Result<unb
|
|||
event.membership = MembershipState::Leave;
|
||||
event.reason.clone_from(&body.reason);
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(body.room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
services()
|
||||
|
@ -387,7 +414,10 @@ pub async fn unban_user_route(body: Ruma<unban_user::v3::Request>) -> Result<unb
|
|||
pub async fn forget_room_route(body: Ruma<forget_room::v3::Request>) -> Result<forget_room::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
services().rooms.state_cache.forget(&body.room_id, sender_user)?;
|
||||
services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.forget(&body.room_id, sender_user)?;
|
||||
|
||||
Ok(forget_room::v3::Response::new())
|
||||
}
|
||||
|
@ -399,7 +429,12 @@ pub async fn joined_rooms_route(body: Ruma<joined_rooms::v3::Request>) -> Result
|
|||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
Ok(joined_rooms::v3::Response {
|
||||
joined_rooms: services().rooms.state_cache.rooms_joined(sender_user).filter_map(Result::ok).collect(),
|
||||
joined_rooms: services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.rooms_joined(sender_user)
|
||||
.filter_map(Result::ok)
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -414,7 +449,11 @@ pub async fn get_member_events_route(
|
|||
) -> Result<get_member_events::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if !services().rooms.state_accessor.user_can_see_state_events(sender_user, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"You don't have permission to view this room.",
|
||||
|
@ -443,7 +482,11 @@ pub async fn get_member_events_route(
|
|||
pub async fn joined_members_route(body: Ruma<joined_members::v3::Request>) -> Result<joined_members::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if !services().rooms.state_accessor.user_can_see_state_events(sender_user, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"You don't have permission to view this room.",
|
||||
|
@ -451,7 +494,12 @@ pub async fn joined_members_route(body: Ruma<joined_members::v3::Request>) -> Re
|
|||
}
|
||||
|
||||
let mut joined = BTreeMap::new();
|
||||
for user_id in services().rooms.state_cache.room_members(&body.room_id).filter_map(Result::ok) {
|
||||
for user_id in services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&body.room_id)
|
||||
.filter_map(Result::ok)
|
||||
{
|
||||
let display_name = services().users.displayname(&user_id)?;
|
||||
let avatar_url = services().users.avatar_url(&user_id)?;
|
||||
|
||||
|
@ -475,12 +523,23 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
) -> Result<join_room_by_id::v3::Response> {
|
||||
let sender_user = sender_user.expect("user is authenticated");
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(room_id.to_owned()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
// Ask a remote server if we are not participating in this room
|
||||
if !services().rooms.state_cache.server_in_room(services().globals.server_name(), room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(services().globals.server_name(), room_id)?
|
||||
{
|
||||
info!("Joining {room_id} over federation.");
|
||||
|
||||
let (make_join_response, remote_server) = make_join_request(sender_user, room_id, servers).await?;
|
||||
|
@ -488,7 +547,14 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
info!("make_join finished");
|
||||
|
||||
let room_version_id = match make_join_response.room_version {
|
||||
Some(room_version) if services().globals.supported_room_versions().contains(&room_version) => room_version,
|
||||
Some(room_version)
|
||||
if services()
|
||||
.globals
|
||||
.supported_room_versions()
|
||||
.contains(&room_version) =>
|
||||
{
|
||||
room_version
|
||||
},
|
||||
_ => return Err(Error::BadServerResponse("Room version is not supported")),
|
||||
};
|
||||
|
||||
|
@ -497,7 +563,11 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
|
||||
let join_authorized_via_users_server = join_event_stub
|
||||
.get("content")
|
||||
.map(|s| s.as_object()?.get("join_authorised_via_users_server")?.as_str())
|
||||
.map(|s| {
|
||||
s.as_object()?
|
||||
.get("join_authorised_via_users_server")?
|
||||
.as_str()
|
||||
})
|
||||
.and_then(|s| OwnedUserId::try_from(s.unwrap_or_default()).ok());
|
||||
|
||||
// TODO: Is origin needed?
|
||||
|
@ -508,7 +578,9 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
join_event_stub.insert(
|
||||
"origin_server_ts".to_owned(),
|
||||
CanonicalJsonValue::Integer(
|
||||
utils::millis_since_unix_epoch().try_into().expect("Timestamp is valid js_int value"),
|
||||
utils::millis_since_unix_epoch()
|
||||
.try_into()
|
||||
.expect("Timestamp is valid js_int value"),
|
||||
),
|
||||
);
|
||||
join_event_stub.insert(
|
||||
|
@ -691,10 +763,15 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
Error::BadServerResponse("Invalid PDU in send_join response.")
|
||||
})?;
|
||||
|
||||
services().rooms.outlier.add_pdu_outlier(&event_id, &value)?;
|
||||
services()
|
||||
.rooms
|
||||
.outlier
|
||||
.add_pdu_outlier(&event_id, &value)?;
|
||||
if let Some(state_key) = &pdu.state_key {
|
||||
let shortstatekey =
|
||||
services().rooms.short.get_or_create_shortstatekey(&pdu.kind.to_string().into(), state_key)?;
|
||||
let shortstatekey = services()
|
||||
.rooms
|
||||
.short
|
||||
.get_or_create_shortstatekey(&pdu.kind.to_string().into(), state_key)?;
|
||||
state.insert(shortstatekey, pdu.event_id.clone());
|
||||
}
|
||||
}
|
||||
|
@ -711,7 +788,10 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
Err(_) => continue,
|
||||
};
|
||||
|
||||
services().rooms.outlier.add_pdu_outlier(&event_id, &value)?;
|
||||
services()
|
||||
.rooms
|
||||
.outlier
|
||||
.add_pdu_outlier(&event_id, &value)?;
|
||||
}
|
||||
|
||||
info!("Running send_join auth check");
|
||||
|
@ -725,8 +805,13 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
.rooms
|
||||
.timeline
|
||||
.get_pdu(
|
||||
state
|
||||
.get(&services().rooms.short.get_or_create_shortstatekey(&k.to_string().into(), s).ok()?)?,
|
||||
state.get(
|
||||
&services()
|
||||
.rooms
|
||||
.short
|
||||
.get_or_create_shortstatekey(&k.to_string().into(), s)
|
||||
.ok()?,
|
||||
)?,
|
||||
)
|
||||
.ok()?
|
||||
},
|
||||
|
@ -746,12 +831,21 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
Arc::new(
|
||||
state
|
||||
.into_iter()
|
||||
.map(|(k, id)| services().rooms.state_compressor.compress_state_event(k, &id))
|
||||
.map(|(k, id)| {
|
||||
services()
|
||||
.rooms
|
||||
.state_compressor
|
||||
.compress_state_event(k, &id)
|
||||
})
|
||||
.collect::<Result<_>>()?,
|
||||
),
|
||||
)?;
|
||||
|
||||
services().rooms.state.force_state(room_id, statehash_before_join, new, removed, &state_lock).await?;
|
||||
services()
|
||||
.rooms
|
||||
.state
|
||||
.force_state(room_id, statehash_before_join, new, removed, &state_lock)
|
||||
.await?;
|
||||
|
||||
info!("Updating joined counts for new room");
|
||||
services().rooms.state_cache.update_joined_count(room_id)?;
|
||||
|
@ -776,14 +870,23 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
info!("Setting final room state for new room");
|
||||
// We set the room state after inserting the pdu, so that we never have a moment
|
||||
// in time where events in the current room state do not exist
|
||||
services().rooms.state.set_room_state(room_id, statehash_after_join, &state_lock)?;
|
||||
services()
|
||||
.rooms
|
||||
.state
|
||||
.set_room_state(room_id, statehash_after_join, &state_lock)?;
|
||||
} else {
|
||||
info!("We can join locally");
|
||||
|
||||
let join_rules_event =
|
||||
services().rooms.state_accessor.room_state_get(room_id, &StateEventType::RoomJoinRules, "")?;
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(room_id, &StateEventType::RoomJoinRules, "")?;
|
||||
let power_levels_event =
|
||||
services().rooms.state_accessor.room_state_get(room_id, &StateEventType::RoomPowerLevels, "")?;
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(room_id, &StateEventType::RoomPowerLevels, "")?;
|
||||
|
||||
let join_rules_event_content: Option<RoomJoinRulesEventContent> = join_rules_event
|
||||
.as_ref()
|
||||
|
@ -821,7 +924,12 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
let authorized_user = restriction_rooms
|
||||
.iter()
|
||||
.find_map(|restriction_room_id| {
|
||||
if !services().rooms.state_cache.is_joined(sender_user, restriction_room_id).ok()? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.is_joined(sender_user, restriction_room_id)
|
||||
.ok()?
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let authorized_user = power_levels_event_content
|
||||
|
@ -888,7 +996,10 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
};
|
||||
|
||||
if !restriction_rooms.is_empty()
|
||||
&& servers.iter().filter(|s| *s != services().globals.server_name()).count() > 0
|
||||
&& servers
|
||||
.iter()
|
||||
.filter(|s| *s != services().globals.server_name())
|
||||
.count() > 0
|
||||
{
|
||||
info!(
|
||||
"We couldn't do the join locally, maybe federation can help to satisfy the restricted join \
|
||||
|
@ -897,7 +1008,12 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
let (make_join_response, remote_server) = make_join_request(sender_user, room_id, servers).await?;
|
||||
|
||||
let room_version_id = match make_join_response.room_version {
|
||||
Some(room_version_id) if services().globals.supported_room_versions().contains(&room_version_id) => {
|
||||
Some(room_version_id)
|
||||
if services()
|
||||
.globals
|
||||
.supported_room_versions()
|
||||
.contains(&room_version_id) =>
|
||||
{
|
||||
room_version_id
|
||||
},
|
||||
_ => return Err(Error::BadServerResponse("Room version is not supported")),
|
||||
|
@ -906,7 +1022,11 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
.map_err(|_| Error::BadServerResponse("Invalid make_join event json received from server."))?;
|
||||
let join_authorized_via_users_server = join_event_stub
|
||||
.get("content")
|
||||
.map(|s| s.as_object()?.get("join_authorised_via_users_server")?.as_str())
|
||||
.map(|s| {
|
||||
s.as_object()?
|
||||
.get("join_authorised_via_users_server")?
|
||||
.as_str()
|
||||
})
|
||||
.and_then(|s| OwnedUserId::try_from(s.unwrap_or_default()).ok());
|
||||
// TODO: Is origin needed?
|
||||
join_event_stub.insert(
|
||||
|
@ -916,7 +1036,9 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
join_event_stub.insert(
|
||||
"origin_server_ts".to_owned(),
|
||||
CanonicalJsonValue::Integer(
|
||||
utils::millis_since_unix_epoch().try_into().expect("Timestamp is valid js_int value"),
|
||||
utils::millis_since_unix_epoch()
|
||||
.try_into()
|
||||
.expect("Timestamp is valid js_int value"),
|
||||
),
|
||||
);
|
||||
join_event_stub.insert(
|
||||
|
@ -1002,7 +1124,11 @@ pub(crate) async fn join_room_by_id_helper(
|
|||
|
||||
drop(state_lock);
|
||||
let pub_key_map = RwLock::new(BTreeMap::new());
|
||||
services().rooms.event_handler.fetch_required_signing_keys([&signed_value], &pub_key_map).await?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_required_signing_keys([&signed_value], &pub_key_map)
|
||||
.await?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
|
@ -1065,7 +1191,13 @@ async fn validate_and_add_event_id(
|
|||
.expect("ruma's reference hashes are valid event ids");
|
||||
|
||||
let back_off = |id| async {
|
||||
match services().globals.bad_event_ratelimiter.write().await.entry(id) {
|
||||
match services()
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.write()
|
||||
.await
|
||||
.entry(id)
|
||||
{
|
||||
Entry::Vacant(e) => {
|
||||
e.insert((Instant::now(), 1));
|
||||
},
|
||||
|
@ -1073,7 +1205,13 @@ async fn validate_and_add_event_id(
|
|||
}
|
||||
};
|
||||
|
||||
if let Some((time, tries)) = services().globals.bad_event_ratelimiter.read().await.get(&event_id) {
|
||||
if let Some((time, tries)) = services()
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.read()
|
||||
.await
|
||||
.get(&event_id)
|
||||
{
|
||||
// Exponential backoff
|
||||
let mut min_elapsed_duration = Duration::from_secs(5 * 60) * (*tries) * (*tries);
|
||||
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
|
||||
|
@ -1110,8 +1248,15 @@ pub(crate) async fn invite_helper(
|
|||
|
||||
if user_id.server_name() != services().globals.server_name() {
|
||||
let (pdu, pdu_json, invite_room_state) = {
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(room_id.to_owned()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
let content = to_raw_value(&RoomMemberEventContent {
|
||||
|
@ -1196,7 +1341,11 @@ pub(crate) async fn invite_helper(
|
|||
)
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Origin field is invalid."))?;
|
||||
|
||||
services().rooms.event_handler.fetch_required_signing_keys([&value], &pub_key_map).await?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_required_signing_keys([&value], &pub_key_map)
|
||||
.await?;
|
||||
|
||||
let pdu_id: Vec<u8> = services()
|
||||
.rooms
|
||||
|
@ -1221,15 +1370,26 @@ pub(crate) async fn invite_helper(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
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.",
|
||||
));
|
||||
}
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(room_id.to_owned()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
services()
|
||||
|
@ -1270,7 +1430,13 @@ pub async fn leave_all_rooms(user_id: &UserId) -> Result<()> {
|
|||
.rooms
|
||||
.state_cache
|
||||
.rooms_joined(user_id)
|
||||
.chain(services().rooms.state_cache.rooms_invited(user_id).map(|t| t.map(|(r, _)| r)))
|
||||
.chain(
|
||||
services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.rooms_invited(user_id)
|
||||
.map(|t| t.map(|(r, _)| r)),
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for room_id in all_rooms {
|
||||
|
@ -1313,12 +1479,22 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
|
|||
)
|
||||
.await?;
|
||||
} else {
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(room_id.to_owned()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
let member_event =
|
||||
services().rooms.state_accessor.room_state_get(room_id, &StateEventType::RoomMember, user_id.as_str())?;
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(room_id, &StateEventType::RoomMember, user_id.as_str())?;
|
||||
|
||||
// Fix for broken rooms
|
||||
let member_event = match member_event {
|
||||
|
@ -1411,7 +1587,14 @@ async fn remote_leave_room(user_id: &UserId, room_id: &RoomId) -> Result<()> {
|
|||
let (make_leave_response, remote_server) = make_leave_response_and_server?;
|
||||
|
||||
let room_version_id = match make_leave_response.room_version {
|
||||
Some(version) if services().globals.supported_room_versions().contains(&version) => version,
|
||||
Some(version)
|
||||
if services()
|
||||
.globals
|
||||
.supported_room_versions()
|
||||
.contains(&version) =>
|
||||
{
|
||||
version
|
||||
},
|
||||
_ => return Err(Error::BadServerResponse("Room version is not supported")),
|
||||
};
|
||||
|
||||
|
@ -1426,7 +1609,9 @@ async fn remote_leave_room(user_id: &UserId, room_id: &RoomId) -> Result<()> {
|
|||
leave_event_stub.insert(
|
||||
"origin_server_ts".to_owned(),
|
||||
CanonicalJsonValue::Integer(
|
||||
utils::millis_since_unix_epoch().try_into().expect("Timestamp is valid js_int value"),
|
||||
utils::millis_since_unix_epoch()
|
||||
.try_into()
|
||||
.expect("Timestamp is valid js_int value"),
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
@ -32,8 +32,15 @@ pub async fn send_message_event_route(
|
|||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
let sender_device = body.sender_device.as_deref();
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(body.room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
// Forbid m.room.encrypted if encryption is disabled
|
||||
|
@ -90,7 +97,10 @@ pub 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() {
|
||||
|
@ -130,7 +140,9 @@ pub async fn send_message_event_route(
|
|||
)
|
||||
.await?;
|
||||
|
||||
services().transaction_ids.add_txnid(sender_user, sender_device, &body.txn_id, event_id.as_bytes())?;
|
||||
services()
|
||||
.transaction_ids
|
||||
.add_txnid(sender_user, sender_device, &body.txn_id, event_id.as_bytes())?;
|
||||
|
||||
drop(state_lock);
|
||||
|
||||
|
@ -158,9 +170,16 @@ pub 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).await?;
|
||||
services()
|
||||
.rooms
|
||||
.lazy_loading
|
||||
.lazy_load_confirm_delivery(sender_user, sender_device, &body.room_id, from)
|
||||
.await?;
|
||||
|
||||
let limit = u64::from(body.limit).min(100) as usize;
|
||||
|
||||
|
@ -208,14 +227,21 @@ pub async fn get_message_events_route(
|
|||
|
||||
next_token = events_after.last().map(|(count, _)| count).copied();
|
||||
|
||||
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();
|
||||
|
||||
resp.start = from.stringify();
|
||||
resp.end = next_token.map(|count| count.stringify());
|
||||
resp.chunk = events_after;
|
||||
},
|
||||
ruma::api::Direction::Backward => {
|
||||
services().rooms.timeline.backfill_if_required(&body.room_id, from).await?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.backfill_if_required(&body.room_id, from)
|
||||
.await?;
|
||||
let events_before: Vec<_> = services()
|
||||
.rooms
|
||||
.timeline
|
||||
|
@ -252,7 +278,10 @@ pub async fn get_message_events_route(
|
|||
|
||||
next_token = events_before.last().map(|(count, _)| count).copied();
|
||||
|
||||
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();
|
||||
|
||||
resp.start = from.stringify();
|
||||
resp.end = next_token.map(|count| count.stringify());
|
||||
|
|
|
@ -46,10 +46,19 @@ pub async fn get_presence_route(body: Ruma<get_presence::v3::Request>) -> Result
|
|||
|
||||
let mut presence_event = None;
|
||||
|
||||
for room_id in services().rooms.user.get_shared_rooms(vec![sender_user.clone(), body.user_id.clone()])? {
|
||||
for room_id in services()
|
||||
.rooms
|
||||
.user
|
||||
.get_shared_rooms(vec![sender_user.clone(), body.user_id.clone()])?
|
||||
{
|
||||
let room_id = room_id?;
|
||||
|
||||
if let Some(presence) = services().rooms.edus.presence.get_presence(&room_id, sender_user)? {
|
||||
if let Some(presence) = services()
|
||||
.rooms
|
||||
.edus
|
||||
.presence
|
||||
.get_presence(&room_id, sender_user)?
|
||||
{
|
||||
presence_event = Some(presence);
|
||||
break;
|
||||
}
|
||||
|
@ -60,7 +69,10 @@ pub async fn get_presence_route(body: Ruma<get_presence::v3::Request>) -> Result
|
|||
// TODO: Should ruma just use the presenceeventcontent type here?
|
||||
status_msg: presence.content.status_msg,
|
||||
currently_active: presence.content.currently_active,
|
||||
last_active_ago: presence.content.last_active_ago.map(|millis| Duration::from_millis(millis.into())),
|
||||
last_active_ago: presence
|
||||
.content
|
||||
.last_active_ago
|
||||
.map(|millis| Duration::from_millis(millis.into())),
|
||||
presence: presence.content.presence,
|
||||
})
|
||||
} else {
|
||||
|
|
|
@ -25,7 +25,10 @@ pub 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()).await?;
|
||||
services()
|
||||
.users
|
||||
.set_displayname(sender_user, body.displayname.clone())
|
||||
.await?;
|
||||
|
||||
// Send a new membership event and presence update into all joined rooms
|
||||
let all_rooms_joined: Vec<_> = services()
|
||||
|
@ -64,16 +67,31 @@ pub async fn set_displayname_route(
|
|||
.collect();
|
||||
|
||||
for (pdu_builder, room_id) in all_rooms_joined {
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
_ = services().rooms.timeline.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock).await;
|
||||
_ = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
|
||||
.await;
|
||||
}
|
||||
|
||||
if services().globals.allow_local_presence() {
|
||||
// Presence update
|
||||
services().rooms.edus.presence.ping_presence(sender_user, PresenceState::Online)?;
|
||||
services()
|
||||
.rooms
|
||||
.edus
|
||||
.presence
|
||||
.ping_presence(sender_user, PresenceState::Online)?;
|
||||
}
|
||||
|
||||
Ok(set_display_name::v3::Response {})
|
||||
|
@ -105,9 +123,18 @@ pub async fn get_displayname_route(
|
|||
services().users.create(&body.user_id, None)?;
|
||||
}
|
||||
|
||||
services().users.set_displayname(&body.user_id, response.displayname.clone()).await?;
|
||||
services().users.set_avatar_url(&body.user_id, response.avatar_url.clone()).await?;
|
||||
services().users.set_blurhash(&body.user_id, response.blurhash.clone()).await?;
|
||||
services()
|
||||
.users
|
||||
.set_displayname(&body.user_id, response.displayname.clone())
|
||||
.await?;
|
||||
services()
|
||||
.users
|
||||
.set_avatar_url(&body.user_id, response.avatar_url.clone())
|
||||
.await?;
|
||||
services()
|
||||
.users
|
||||
.set_blurhash(&body.user_id, response.blurhash.clone())
|
||||
.await?;
|
||||
|
||||
return Ok(get_display_name::v3::Response {
|
||||
displayname: response.displayname,
|
||||
|
@ -134,9 +161,15 @@ pub async fn get_displayname_route(
|
|||
pub async fn set_avatar_url_route(body: Ruma<set_avatar_url::v3::Request>) -> Result<set_avatar_url::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
services().users.set_avatar_url(sender_user, body.avatar_url.clone()).await?;
|
||||
services()
|
||||
.users
|
||||
.set_avatar_url(sender_user, body.avatar_url.clone())
|
||||
.await?;
|
||||
|
||||
services().users.set_blurhash(sender_user, body.blurhash.clone()).await?;
|
||||
services()
|
||||
.users
|
||||
.set_blurhash(sender_user, body.blurhash.clone())
|
||||
.await?;
|
||||
|
||||
// Send a new membership event and presence update into all joined rooms
|
||||
let all_joined_rooms: Vec<_> = services()
|
||||
|
@ -175,16 +208,31 @@ pub async fn set_avatar_url_route(body: Ruma<set_avatar_url::v3::Request>) -> Re
|
|||
.collect();
|
||||
|
||||
for (pdu_builder, room_id) in all_joined_rooms {
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
_ = services().rooms.timeline.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock).await;
|
||||
_ = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
|
||||
.await;
|
||||
}
|
||||
|
||||
if services().globals.allow_local_presence() {
|
||||
// Presence update
|
||||
services().rooms.edus.presence.ping_presence(sender_user, PresenceState::Online)?;
|
||||
services()
|
||||
.rooms
|
||||
.edus
|
||||
.presence
|
||||
.ping_presence(sender_user, PresenceState::Online)?;
|
||||
}
|
||||
|
||||
Ok(set_avatar_url::v3::Response {})
|
||||
|
@ -214,9 +262,18 @@ pub async fn get_avatar_url_route(body: Ruma<get_avatar_url::v3::Request>) -> Re
|
|||
services().users.create(&body.user_id, None)?;
|
||||
}
|
||||
|
||||
services().users.set_displayname(&body.user_id, response.displayname.clone()).await?;
|
||||
services().users.set_avatar_url(&body.user_id, response.avatar_url.clone()).await?;
|
||||
services().users.set_blurhash(&body.user_id, response.blurhash.clone()).await?;
|
||||
services()
|
||||
.users
|
||||
.set_displayname(&body.user_id, response.displayname.clone())
|
||||
.await?;
|
||||
services()
|
||||
.users
|
||||
.set_avatar_url(&body.user_id, response.avatar_url.clone())
|
||||
.await?;
|
||||
services()
|
||||
.users
|
||||
.set_blurhash(&body.user_id, response.blurhash.clone())
|
||||
.await?;
|
||||
|
||||
return Ok(get_avatar_url::v3::Response {
|
||||
avatar_url: response.avatar_url,
|
||||
|
@ -261,9 +318,18 @@ pub async fn get_profile_route(body: Ruma<get_profile::v3::Request>) -> Result<g
|
|||
services().users.create(&body.user_id, None)?;
|
||||
}
|
||||
|
||||
services().users.set_displayname(&body.user_id, response.displayname.clone()).await?;
|
||||
services().users.set_avatar_url(&body.user_id, response.avatar_url.clone()).await?;
|
||||
services().users.set_blurhash(&body.user_id, response.blurhash.clone()).await?;
|
||||
services()
|
||||
.users
|
||||
.set_displayname(&body.user_id, response.displayname.clone())
|
||||
.await?;
|
||||
services()
|
||||
.users
|
||||
.set_avatar_url(&body.user_id, response.avatar_url.clone())
|
||||
.await?;
|
||||
services()
|
||||
.users
|
||||
.set_blurhash(&body.user_id, response.blurhash.clone())
|
||||
.await?;
|
||||
|
||||
return Ok(get_profile::v3::Response {
|
||||
displayname: response.displayname,
|
||||
|
|
|
@ -49,7 +49,10 @@ pub async fn get_pushrule_route(body: Ruma<get_pushrule::v3::Request>) -> Result
|
|||
.map_err(|_| Error::bad_database("Invalid account data event in db."))?
|
||||
.content;
|
||||
|
||||
let rule = account_data.global.get(body.kind.clone(), &body.rule_id).map(Into::into);
|
||||
let rule = account_data
|
||||
.global
|
||||
.get(body.kind.clone(), &body.rule_id)
|
||||
.map(Into::into);
|
||||
|
||||
if let Some(rule) = rule {
|
||||
Ok(get_pushrule::v3::Response {
|
||||
|
@ -83,7 +86,10 @@ pub async fn set_pushrule_route(body: Ruma<set_pushrule::v3::Request>) -> Result
|
|||
.map_err(|_| Error::bad_database("Invalid account data event in db."))?;
|
||||
|
||||
if let Err(error) =
|
||||
account_data.content.global.insert(body.rule.clone(), body.after.as_deref(), body.before.as_deref())
|
||||
account_data
|
||||
.content
|
||||
.global
|
||||
.insert(body.rule.clone(), body.after.as_deref(), body.before.as_deref())
|
||||
{
|
||||
let err = match error {
|
||||
InsertPushRuleError::ServerDefaultRuleId => Error::BadRequest(
|
||||
|
@ -178,7 +184,12 @@ pub 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."))?;
|
||||
|
||||
if account_data.content.global.set_actions(body.kind.clone(), &body.rule_id, body.actions.clone()).is_err() {
|
||||
if account_data
|
||||
.content
|
||||
.global
|
||||
.set_actions(body.kind.clone(), &body.rule_id, body.actions.clone())
|
||||
.is_err()
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Push rule not found."));
|
||||
}
|
||||
|
||||
|
@ -249,7 +260,12 @@ pub 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."))?;
|
||||
|
||||
if account_data.content.global.set_enabled(body.kind.clone(), &body.rule_id, body.enabled).is_err() {
|
||||
if account_data
|
||||
.content
|
||||
.global
|
||||
.set_enabled(body.kind.clone(), &body.rule_id, body.enabled)
|
||||
.is_err()
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Push rule not found."));
|
||||
}
|
||||
|
||||
|
@ -284,7 +300,11 @@ pub async fn delete_pushrule_route(body: Ruma<delete_pushrule::v3::Request>) ->
|
|||
let mut account_data = serde_json::from_str::<PushRulesEvent>(event.get())
|
||||
.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(ErrorKind::InvalidParam, "Cannot delete a server-default pushrule.")
|
||||
|
@ -325,7 +345,9 @@ pub async fn get_pushers_route(body: Ruma<get_pushers::v3::Request>) -> Result<g
|
|||
pub async fn set_pushers_route(body: Ruma<set_pusher::v3::Request>) -> 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())
|
||||
}
|
||||
|
|
|
@ -36,7 +36,10 @@ pub async fn set_read_marker_route(body: Ruma<set_read_marker::v3::Request>) ->
|
|||
}
|
||||
|
||||
if body.private_read_receipt.is_some() || body.read_receipt.is_some() {
|
||||
services().rooms.user.reset_notification_counts(sender_user, &body.room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.user
|
||||
.reset_notification_counts(sender_user, &body.room_id)?;
|
||||
}
|
||||
|
||||
if let Some(event) = &body.private_read_receipt {
|
||||
|
@ -54,7 +57,11 @@ pub async fn set_read_marker_route(body: Ruma<set_read_marker::v3::Request>) ->
|
|||
},
|
||||
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 {
|
||||
|
@ -98,7 +105,10 @@ pub async fn create_receipt_route(body: Ruma<create_receipt::v3::Request>) -> Re
|
|||
&body.receipt_type,
|
||||
create_receipt::v3::ReceiptType::Read | create_receipt::v3::ReceiptType::ReadPrivate
|
||||
) {
|
||||
services().rooms.user.reset_notification_counts(sender_user, &body.room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.user
|
||||
.reset_notification_counts(sender_user, &body.room_id)?;
|
||||
}
|
||||
|
||||
match body.receipt_type {
|
||||
|
@ -156,7 +166,11 @@ pub async fn create_receipt_route(body: Ruma<create_receipt::v3::Request>) -> Re
|
|||
},
|
||||
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)?;
|
||||
},
|
||||
_ => return Err(Error::bad_database("Unsupported receipt type")),
|
||||
}
|
||||
|
|
|
@ -17,8 +17,15 @@ pub async fn redact_event_route(body: Ruma<redact_event::v3::Request>) -> Result
|
|||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
let body = body.body;
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(body.room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
let event_id = services()
|
||||
|
|
|
@ -19,21 +19,31 @@ pub 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.limit.and_then(|u| u32::try_from(u).ok()).map_or(10_usize, |u| u as usize).min(100);
|
||||
let limit = body
|
||||
.limit
|
||||
.and_then(|u| u32::try_from(u).ok())
|
||||
.map_or(10_usize, |u| u as usize)
|
||||
.min(100);
|
||||
|
||||
let res = services().rooms.pdu_metadata.paginate_relations_with_filter(
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&body.event_id,
|
||||
&Some(body.event_type.clone()),
|
||||
&Some(body.rel_type.clone()),
|
||||
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.clone()),
|
||||
&Some(body.rel_type.clone()),
|
||||
from,
|
||||
to,
|
||||
limit,
|
||||
)?;
|
||||
|
||||
Ok(get_relating_events_with_rel_type_and_event_type::v1::Response {
|
||||
chunk: res.chunk,
|
||||
|
@ -57,21 +67,31 @@ pub 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.limit.and_then(|u| u32::try_from(u).ok()).map_or(10_usize, |u| u as usize).min(100);
|
||||
let limit = body
|
||||
.limit
|
||||
.and_then(|u| u32::try_from(u).ok())
|
||||
.map_or(10_usize, |u| u as usize)
|
||||
.min(100);
|
||||
|
||||
let res = services().rooms.pdu_metadata.paginate_relations_with_filter(
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&body.event_id,
|
||||
&None,
|
||||
&Some(body.rel_type.clone()),
|
||||
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.clone()),
|
||||
from,
|
||||
to,
|
||||
limit,
|
||||
)?;
|
||||
|
||||
Ok(get_relating_events_with_rel_type::v1::Response {
|
||||
chunk: res.chunk,
|
||||
|
@ -95,19 +115,20 @@ pub 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.limit.and_then(|u| u32::try_from(u).ok()).map_or(10_usize, |u| u as usize).min(100);
|
||||
let limit = body
|
||||
.limit
|
||||
.and_then(|u| u32::try_from(u).ok())
|
||||
.map_or(10_usize, |u| u as usize)
|
||||
.min(100);
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -71,18 +71,20 @@ pub async fn report_event_route(body: Ruma<report_content::v3::Request>) -> Resu
|
|||
|
||||
// send admin room message that we received the report with an @room ping for
|
||||
// urgency
|
||||
services().admin.send_message(message::RoomMessageEventContent::text_html(
|
||||
format!(
|
||||
"@room Report received from: {}\n\nEvent ID: {}\nRoom ID: {}\nSent By: {}\n\nReport Score: {}\nReport \
|
||||
Reason: {}",
|
||||
sender_user.to_owned(),
|
||||
pdu.event_id,
|
||||
pdu.room_id,
|
||||
pdu.sender.clone(),
|
||||
body.score.unwrap_or_else(|| ruma::Int::from(0)),
|
||||
body.reason.as_deref().unwrap_or("")
|
||||
),
|
||||
format!(
|
||||
services()
|
||||
.admin
|
||||
.send_message(message::RoomMessageEventContent::text_html(
|
||||
format!(
|
||||
"@room Report received from: {}\n\nEvent ID: {}\nRoom ID: {}\nSent By: {}\n\nReport Score: {}\nReport \
|
||||
Reason: {}",
|
||||
sender_user.to_owned(),
|
||||
pdu.event_id,
|
||||
pdu.room_id,
|
||||
pdu.sender.clone(),
|
||||
body.score.unwrap_or_else(|| ruma::Int::from(0)),
|
||||
body.reason.as_deref().unwrap_or("")
|
||||
),
|
||||
format!(
|
||||
"<details><summary>@room Report received from: <a href=\"https://matrix.to/#/{0}\">{0}\
|
||||
</a></summary><ul><li>Event Info<ul><li>Event ID: <code>{1}</code>\
|
||||
<a href=\"https://matrix.to/#/{2}/{1}\">🔗</a></li><li>Room ID: <code>{2}</code>\
|
||||
|
@ -96,7 +98,7 @@ pub async fn report_event_route(body: Ruma<report_content::v3::Request>) -> Resu
|
|||
body.score.unwrap_or_else(|| ruma::Int::from(0)),
|
||||
HtmlEscape(body.reason.as_deref().unwrap_or(""))
|
||||
),
|
||||
));
|
||||
));
|
||||
|
||||
// even though this is kinda security by obscurity, let's still make a small
|
||||
// random delay sending a successful response per spec suggestion regarding
|
||||
|
|
|
@ -80,7 +80,11 @@ pub async fn create_room_route(body: Ruma<create_room::v3::Request>) -> Result<c
|
|||
}
|
||||
|
||||
// apply forbidden room alias checks to custom room IDs too
|
||||
if services().globals.forbidden_alias_names().is_match(&custom_room_id_s) {
|
||||
if services()
|
||||
.globals
|
||||
.forbidden_alias_names()
|
||||
.is_match(&custom_room_id_s)
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Unknown, "Custom room ID is forbidden."));
|
||||
}
|
||||
|
||||
|
@ -110,60 +114,83 @@ pub async fn create_room_route(body: Ruma<create_room::v3::Request>) -> Result<c
|
|||
|
||||
services().rooms.short.get_or_create_shortroomid(&room_id)?;
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
let alias: Option<OwnedRoomAliasId> = body.room_alias_name.as_ref().map_or(Ok(None), |localpart| {
|
||||
// Basic checks on the room alias validity
|
||||
if localpart.contains(':') {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Room alias contained `:` which is not allowed. Please note that this expects a localpart, not the \
|
||||
full room alias.",
|
||||
));
|
||||
} else if localpart.contains(char::is_whitespace) {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Room alias contained spaces which is not a valid room alias.",
|
||||
));
|
||||
} else if localpart.len() > 255 {
|
||||
// there is nothing spec-wise saying to check the limit of this,
|
||||
// however absurdly long room aliases are guaranteed to be unreadable or done
|
||||
// maliciously. there is no reason a room alias should even exceed 100
|
||||
// characters as is. generally in spec, 255 is matrix's fav number
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Room alias is excessively long, clients may not be able to handle this. Please shorten it.",
|
||||
));
|
||||
} else if localpart.contains('"') {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Room alias contained `\"` which is not allowed.",
|
||||
));
|
||||
}
|
||||
let alias: Option<OwnedRoomAliasId> = body
|
||||
.room_alias_name
|
||||
.as_ref()
|
||||
.map_or(Ok(None), |localpart| {
|
||||
// Basic checks on the room alias validity
|
||||
if localpart.contains(':') {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Room alias contained `:` which is not allowed. Please note that this expects a localpart, not \
|
||||
the full room alias.",
|
||||
));
|
||||
} else if localpart.contains(char::is_whitespace) {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Room alias contained spaces which is not a valid room alias.",
|
||||
));
|
||||
} else if localpart.len() > 255 {
|
||||
// there is nothing spec-wise saying to check the limit of this,
|
||||
// however absurdly long room aliases are guaranteed to be unreadable or done
|
||||
// maliciously. there is no reason a room alias should even exceed 100
|
||||
// characters as is. generally in spec, 255 is matrix's fav number
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Room alias is excessively long, clients may not be able to handle this. Please shorten it.",
|
||||
));
|
||||
} else if localpart.contains('"') {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Room alias contained `\"` which is not allowed.",
|
||||
));
|
||||
}
|
||||
|
||||
// check if room alias is forbidden
|
||||
if services().globals.forbidden_alias_names().is_match(localpart) {
|
||||
return Err(Error::BadRequest(ErrorKind::Unknown, "Room alias name is forbidden."));
|
||||
}
|
||||
// check if room alias is forbidden
|
||||
if services()
|
||||
.globals
|
||||
.forbidden_alias_names()
|
||||
.is_match(localpart)
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Unknown, "Room alias name is forbidden."));
|
||||
}
|
||||
|
||||
let alias =
|
||||
RoomAliasId::parse(format!("#{}:{}", localpart, services().globals.server_name())).map_err(|e| {
|
||||
warn!("Failed to parse room alias for room ID {}: {e}", room_id);
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Invalid room alias specified.")
|
||||
})?;
|
||||
let alias =
|
||||
RoomAliasId::parse(format!("#{}:{}", localpart, services().globals.server_name())).map_err(|e| {
|
||||
warn!("Failed to parse room alias for room ID {}: {e}", room_id);
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Invalid room alias specified.")
|
||||
})?;
|
||||
|
||||
if services().rooms.alias.resolve_local_alias(&alias)?.is_some() {
|
||||
Err(Error::BadRequest(ErrorKind::RoomInUse, "Room alias already exists."))
|
||||
} else {
|
||||
Ok(Some(alias))
|
||||
}
|
||||
})?;
|
||||
if services()
|
||||
.rooms
|
||||
.alias
|
||||
.resolve_local_alias(&alias)?
|
||||
.is_some()
|
||||
{
|
||||
Err(Error::BadRequest(ErrorKind::RoomInUse, "Room alias already exists."))
|
||||
} else {
|
||||
Ok(Some(alias))
|
||||
}
|
||||
})?;
|
||||
|
||||
let room_version = match body.room_version.clone() {
|
||||
Some(room_version) => {
|
||||
if services().globals.supported_room_versions().contains(&room_version) {
|
||||
if services()
|
||||
.globals
|
||||
.supported_room_versions()
|
||||
.contains(&room_version)
|
||||
{
|
||||
room_version
|
||||
} else {
|
||||
return Err(Error::BadRequest(
|
||||
|
@ -177,10 +204,12 @@ pub async fn create_room_route(body: Ruma<create_room::v3::Request>) -> Result<c
|
|||
|
||||
let content = match &body.creation_content {
|
||||
Some(content) => {
|
||||
let mut content = content.deserialize_as::<CanonicalJsonObject>().map_err(|e| {
|
||||
error!("Failed to deserialise content as canonical JSON: {}", e);
|
||||
Error::bad_database("Failed to deserialise content as canonical JSON.")
|
||||
})?;
|
||||
let mut content = content
|
||||
.deserialize_as::<CanonicalJsonObject>()
|
||||
.map_err(|e| {
|
||||
error!("Failed to deserialise content as canonical JSON: {}", e);
|
||||
Error::bad_database("Failed to deserialise content as canonical JSON.")
|
||||
})?;
|
||||
match room_version {
|
||||
RoomVersionId::V1
|
||||
| RoomVersionId::V2
|
||||
|
@ -256,8 +285,11 @@ pub async fn create_room_route(body: Ruma<create_room::v3::Request>) -> Result<c
|
|||
};
|
||||
|
||||
// Validate creation content
|
||||
let de_result =
|
||||
serde_json::from_str::<CanonicalJsonObject>(to_raw_value(&content).expect("Invalid creation content").get());
|
||||
let de_result = serde_json::from_str::<CanonicalJsonObject>(
|
||||
to_raw_value(&content)
|
||||
.expect("Invalid creation content")
|
||||
.get(),
|
||||
);
|
||||
|
||||
if de_result.is_err() {
|
||||
return Err(Error::BadRequest(ErrorKind::BadJson, "Invalid creation content"));
|
||||
|
@ -463,7 +495,11 @@ pub async fn create_room_route(body: Ruma<create_room::v3::Request>) -> Result<c
|
|||
continue;
|
||||
}
|
||||
|
||||
services().rooms.timeline.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock).await?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// 7. Events implied by name and topic
|
||||
|
@ -538,12 +574,20 @@ pub async fn create_room_route(body: Ruma<create_room::v3::Request>) -> Result<c
|
|||
pub 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(|| {
|
||||
warn!("Event not found, event ID: {:?}", &body.event_id);
|
||||
Error::BadRequest(ErrorKind::NotFound, "Event not found.")
|
||||
})?;
|
||||
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, &event.room_id, &body.event_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_event(sender_user, &event.room_id, &body.event_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"You don't have permission to view this event.",
|
||||
|
@ -567,7 +611,11 @@ pub async fn get_room_event_route(body: Ruma<get_room_event::v3::Request>) -> Re
|
|||
pub 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_accessor.user_can_see_state_events(sender_user, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"You don't have permission to view this room.",
|
||||
|
@ -575,7 +623,12 @@ pub async fn get_room_aliases_route(body: Ruma<aliases::v3::Request>) -> Result<
|
|||
}
|
||||
|
||||
Ok(aliases::v3::Response {
|
||||
aliases: services().rooms.alias.local_aliases_for_room(&body.room_id).filter_map(Result::ok).collect(),
|
||||
aliases: services()
|
||||
.rooms
|
||||
.alias
|
||||
.local_aliases_for_room(&body.room_id)
|
||||
.filter_map(Result::ok)
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -592,7 +645,11 @@ pub async fn get_room_aliases_route(body: Ruma<aliases::v3::Request>) -> Result<
|
|||
pub async fn upgrade_room_route(body: Ruma<upgrade_room::v3::Request>) -> 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,
|
||||
"This server does not support that room version.",
|
||||
|
@ -601,10 +658,20 @@ pub async fn upgrade_room_route(body: Ruma<upgrade_room::v3::Request>) -> Result
|
|||
|
||||
// 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().globals.roomid_mutex_state.write().await.entry(body.room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
// Send a m.room.tombstone event to the old room to indicate that it is not
|
||||
|
@ -633,8 +700,15 @@ pub async fn upgrade_room_route(body: Ruma<upgrade_room::v3::Request>) -> Result
|
|||
|
||||
// Change lock to replacement room
|
||||
drop(state_lock);
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(replacement_room.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(replacement_room.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
// Get the old room creation event
|
||||
|
@ -704,7 +778,9 @@ pub async fn upgrade_room_route(body: Ruma<upgrade_room::v3::Request>) -> Result
|
|||
|
||||
// Validate creation event content
|
||||
let de_result = serde_json::from_str::<CanonicalJsonObject>(
|
||||
to_raw_value(&create_event_content).expect("Error forming creation event").get(),
|
||||
to_raw_value(&create_event_content)
|
||||
.expect("Error forming creation event")
|
||||
.get(),
|
||||
);
|
||||
|
||||
if de_result.is_err() {
|
||||
|
@ -771,7 +847,11 @@ pub async fn upgrade_room_route(body: Ruma<upgrade_room::v3::Request>) -> Result
|
|||
|
||||
// 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, "")? {
|
||||
let event_content = match services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&body.room_id, &event_type, "")?
|
||||
{
|
||||
Some(v) => v.content.clone(),
|
||||
None => continue, // Skipping missing events.
|
||||
};
|
||||
|
@ -795,8 +875,16 @@ pub async fn upgrade_room_route(body: Ruma<upgrade_room::v3::Request>) -> Result
|
|||
}
|
||||
|
||||
// Moves any local aliases to the new room
|
||||
for alias in services().rooms.alias.local_aliases_for_room(&body.room_id).filter_map(Result::ok) {
|
||||
services().rooms.alias.set_alias(&alias, &replacement_room)?;
|
||||
for alias in services()
|
||||
.rooms
|
||||
.alias
|
||||
.local_aliases_for_room(&body.room_id)
|
||||
.filter_map(Result::ok)
|
||||
{
|
||||
services()
|
||||
.rooms
|
||||
.alias
|
||||
.set_alias(&alias, &replacement_room)?;
|
||||
}
|
||||
|
||||
// Get the old room power levels
|
||||
|
|
|
@ -29,10 +29,14 @@ pub async fn search_events_route(body: Ruma<search_events::v3::Request>) -> Resu
|
|||
let filter = &search_criteria.filter;
|
||||
let include_state = &search_criteria.include_state;
|
||||
|
||||
let room_ids = filter
|
||||
.rooms
|
||||
.clone()
|
||||
.unwrap_or_else(|| services().rooms.state_cache.rooms_joined(sender_user).filter_map(Result::ok).collect());
|
||||
let room_ids = filter.rooms.clone().unwrap_or_else(|| {
|
||||
services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.rooms_joined(sender_user)
|
||||
.filter_map(Result::ok)
|
||||
.collect()
|
||||
});
|
||||
|
||||
// Use limit or else 10, with maximum 100
|
||||
let limit = filter.limit.map_or(10, u64::from).min(100) as usize;
|
||||
|
@ -41,7 +45,11 @@ pub async fn search_events_route(body: Ruma<search_events::v3::Request>) -> Resu
|
|||
|
||||
if include_state.is_some_and(|include_state| include_state) {
|
||||
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.",
|
||||
|
@ -49,7 +57,11 @@ pub async fn search_events_route(body: Ruma<search_events::v3::Request>) -> Resu
|
|||
}
|
||||
|
||||
// check if sender_user can see state events
|
||||
if services().rooms.state_accessor.user_can_see_state_events(sender_user, room_id)? {
|
||||
if services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(sender_user, room_id)?
|
||||
{
|
||||
let room_state = services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
|
@ -74,14 +86,22 @@ pub async fn search_events_route(body: Ruma<search_events::v3::Request>) -> Resu
|
|||
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.",
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(search) = services().rooms.search.search_pdus(room_id, &search_criteria.search_term)? {
|
||||
if let Some(search) = services()
|
||||
.rooms
|
||||
.search
|
||||
.search_pdus(room_id, &search_criteria.search_term)?
|
||||
{
|
||||
searches.push(search.0.peekable());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,11 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
|
|||
return Err(Error::BadServerResponse("could not hash"));
|
||||
};
|
||||
|
||||
let hash_matches = services().globals.argon.verify_password(password.as_bytes(), &parsed_hash).is_ok();
|
||||
let hash_matches = services()
|
||||
.globals
|
||||
.argon
|
||||
.verify_password(password.as_bytes(), &parsed_hash)
|
||||
.is_ok();
|
||||
|
||||
if !hash_matches {
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Wrong username or password."));
|
||||
|
@ -174,25 +178,37 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
|
|||
};
|
||||
|
||||
// Generate new device id if the user didn't specify one
|
||||
let device_id = body.device_id.clone().unwrap_or_else(|| utils::random_string(DEVICE_ID_LENGTH).into());
|
||||
let device_id = body
|
||||
.device_id
|
||||
.clone()
|
||||
.unwrap_or_else(|| utils::random_string(DEVICE_ID_LENGTH).into());
|
||||
|
||||
// Generate a new token for the device
|
||||
let token = utils::random_string(TOKEN_LENGTH);
|
||||
|
||||
// Determine if device_id was provided and exists in the db for this user
|
||||
let device_exists = body.device_id.as_ref().map_or(false, |device_id| {
|
||||
services().users.all_device_ids(&user_id).any(|x| x.as_ref().map_or(false, |v| v == device_id))
|
||||
services()
|
||||
.users
|
||||
.all_device_ids(&user_id)
|
||||
.any(|x| x.as_ref().map_or(false, |v| v == device_id))
|
||||
});
|
||||
|
||||
if device_exists {
|
||||
services().users.set_token(&user_id, &device_id, &token)?;
|
||||
} else {
|
||||
services().users.create_device(&user_id, &device_id, &token, body.initial_device_display_name.clone())?;
|
||||
services()
|
||||
.users
|
||||
.create_device(&user_id, &device_id, &token, body.initial_device_display_name.clone())?;
|
||||
}
|
||||
|
||||
// send client well-known if specified so the client knows to reconfigure itself
|
||||
let client_discovery_info = DiscoveryInfo::new(HomeserverInfo::new(
|
||||
services().globals.well_known_client().to_owned().unwrap_or_default(),
|
||||
services()
|
||||
.globals
|
||||
.well_known_client()
|
||||
.to_owned()
|
||||
.unwrap_or_default(),
|
||||
));
|
||||
|
||||
info!("{} logged in", user_id);
|
||||
|
|
|
@ -14,11 +14,20 @@ use crate::{service::rooms::spaces::PagnationToken, services, Error, Result, Rum
|
|||
pub 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 limit = body.limit.unwrap_or_else(|| UInt::from(10_u32)).min(UInt::from(100_u32));
|
||||
let limit = body
|
||||
.limit
|
||||
.unwrap_or_else(|| UInt::from(10_u32))
|
||||
.min(UInt::from(100_u32));
|
||||
|
||||
let max_depth = body.max_depth.unwrap_or_else(|| UInt::from(3_u32)).min(UInt::from(10_u32));
|
||||
let max_depth = body
|
||||
.max_depth
|
||||
.unwrap_or_else(|| UInt::from(3_u32))
|
||||
.min(UInt::from(10_u32));
|
||||
|
||||
let key = body.from.as_ref().and_then(|s| PagnationToken::from_str(s).ok());
|
||||
let key = body
|
||||
.from
|
||||
.as_ref()
|
||||
.and_then(|s| PagnationToken::from_str(s).ok());
|
||||
|
||||
// Should prevent unexpeded behaviour in (bad) clients
|
||||
if let Some(ref token) = key {
|
||||
|
|
|
@ -86,7 +86,11 @@ pub async fn get_state_events_route(
|
|||
) -> Result<get_state_events::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if !services().rooms.state_accessor.user_can_see_state_events(sender_user, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"You don't have permission to view the room state.",
|
||||
|
@ -118,21 +122,30 @@ pub async fn get_state_events_for_key_route(
|
|||
) -> Result<get_state_events_for_key::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if !services().rooms.state_accessor.user_can_see_state_events(sender_user, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"You don't have permission to view the room state.",
|
||||
));
|
||||
}
|
||||
|
||||
let event =
|
||||
services().rooms.state_accessor.room_state_get(&body.room_id, &body.event_type, &body.state_key)?.ok_or_else(
|
||||
|| {
|
||||
warn!("State event {:?} not found in room {:?}", &body.event_type, &body.room_id);
|
||||
Error::BadRequest(ErrorKind::NotFound, "State event not found.")
|
||||
},
|
||||
)?;
|
||||
if body.format.as_ref().is_some_and(|f| f.to_lowercase().eq("event")) {
|
||||
let event = services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&body.room_id, &body.event_type, &body.state_key)?
|
||||
.ok_or_else(|| {
|
||||
warn!("State event {:?} not found in room {:?}", &body.event_type, &body.room_id);
|
||||
Error::BadRequest(ErrorKind::NotFound, "State event not found.")
|
||||
})?;
|
||||
if body
|
||||
.format
|
||||
.as_ref()
|
||||
.is_some_and(|f| f.to_lowercase().eq("event"))
|
||||
{
|
||||
Ok(get_state_events_for_key::v3::Response {
|
||||
content: None,
|
||||
event: serde_json::from_str(event.to_state_event().json().get()).map_err(|e| {
|
||||
|
@ -164,20 +177,31 @@ pub async fn get_state_events_for_empty_key_route(
|
|||
) -> Result<RumaResponse<get_state_events_for_key::v3::Response>> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if !services().rooms.state_accessor.user_can_see_state_events(sender_user, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"You don't have permission to view the room state.",
|
||||
));
|
||||
}
|
||||
|
||||
let event =
|
||||
services().rooms.state_accessor.room_state_get(&body.room_id, &body.event_type, "")?.ok_or_else(|| {
|
||||
let event = services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&body.room_id, &body.event_type, "")?
|
||||
.ok_or_else(|| {
|
||||
warn!("State event {:?} not found in room {:?}", &body.event_type, &body.room_id);
|
||||
Error::BadRequest(ErrorKind::NotFound, "State event not found.")
|
||||
})?;
|
||||
|
||||
if body.format.as_ref().is_some_and(|f| f.to_lowercase().eq("event")) {
|
||||
if body
|
||||
.format
|
||||
.as_ref()
|
||||
.is_some_and(|f| f.to_lowercase().eq("event"))
|
||||
{
|
||||
Ok(get_state_events_for_key::v3::Response {
|
||||
content: None,
|
||||
event: serde_json::from_str(event.to_state_event().json().get()).map_err(|e| {
|
||||
|
@ -229,8 +253,15 @@ async fn send_state_event_for_key_helper(
|
|||
}
|
||||
}
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(room_id.to_owned()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
let event_id = services()
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,7 +18,9 @@ use crate::{services, Error, Result, Ruma};
|
|||
pub async fn update_tag_route(body: Ruma<create_tag::v3::Request>) -> Result<create_tag::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
let event = services().account_data.get(Some(&body.room_id), sender_user, RoomAccountDataEventType::Tag)?;
|
||||
let event = services()
|
||||
.account_data
|
||||
.get(Some(&body.room_id), sender_user, RoomAccountDataEventType::Tag)?;
|
||||
|
||||
let mut tags_event = event.map_or_else(
|
||||
|| {
|
||||
|
@ -31,7 +33,10 @@ pub async fn update_tag_route(body: Ruma<create_tag::v3::Request>) -> Result<cre
|
|||
|e| serde_json::from_str(e.get()).map_err(|_| Error::bad_database("Invalid account data event in db.")),
|
||||
)?;
|
||||
|
||||
tags_event.content.tags.insert(body.tag.clone().into(), body.tag_info.clone());
|
||||
tags_event
|
||||
.content
|
||||
.tags
|
||||
.insert(body.tag.clone().into(), body.tag_info.clone());
|
||||
|
||||
services().account_data.update(
|
||||
Some(&body.room_id),
|
||||
|
@ -51,7 +56,9 @@ pub async fn update_tag_route(body: Ruma<create_tag::v3::Request>) -> Result<cre
|
|||
pub async fn delete_tag_route(body: Ruma<delete_tag::v3::Request>) -> Result<delete_tag::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
let event = services().account_data.get(Some(&body.room_id), sender_user, RoomAccountDataEventType::Tag)?;
|
||||
let event = services()
|
||||
.account_data
|
||||
.get(Some(&body.room_id), sender_user, RoomAccountDataEventType::Tag)?;
|
||||
|
||||
let mut tags_event = event.map_or_else(
|
||||
|| {
|
||||
|
@ -84,7 +91,9 @@ pub async fn delete_tag_route(body: Ruma<delete_tag::v3::Request>) -> Result<del
|
|||
pub async fn get_tags_route(body: Ruma<get_tags::v3::Request>) -> Result<get_tags::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
let event = services().account_data.get(Some(&body.room_id), sender_user, RoomAccountDataEventType::Tag)?;
|
||||
let event = services()
|
||||
.account_data
|
||||
.get(Some(&body.room_id), sender_user, RoomAccountDataEventType::Tag)?;
|
||||
|
||||
let tags_event = event.map_or_else(
|
||||
|| {
|
||||
|
|
|
@ -7,10 +7,15 @@ pub async fn get_threads_route(body: Ruma<get_threads::v1::Request>) -> Result<g
|
|||
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().map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, ""))?
|
||||
from.parse()
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, ""))?
|
||||
} else {
|
||||
u64::MAX
|
||||
};
|
||||
|
@ -33,7 +38,10 @@ pub async fn get_threads_route(body: Ruma<get_threads::v1::Request>) -> Result<g
|
|||
let next_batch = threads.last().map(|(count, _)| count.to_string());
|
||||
|
||||
Ok(get_threads::v1::Response {
|
||||
chunk: threads.into_iter().map(|(_, pdu)| pdu.to_room_event()).collect(),
|
||||
chunk: threads
|
||||
.into_iter()
|
||||
.map(|(_, pdu)| pdu.to_room_event())
|
||||
.collect(),
|
||||
next_batch,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -20,7 +20,11 @@ pub async fn send_event_to_device_route(
|
|||
let sender_device = body.sender_device.as_deref();
|
||||
|
||||
// Check if this is a new transaction id
|
||||
if services().transaction_ids.existing_txnid(sender_user, sender_device, &body.txn_id)?.is_some() {
|
||||
if services()
|
||||
.transaction_ids
|
||||
.existing_txnid(sender_user, sender_device, &body.txn_id)?
|
||||
.is_some()
|
||||
{
|
||||
return Ok(send_event_to_device::v3::Response {});
|
||||
}
|
||||
|
||||
|
@ -79,7 +83,9 @@ pub 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 {})
|
||||
}
|
||||
|
|
|
@ -12,7 +12,11 @@ pub 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."));
|
||||
}
|
||||
|
||||
|
@ -28,7 +32,12 @@ pub async fn create_typing_event_route(
|
|||
)
|
||||
.await?;
|
||||
} else {
|
||||
services().rooms.edus.typing.typing_remove(sender_user, &body.room_id).await?;
|
||||
services()
|
||||
.rooms
|
||||
.edus
|
||||
.typing
|
||||
.typing_remove(sender_user, &body.room_id)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(create_typing_event::v3::Response {})
|
||||
|
|
|
@ -29,12 +29,19 @@ pub async fn search_users_route(body: Ruma<search_users::v3::Request>) -> Result
|
|||
avatar_url: services().users.avatar_url(&user_id).ok()?,
|
||||
};
|
||||
|
||||
let user_id_matches = user.user_id.to_string().to_lowercase().contains(&body.search_term.to_lowercase());
|
||||
let user_id_matches = user
|
||||
.user_id
|
||||
.to_string()
|
||||
.to_lowercase()
|
||||
.contains(&body.search_term.to_lowercase());
|
||||
|
||||
let user_displayname_matches = user
|
||||
.display_name
|
||||
.as_ref()
|
||||
.filter(|name| name.to_lowercase().contains(&body.search_term.to_lowercase()))
|
||||
.filter(|name| {
|
||||
name.to_lowercase()
|
||||
.contains(&body.search_term.to_lowercase())
|
||||
})
|
||||
.is_some();
|
||||
|
||||
if !user_id_matches && !user_displayname_matches {
|
||||
|
@ -44,24 +51,34 @@ pub async fn search_users_route(body: Ruma<search_users::v3::Request>) -> Result
|
|||
// It's a matching user, but is the sender allowed to see them?
|
||||
let mut user_visible = false;
|
||||
|
||||
let user_is_in_public_rooms =
|
||||
services().rooms.state_cache.rooms_joined(&user_id).filter_map(Result::ok).any(|room| {
|
||||
services().rooms.state_accessor.room_state_get(&room, &StateEventType::RoomJoinRules, "").map_or(
|
||||
false,
|
||||
|event| {
|
||||
let user_is_in_public_rooms = services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.rooms_joined(&user_id)
|
||||
.filter_map(Result::ok)
|
||||
.any(|room| {
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.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| r.join_rule == JoinRule::Public)
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
if user_is_in_public_rooms {
|
||||
user_visible = true;
|
||||
} else {
|
||||
let user_is_in_shared_rooms =
|
||||
services().rooms.user.get_shared_rooms(vec![sender_user.clone(), user_id]).ok()?.next().is_some();
|
||||
let user_is_in_shared_rooms = services()
|
||||
.rooms
|
||||
.user
|
||||
.get_shared_rooms(vec![sender_user.clone(), user_id])
|
||||
.ok()?
|
||||
.next()
|
||||
.is_some();
|
||||
|
||||
if user_is_in_shared_rooms {
|
||||
user_visible = true;
|
||||
|
|
|
@ -44,14 +44,16 @@ where
|
|||
let (mut parts, mut body) = match req.with_limited_body() {
|
||||
Ok(limited_req) => {
|
||||
let (parts, body) = limited_req.into_parts();
|
||||
let body =
|
||||
to_bytes(body).await.map_err(|_| Error::BadRequest(ErrorKind::MissingToken, "Missing token."))?;
|
||||
let body = to_bytes(body)
|
||||
.await
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::MissingToken, "Missing token."))?;
|
||||
(parts, body)
|
||||
},
|
||||
Err(original_req) => {
|
||||
let (parts, body) = original_req.into_parts();
|
||||
let body =
|
||||
to_bytes(body).await.map_err(|_| Error::BadRequest(ErrorKind::MissingToken, "Missing token."))?;
|
||||
let body = to_bytes(body)
|
||||
.await
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::MissingToken, "Missing token."))?;
|
||||
(parts, body)
|
||||
},
|
||||
};
|
||||
|
@ -180,8 +182,10 @@ where
|
|||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let TypedHeader(Authorization(x_matrix)) =
|
||||
parts.extract::<TypedHeader<Authorization<XMatrix>>>().await.map_err(|e| {
|
||||
let TypedHeader(Authorization(x_matrix)) = parts
|
||||
.extract::<TypedHeader<Authorization<XMatrix>>>()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Missing or invalid Authorization header: {}", e);
|
||||
|
||||
let msg = match e.reason() {
|
||||
|
@ -265,7 +269,11 @@ where
|
|||
AuthScheme::None => match parts.uri.path() {
|
||||
// allow_public_room_directory_without_auth
|
||||
"/_matrix/client/v3/publicRooms" | "/_matrix/client/r0/publicRooms" => {
|
||||
if !services().globals.config.allow_public_room_directory_without_auth {
|
||||
if !services()
|
||||
.globals
|
||||
.config
|
||||
.allow_public_room_directory_without_auth
|
||||
{
|
||||
let token = match token {
|
||||
Some(token) => token,
|
||||
_ => return Err(Error::BadRequest(ErrorKind::MissingToken, "Missing access token.")),
|
||||
|
@ -362,7 +370,9 @@ impl Credentials for XMatrix {
|
|||
"HeaderValue to decode should start with \"X-Matrix ..\", received = {value:?}",
|
||||
);
|
||||
|
||||
let parameters = str::from_utf8(&value.as_bytes()["X-Matrix ".len()..]).ok()?.trim_start();
|
||||
let parameters = str::from_utf8(&value.as_bytes()["X-Matrix ".len()..])
|
||||
.ok()?
|
||||
.trim_start();
|
||||
|
||||
let mut origin = None;
|
||||
let mut destination = None;
|
||||
|
@ -374,7 +384,10 @@ impl Credentials for XMatrix {
|
|||
|
||||
// It's not at all clear why some fields are quoted and others not in the spec,
|
||||
// let's simply accept either form for every field.
|
||||
let value = value.strip_prefix('"').and_then(|rest| rest.strip_suffix('"')).unwrap_or(value);
|
||||
let value = value
|
||||
.strip_prefix('"')
|
||||
.and_then(|rest| rest.strip_suffix('"'))
|
||||
.unwrap_or(value);
|
||||
|
||||
// FIXME: Catch multiple fields of the same name
|
||||
match name {
|
||||
|
|
|
@ -159,7 +159,13 @@ where
|
|||
|
||||
let mut write_destination_to_cache = false;
|
||||
|
||||
let cached_result = services().globals.actual_destinations().read().await.get(destination).cloned();
|
||||
let cached_result = services()
|
||||
.globals
|
||||
.actual_destinations()
|
||||
.read()
|
||||
.await
|
||||
.get(destination)
|
||||
.cloned();
|
||||
|
||||
let (actual_destination, host) = if let Some(result) = cached_result {
|
||||
result
|
||||
|
@ -196,7 +202,12 @@ where
|
|||
request_map.insert("method".to_owned(), T::METADATA.method.to_string().into());
|
||||
request_map.insert(
|
||||
"uri".to_owned(),
|
||||
http_request.uri().path_and_query().expect("all requests have a path").to_string().into(),
|
||||
http_request
|
||||
.uri()
|
||||
.path_and_query()
|
||||
.expect("all requests have a path")
|
||||
.to_string()
|
||||
.into(),
|
||||
);
|
||||
request_map.insert("origin".to_owned(), services().globals.server_name().as_str().into());
|
||||
request_map.insert("destination".to_owned(), destination.as_str().into());
|
||||
|
@ -217,7 +228,12 @@ where
|
|||
.as_object()
|
||||
.unwrap()
|
||||
.values()
|
||||
.map(|v| v.as_object().unwrap().iter().map(|(k, v)| (k, v.as_str().unwrap())));
|
||||
.map(|v| {
|
||||
v.as_object()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(k, v)| (k, v.as_str().unwrap()))
|
||||
});
|
||||
|
||||
for signature_server in signatures {
|
||||
for s in signature_server {
|
||||
|
@ -257,7 +273,12 @@ where
|
|||
}
|
||||
|
||||
debug!("Sending request to {destination} at {url}");
|
||||
let response = services().globals.client.federation.execute(reqwest_request).await;
|
||||
let response = services()
|
||||
.globals
|
||||
.client
|
||||
.federation
|
||||
.execute(reqwest_request)
|
||||
.await;
|
||||
debug!("Received response from {destination} at {url}");
|
||||
|
||||
match response {
|
||||
|
@ -283,10 +304,14 @@ where
|
|||
}
|
||||
|
||||
let status = response.status();
|
||||
let mut http_response_builder = http::Response::builder().status(status).version(response.version());
|
||||
let mut http_response_builder = http::Response::builder()
|
||||
.status(status)
|
||||
.version(response.version());
|
||||
mem::swap(
|
||||
response.headers_mut(),
|
||||
http_response_builder.headers_mut().expect("http::response::Builder is usable"),
|
||||
http_response_builder
|
||||
.headers_mut()
|
||||
.expect("http::response::Builder is usable"),
|
||||
);
|
||||
|
||||
debug!("Getting response bytes from {destination}");
|
||||
|
@ -301,11 +326,16 @@ where
|
|||
"Response not successful\n{} {}: {}",
|
||||
url,
|
||||
status,
|
||||
String::from_utf8_lossy(&body).lines().collect::<Vec<_>>().join(" ")
|
||||
String::from_utf8_lossy(&body)
|
||||
.lines()
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
);
|
||||
}
|
||||
|
||||
let http_response = http_response_builder.body(body).expect("reqwest body is valid http body");
|
||||
let http_response = http_response_builder
|
||||
.body(body)
|
||||
.expect("reqwest body is valid http body");
|
||||
|
||||
if status.is_success() {
|
||||
debug!("Parsing response bytes from {destination}");
|
||||
|
@ -490,7 +520,12 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe
|
|||
}
|
||||
|
||||
async fn query_and_cache_override(overname: &'_ str, hostname: &'_ str, port: u16) {
|
||||
match services().globals.dns_resolver().lookup_ip(hostname.to_owned()).await {
|
||||
match services()
|
||||
.globals
|
||||
.dns_resolver()
|
||||
.lookup_ip(hostname.to_owned())
|
||||
.await
|
||||
{
|
||||
Ok(override_ip) => {
|
||||
debug!("Caching result of {:?} overriding {:?}", hostname, overname);
|
||||
|
||||
|
@ -521,7 +556,11 @@ async fn query_srv_record(hostname: &'_ str) -> Option<FedDest> {
|
|||
async fn lookup_srv(hostname: &str) -> Result<SrvLookup, ResolveError> {
|
||||
debug!("querying SRV for {:?}", hostname);
|
||||
let hostname = hostname.trim_end_matches('.');
|
||||
services().globals.dns_resolver().srv_lookup(hostname.to_owned()).await
|
||||
services()
|
||||
.globals
|
||||
.dns_resolver()
|
||||
.srv_lookup(hostname.to_owned())
|
||||
.await
|
||||
}
|
||||
|
||||
let first_hostname = format!("_matrix-fed._tcp.{hostname}.");
|
||||
|
@ -539,7 +578,14 @@ async fn query_srv_record(hostname: &'_ str) -> Option<FedDest> {
|
|||
}
|
||||
|
||||
async fn request_well_known(destination: &str) -> Option<String> {
|
||||
if !services().globals.resolver.overrides.read().unwrap().contains_key(destination) {
|
||||
if !services()
|
||||
.globals
|
||||
.resolver
|
||||
.overrides
|
||||
.read()
|
||||
.unwrap()
|
||||
.contains_key(destination)
|
||||
{
|
||||
query_and_cache_override(destination, destination, 8448).await;
|
||||
}
|
||||
|
||||
|
@ -663,7 +709,10 @@ pub async fn get_server_keys_deprecated_route() -> impl IntoResponse { get_serve
|
|||
pub async fn get_public_rooms_filtered_route(
|
||||
body: Ruma<get_public_rooms_filtered::v1::Request>,
|
||||
) -> Result<get_public_rooms_filtered::v1::Response> {
|
||||
if !services().globals.allow_public_room_directory_over_federation() {
|
||||
if !services()
|
||||
.globals
|
||||
.allow_public_room_directory_over_federation()
|
||||
{
|
||||
return Err(Error::bad_config("Room directory is not public."));
|
||||
}
|
||||
|
||||
|
@ -690,7 +739,10 @@ pub async fn get_public_rooms_filtered_route(
|
|||
pub async fn get_public_rooms_route(
|
||||
body: Ruma<get_public_rooms::v1::Request>,
|
||||
) -> Result<get_public_rooms::v1::Response> {
|
||||
if !services().globals.allow_public_room_directory_over_federation() {
|
||||
if !services()
|
||||
.globals
|
||||
.allow_public_room_directory_over_federation()
|
||||
{
|
||||
return Err(Error::bad_config("Room directory is not public."));
|
||||
}
|
||||
|
||||
|
@ -743,7 +795,10 @@ pub fn parse_incoming_pdu(pdu: &RawJsonValue) -> Result<(OwnedEventId, Canonical
|
|||
pub async fn send_transaction_message_route(
|
||||
body: Ruma<send_transaction_message::v1::Request>,
|
||||
) -> Result<send_transaction_message::v1::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
let mut resolved_map = BTreeMap::new();
|
||||
|
||||
|
@ -799,8 +854,15 @@ pub async fn send_transaction_message_route(
|
|||
});
|
||||
|
||||
for (event_id, value, room_id) in parsed_pdus {
|
||||
let mutex =
|
||||
Arc::clone(services().globals.roomid_mutex_federation.write().await.entry(room_id.clone()).or_default());
|
||||
let mutex = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_federation
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let mutex_lock = mutex.lock().await;
|
||||
let start_time = Instant::now();
|
||||
resolved_map.insert(
|
||||
|
@ -831,7 +893,11 @@ pub async fn send_transaction_message_route(
|
|||
}
|
||||
}
|
||||
|
||||
for edu in body.edus.iter().filter_map(|edu| serde_json::from_str::<Edu>(edu.json().get()).ok()) {
|
||||
for edu in body
|
||||
.edus
|
||||
.iter()
|
||||
.filter_map(|edu| serde_json::from_str::<Edu>(edu.json().get()).ok())
|
||||
{
|
||||
match edu {
|
||||
Edu::Presence(presence) => {
|
||||
if !services().globals.allow_incoming_presence() {
|
||||
|
@ -862,7 +928,13 @@ pub async fn send_transaction_message_route(
|
|||
.event_ids
|
||||
.iter()
|
||||
.filter_map(|id| {
|
||||
services().rooms.timeline.get_pdu_count(id).ok().flatten().map(|r| (id, r))
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.get_pdu_count(id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|r| (id, r))
|
||||
})
|
||||
.max_by_key(|(_, count)| *count)
|
||||
{
|
||||
|
@ -879,7 +951,11 @@ pub async fn send_transaction_message_route(
|
|||
content: ReceiptEventContent(receipt_content),
|
||||
room_id: room_id.clone(),
|
||||
};
|
||||
services().rooms.edus.read_receipt.readreceipt_update(&user_id, &room_id, event)?;
|
||||
services()
|
||||
.rooms
|
||||
.edus
|
||||
.read_receipt
|
||||
.readreceipt_update(&user_id, &room_id, event)?;
|
||||
} else {
|
||||
// TODO fetch missing events
|
||||
debug!("No known event ids in read receipt: {:?}", user_updates);
|
||||
|
@ -888,7 +964,11 @@ pub async fn send_transaction_message_route(
|
|||
}
|
||||
},
|
||||
Edu::Typing(typing) => {
|
||||
if services().rooms.state_cache.is_joined(&typing.user_id, &typing.room_id)? {
|
||||
if services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.is_joined(&typing.user_id, &typing.room_id)?
|
||||
{
|
||||
if typing.typing {
|
||||
services()
|
||||
.rooms
|
||||
|
@ -897,7 +977,12 @@ pub async fn send_transaction_message_route(
|
|||
.typing_add(&typing.user_id, &typing.room_id, 3000 + utils::millis_since_unix_epoch())
|
||||
.await?;
|
||||
} else {
|
||||
services().rooms.edus.typing.typing_remove(&typing.user_id, &typing.room_id).await?;
|
||||
services()
|
||||
.rooms
|
||||
.edus
|
||||
.typing
|
||||
.typing_remove(&typing.user_id, &typing.room_id)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -914,7 +999,11 @@ pub async fn send_transaction_message_route(
|
|||
messages,
|
||||
}) => {
|
||||
// Check if this is a new transaction id
|
||||
if services().transaction_ids.existing_txnid(&sender, None, &message_id)?.is_some() {
|
||||
if services()
|
||||
.transaction_ids
|
||||
.existing_txnid(&sender, None, &message_id)?
|
||||
.is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -952,7 +1041,9 @@ pub async fn send_transaction_message_route(
|
|||
}
|
||||
|
||||
// Save transaction id with empty data
|
||||
services().transaction_ids.add_txnid(&sender, None, &message_id, &[])?;
|
||||
services()
|
||||
.transaction_ids
|
||||
.add_txnid(&sender, None, &message_id, &[])?;
|
||||
},
|
||||
Edu::SigningKeyUpdate(SigningKeyUpdateContent {
|
||||
user_id,
|
||||
|
@ -963,7 +1054,9 @@ pub async fn send_transaction_message_route(
|
|||
continue;
|
||||
}
|
||||
if let Some(master_key) = master_key {
|
||||
services().users.add_cross_signing_keys(&user_id, &master_key, &self_signing_key, &None, true)?;
|
||||
services()
|
||||
.users
|
||||
.add_cross_signing_keys(&user_id, &master_key, &self_signing_key, &None, true)?;
|
||||
}
|
||||
},
|
||||
Edu::_Custom(_) => {},
|
||||
|
@ -971,7 +1064,10 @@ pub async fn send_transaction_message_route(
|
|||
}
|
||||
|
||||
Ok(send_transaction_message::v1::Response {
|
||||
pdus: resolved_map.into_iter().map(|(e, r)| (e, r.map_err(|e| e.sanitized_error()))).collect(),
|
||||
pdus: resolved_map
|
||||
.into_iter()
|
||||
.map(|(e, r)| (e, r.map_err(|e| e.sanitized_error())))
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -982,12 +1078,19 @@ pub async fn send_transaction_message_route(
|
|||
/// - Only works if a user of this server is currently invited or joined the
|
||||
/// room
|
||||
pub async fn get_event_route(body: Ruma<get_event::v1::Request>) -> Result<get_event::v1::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
let event = services().rooms.timeline.get_pdu_json(&body.event_id)?.ok_or_else(|| {
|
||||
warn!("Event not found, event ID: {:?}", &body.event_id);
|
||||
Error::BadRequest(ErrorKind::NotFound, "Event not found.")
|
||||
})?;
|
||||
let event = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.get_pdu_json(&body.event_id)?
|
||||
.ok_or_else(|| {
|
||||
warn!("Event not found, event ID: {:?}", &body.event_id);
|
||||
Error::BadRequest(ErrorKind::NotFound, "Event not found.")
|
||||
})?;
|
||||
|
||||
let room_id_str = event
|
||||
.get("room_id")
|
||||
|
@ -997,11 +1100,19 @@ pub async fn get_event_route(body: Ruma<get_event::v1::Request>) -> Result<get_e
|
|||
let room_id = <&RoomId>::try_from(room_id_str)
|
||||
.map_err(|_| Error::bad_database("Invalid room id field in event in database"))?;
|
||||
|
||||
if !services().rooms.state_cache.server_in_room(sender_servername, room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(sender_servername, room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Server is not in room"));
|
||||
}
|
||||
|
||||
if !services().rooms.state_accessor.server_can_see_event(sender_servername, room_id, &body.event_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.server_can_see_event(sender_servername, room_id, &body.event_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Server is not allowed to see event."));
|
||||
}
|
||||
|
||||
|
@ -1017,15 +1128,25 @@ pub async fn get_event_route(body: Ruma<get_event::v1::Request>) -> Result<get_e
|
|||
/// Retrieves events from before the sender joined the room, if the room's
|
||||
/// history visibility allows.
|
||||
pub async fn get_backfill_route(body: Ruma<get_backfill::v1::Request>) -> Result<get_backfill::v1::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
debug!("Got backfill request from: {}", sender_servername);
|
||||
|
||||
if !services().rooms.state_cache.server_in_room(sender_servername, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(sender_servername, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Server is not in room."));
|
||||
}
|
||||
|
||||
services().rooms.event_handler.acl_check(sender_servername, &body.room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.acl_check(sender_servername, &body.room_id)?;
|
||||
|
||||
let until = body
|
||||
.v
|
||||
|
@ -1047,7 +1168,10 @@ pub async fn get_backfill_route(body: Ruma<get_backfill::v1::Request>) -> Result
|
|||
.filter_map(Result::ok)
|
||||
.filter(|(_, e)| {
|
||||
matches!(
|
||||
services().rooms.state_accessor.server_can_see_event(sender_servername, &e.room_id, &e.event_id,),
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.server_can_see_event(sender_servername, &e.room_id, &e.event_id,),
|
||||
Ok(true),
|
||||
)
|
||||
})
|
||||
|
@ -1069,13 +1193,23 @@ pub async fn get_backfill_route(body: Ruma<get_backfill::v1::Request>) -> Result
|
|||
pub async fn get_missing_events_route(
|
||||
body: Ruma<get_missing_events::v1::Request>,
|
||||
) -> Result<get_missing_events::v1::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
if !services().rooms.state_cache.server_in_room(sender_servername, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(sender_servername, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Server is not in room"));
|
||||
}
|
||||
|
||||
services().rooms.event_handler.acl_check(sender_servername, &body.room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.acl_check(sender_servername, &body.room_id)?;
|
||||
|
||||
let mut queued_events = body.latest_events.clone();
|
||||
let mut events = Vec::new();
|
||||
|
@ -1142,18 +1276,32 @@ pub async fn get_missing_events_route(
|
|||
pub async fn get_event_authorization_route(
|
||||
body: Ruma<get_event_authorization::v1::Request>,
|
||||
) -> Result<get_event_authorization::v1::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
if !services().rooms.state_cache.server_in_room(sender_servername, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(sender_servername, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Server is not in room."));
|
||||
}
|
||||
|
||||
services().rooms.event_handler.acl_check(sender_servername, &body.room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.acl_check(sender_servername, &body.room_id)?;
|
||||
|
||||
let event = services().rooms.timeline.get_pdu_json(&body.event_id)?.ok_or_else(|| {
|
||||
warn!("Event not found, event ID: {:?}", &body.event_id);
|
||||
Error::BadRequest(ErrorKind::NotFound, "Event not found.")
|
||||
})?;
|
||||
let event = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.get_pdu_json(&body.event_id)?
|
||||
.ok_or_else(|| {
|
||||
warn!("Event not found, event ID: {:?}", &body.event_id);
|
||||
Error::BadRequest(ErrorKind::NotFound, "Event not found.")
|
||||
})?;
|
||||
|
||||
let room_id_str = event
|
||||
.get("room_id")
|
||||
|
@ -1163,7 +1311,11 @@ pub async fn get_event_authorization_route(
|
|||
let room_id = <&RoomId>::try_from(room_id_str)
|
||||
.map_err(|_| Error::bad_database("Invalid room id field in event in database"))?;
|
||||
|
||||
let auth_chain_ids = services().rooms.auth_chain.get_auth_chain(room_id, vec![Arc::from(&*body.event_id)]).await?;
|
||||
let auth_chain_ids = services()
|
||||
.rooms
|
||||
.auth_chain
|
||||
.get_auth_chain(room_id, vec![Arc::from(&*body.event_id)])
|
||||
.await?;
|
||||
|
||||
Ok(get_event_authorization::v1::Response {
|
||||
auth_chain: auth_chain_ids
|
||||
|
@ -1177,13 +1329,23 @@ pub async fn get_event_authorization_route(
|
|||
///
|
||||
/// Retrieves the current state of the room.
|
||||
pub async fn get_room_state_route(body: Ruma<get_room_state::v1::Request>) -> Result<get_room_state::v1::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
if !services().rooms.state_cache.server_in_room(sender_servername, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(sender_servername, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Server is not in room."));
|
||||
}
|
||||
|
||||
services().rooms.event_handler.acl_check(sender_servername, &body.room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.acl_check(sender_servername, &body.room_id)?;
|
||||
|
||||
let shortstatehash = services()
|
||||
.rooms
|
||||
|
@ -1199,13 +1361,21 @@ pub async fn get_room_state_route(body: Ruma<get_room_state::v1::Request>) -> Re
|
|||
.into_values()
|
||||
.map(|id| {
|
||||
PduEvent::convert_to_outgoing_federation_event(
|
||||
services().rooms.timeline.get_pdu_json(&id).unwrap().unwrap(),
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.get_pdu_json(&id)
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let auth_chain_ids =
|
||||
services().rooms.auth_chain.get_auth_chain(&body.room_id, vec![Arc::from(&*body.event_id)]).await?;
|
||||
let auth_chain_ids = services()
|
||||
.rooms
|
||||
.auth_chain
|
||||
.get_auth_chain(&body.room_id, vec![Arc::from(&*body.event_id)])
|
||||
.await?;
|
||||
|
||||
Ok(get_room_state::v1::Response {
|
||||
auth_chain: auth_chain_ids
|
||||
|
@ -1227,13 +1397,23 @@ pub async fn get_room_state_route(body: Ruma<get_room_state::v1::Request>) -> Re
|
|||
pub async fn get_room_state_ids_route(
|
||||
body: Ruma<get_room_state_ids::v1::Request>,
|
||||
) -> Result<get_room_state_ids::v1::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
if !services().rooms.state_cache.server_in_room(sender_servername, &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(sender_servername, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Server is not in room."));
|
||||
}
|
||||
|
||||
services().rooms.event_handler.acl_check(sender_servername, &body.room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.acl_check(sender_servername, &body.room_id)?;
|
||||
|
||||
let shortstatehash = services()
|
||||
.rooms
|
||||
|
@ -1250,8 +1430,11 @@ pub async fn get_room_state_ids_route(
|
|||
.map(|id| (*id).to_owned())
|
||||
.collect();
|
||||
|
||||
let auth_chain_ids =
|
||||
services().rooms.auth_chain.get_auth_chain(&body.room_id, vec![Arc::from(&*body.event_id)]).await?;
|
||||
let auth_chain_ids = services()
|
||||
.rooms
|
||||
.auth_chain
|
||||
.get_auth_chain(&body.room_id, vec![Arc::from(&*body.event_id)])
|
||||
.await?;
|
||||
|
||||
Ok(get_room_state_ids::v1::Response {
|
||||
auth_chain_ids: auth_chain_ids.map(|id| (*id).to_owned()).collect(),
|
||||
|
@ -1269,17 +1452,33 @@ pub async fn create_join_event_template_route(
|
|||
return Err(Error::BadRequest(ErrorKind::NotFound, "Room is unknown to this server."));
|
||||
}
|
||||
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
services().rooms.event_handler.acl_check(sender_servername, &body.room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.acl_check(sender_servername, &body.room_id)?;
|
||||
|
||||
let mutex_state =
|
||||
Arc::clone(services().globals.roomid_mutex_state.write().await.entry(body.room_id.clone()).or_default());
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
// TODO: Conduit does not implement restricted join rules yet, we always reject
|
||||
let join_rules_event =
|
||||
services().rooms.state_accessor.room_state_get(&body.room_id, &StateEventType::RoomJoinRules, "")?;
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&body.room_id, &StateEventType::RoomJoinRules, "")?;
|
||||
|
||||
let join_rules_event_content: Option<RoomJoinRulesEventContent> = join_rules_event
|
||||
.as_ref()
|
||||
|
@ -1376,11 +1575,17 @@ async fn create_join_event(
|
|||
return Err(Error::BadRequest(ErrorKind::NotFound, "Room is unknown to this server."));
|
||||
}
|
||||
|
||||
services().rooms.event_handler.acl_check(sender_servername, room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.acl_check(sender_servername, room_id)?;
|
||||
|
||||
// TODO: Conduit does not implement restricted join rules yet, we always reject
|
||||
let join_rules_event =
|
||||
services().rooms.state_accessor.room_state_get(room_id, &StateEventType::RoomJoinRules, "")?;
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(room_id, &StateEventType::RoomJoinRules, "")?;
|
||||
|
||||
let join_rules_event_content: Option<RoomJoinRulesEventContent> = join_rules_event
|
||||
.as_ref()
|
||||
|
@ -1431,16 +1636,29 @@ async fn create_join_event(
|
|||
|
||||
let origin: OwnedServerName = serde_json::from_value(
|
||||
serde_json::to_value(
|
||||
value.get("origin").ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Event needs an origin field."))?,
|
||||
value
|
||||
.get("origin")
|
||||
.ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Event needs an origin field."))?,
|
||||
)
|
||||
.expect("CanonicalJson is valid json value"),
|
||||
)
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Origin field is invalid."))?;
|
||||
|
||||
services().rooms.event_handler.fetch_required_signing_keys([&value], &pub_key_map).await?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_required_signing_keys([&value], &pub_key_map)
|
||||
.await?;
|
||||
|
||||
let mutex =
|
||||
Arc::clone(services().globals.roomid_mutex_federation.write().await.entry(room_id.to_owned()).or_default());
|
||||
let mutex = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_federation
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let mutex_lock = mutex.lock().await;
|
||||
let pdu_id: Vec<u8> = services()
|
||||
.rooms
|
||||
|
@ -1453,9 +1671,16 @@ async fn create_join_event(
|
|||
))?;
|
||||
drop(mutex_lock);
|
||||
|
||||
let state_ids = services().rooms.state_accessor.state_full_ids(shortstatehash).await?;
|
||||
let auth_chain_ids =
|
||||
services().rooms.auth_chain.get_auth_chain(room_id, state_ids.values().cloned().collect()).await?;
|
||||
let state_ids = services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.state_full_ids(shortstatehash)
|
||||
.await?;
|
||||
let auth_chain_ids = services()
|
||||
.rooms
|
||||
.auth_chain
|
||||
.get_auth_chain(room_id, state_ids.values().cloned().collect())
|
||||
.await?;
|
||||
|
||||
let servers = services()
|
||||
.rooms
|
||||
|
@ -1486,7 +1711,10 @@ async fn create_join_event(
|
|||
pub async fn create_join_event_v1_route(
|
||||
body: Ruma<create_join_event::v1::Request>,
|
||||
) -> Result<create_join_event::v1::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
let room_state = create_join_event(sender_servername, &body.room_id, &body.pdu).await?;
|
||||
|
||||
|
@ -1501,7 +1729,10 @@ pub async fn create_join_event_v1_route(
|
|||
pub async fn create_join_event_v2_route(
|
||||
body: Ruma<create_join_event::v2::Request>,
|
||||
) -> Result<create_join_event::v2::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
let create_join_event::v1::RoomState {
|
||||
auth_chain,
|
||||
|
@ -1525,11 +1756,21 @@ pub async fn create_join_event_v2_route(
|
|||
///
|
||||
/// Invites a remote user to a room.
|
||||
pub async fn create_invite_route(body: Ruma<create_invite::v2::Request>) -> Result<create_invite::v2::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
services().rooms.event_handler.acl_check(sender_servername, &body.room_id)?;
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.acl_check(sender_servername, &body.room_id)?;
|
||||
|
||||
if !services().globals.supported_room_versions().contains(&body.room_version) {
|
||||
if !services()
|
||||
.globals
|
||||
.supported_room_versions()
|
||||
.contains(&body.room_version)
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::IncompatibleRoomVersion {
|
||||
room_version: body.room_version.clone(),
|
||||
|
@ -1619,7 +1860,11 @@ pub async fn create_invite_route(body: Ruma<create_invite::v2::Request>) -> Resu
|
|||
|
||||
// If we are active in the room, the remote server will notify us about the join
|
||||
// via /send
|
||||
if !services().rooms.state_cache.server_in_room(services().globals.server_name(), &body.room_id)? {
|
||||
if !services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(services().globals.server_name(), &body.room_id)?
|
||||
{
|
||||
services()
|
||||
.rooms
|
||||
.state_cache
|
||||
|
@ -1650,7 +1895,10 @@ pub async fn get_devices_route(body: Ruma<get_devices::v1::Request>) -> Result<g
|
|||
));
|
||||
}
|
||||
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
Ok(get_devices::v1::Response {
|
||||
user_id: body.user_id.clone(),
|
||||
|
@ -1672,13 +1920,18 @@ pub async fn get_devices_route(body: Ruma<get_devices::v1::Request>) -> Result<g
|
|||
Some(device_id_string)
|
||||
};
|
||||
Some(UserDevice {
|
||||
keys: services().users.get_device_keys(&body.user_id, &metadata.device_id).ok()??,
|
||||
keys: services()
|
||||
.users
|
||||
.get_device_keys(&body.user_id, &metadata.device_id)
|
||||
.ok()??,
|
||||
device_id: metadata.device_id,
|
||||
device_display_name,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
master_key: services().users.get_master_key(None, &body.user_id, &|u| u.server_name() == sender_servername)?,
|
||||
master_key: services()
|
||||
.users
|
||||
.get_master_key(None, &body.user_id, &|u| u.server_name() == sender_servername)?,
|
||||
self_signing_key: services()
|
||||
.users
|
||||
.get_self_signing_key(None, &body.user_id, &|u| u.server_name() == sender_servername)?,
|
||||
|
@ -1748,7 +2001,11 @@ pub async fn get_profile_information_route(
|
|||
///
|
||||
/// Gets devices and identity keys for the given users.
|
||||
pub async fn get_keys_route(body: Ruma<get_keys::v1::Request>) -> Result<get_keys::v1::Response> {
|
||||
if body.device_keys.iter().any(|(u, _)| u.server_name() != services().globals.server_name()) {
|
||||
if body
|
||||
.device_keys
|
||||
.iter()
|
||||
.any(|(u, _)| u.server_name() != services().globals.server_name())
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"User does not belong to this server.",
|
||||
|
@ -1774,7 +2031,11 @@ pub async fn get_keys_route(body: Ruma<get_keys::v1::Request>) -> Result<get_key
|
|||
///
|
||||
/// Claims one-time keys.
|
||||
pub async fn claim_keys_route(body: Ruma<claim_keys::v1::Request>) -> Result<claim_keys::v1::Response> {
|
||||
if body.one_time_keys.iter().any(|(u, _)| u.server_name() != services().globals.server_name()) {
|
||||
if body
|
||||
.one_time_keys
|
||||
.iter()
|
||||
.any(|(u, _)| u.server_name() != services().globals.server_name())
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Tried to access user from other server.",
|
||||
|
@ -1809,10 +2070,17 @@ pub async fn well_known_server_route() -> Result<impl IntoResponse> {
|
|||
/// Gets the space tree in a depth-first manner to locate child rooms of a given
|
||||
/// space.
|
||||
pub async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>) -> Result<get_hierarchy::v1::Response> {
|
||||
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
if services().rooms.metadata.exists(&body.room_id)? {
|
||||
services().rooms.spaces.get_federation_hierarchy(&body.room_id, sender_servername, body.suggested_only).await
|
||||
services()
|
||||
.rooms
|
||||
.spaces
|
||||
.get_federation_hierarchy(&body.room_id, sender_servername, body.suggested_only)
|
||||
.await
|
||||
} else {
|
||||
Err(Error::BadRequest(ErrorKind::NotFound, "Room does not exist."))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue