Macroize various remaining Error constructions.

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk
2025-04-26 23:50:03 +00:00
parent 130f61d409
commit 72fd072026
8 changed files with 58 additions and 110 deletions

View File

@@ -1,11 +1,8 @@
use std::time::Duration; use std::time::Duration;
use axum::extract::State; use axum::extract::State;
use ruma::{ use ruma::{api::client::account, authentication::TokenType};
api::client::{account, error::ErrorKind}, use tuwunel_core::{Err, Result, utils};
authentication::TokenType,
};
use tuwunel_core::{Error, Result, utils};
use super::TOKEN_LENGTH; use super::TOKEN_LENGTH;
use crate::Ruma; use crate::Ruma;
@@ -22,14 +19,12 @@ pub(crate) async fn create_openid_token_route(
let sender_user = body.sender_user(); let sender_user = body.sender_user();
if sender_user != body.user_id { if sender_user != body.user_id {
return Err(Error::BadRequest( return Err!(Request(InvalidParam(
ErrorKind::InvalidParam,
"Not allowed to request OpenID tokens on behalf of other users", "Not allowed to request OpenID tokens on behalf of other users",
)); )));
} }
let access_token = utils::random_string(TOKEN_LENGTH); let access_token = utils::random_string(TOKEN_LENGTH);
let expires_in = services let expires_in = services
.users .users
.create_openid_token(&body.user_id, &access_token)?; .create_openid_token(&body.user_id, &access_token)?;

View File

@@ -5,11 +5,8 @@ use futures::{StreamExt, TryStreamExt, future::join3};
use ruma::{ use ruma::{
OwnedMxcUri, OwnedRoomId, UserId, OwnedMxcUri, OwnedRoomId, UserId,
api::{ api::{
client::{ client::profile::{
error::ErrorKind, get_avatar_url, get_display_name, get_profile, set_avatar_url, set_display_name,
profile::{
get_avatar_url, get_display_name, get_profile, set_avatar_url, set_display_name,
},
}, },
federation, federation,
}, },
@@ -17,7 +14,7 @@ use ruma::{
presence::PresenceState, presence::PresenceState,
}; };
use tuwunel_core::{ use tuwunel_core::{
Err, Error, Result, Err, Result,
matrix::pdu::PduBuilder, matrix::pdu::PduBuilder,
utils::{IterStream, stream::TryIgnore}, utils::{IterStream, stream::TryIgnore},
warn, warn,
@@ -110,7 +107,7 @@ pub(crate) async fn get_displayname_route(
if !services.users.exists(&body.user_id).await { if !services.users.exists(&body.user_id).await {
// Return 404 if this user doesn't exist and we couldn't fetch it over // Return 404 if this user doesn't exist and we couldn't fetch it over
// federation // federation
return Err(Error::BadRequest(ErrorKind::NotFound, "Profile was not found.")); return Err!(Request(NotFound("Profile was not found.")));
} }
Ok(get_display_name::v3::Response { Ok(get_display_name::v3::Response {
@@ -218,7 +215,7 @@ pub(crate) async fn get_avatar_url_route(
if !services.users.exists(&body.user_id).await { if !services.users.exists(&body.user_id).await {
// Return 404 if this user doesn't exist and we couldn't fetch it over // Return 404 if this user doesn't exist and we couldn't fetch it over
// federation // federation
return Err(Error::BadRequest(ErrorKind::NotFound, "Profile was not found.")); return Err!(Request(NotFound("Profile was not found.")));
} }
Ok(get_avatar_url::v3::Response { Ok(get_avatar_url::v3::Response {
@@ -298,7 +295,7 @@ pub(crate) async fn get_profile_route(
if !services.users.exists(&body.user_id).await { if !services.users.exists(&body.user_id).await {
// Return 404 if this user doesn't exist and we couldn't fetch it over // Return 404 if this user doesn't exist and we couldn't fetch it over
// federation // federation
return Err(Error::BadRequest(ErrorKind::NotFound, "Profile was not found.")); return Err!(Request(NotFound("Profile was not found.")));
} }
let mut custom_profile_fields: BTreeMap<String, serde_json::Value> = services let mut custom_profile_fields: BTreeMap<String, serde_json::Value> = services

View File

@@ -223,7 +223,7 @@ pub(crate) async fn get_pushrule_route(
if let Some(rule) = rule { if let Some(rule) = rule {
Ok(get_pushrule::v3::Response { rule }) Ok(get_pushrule::v3::Response { rule })
} else { } else {
Err(Error::BadRequest(ErrorKind::NotFound, "Push rule not found.")) Err!(Request(NotFound("Push rule not found.")))
} }
} }
@@ -338,7 +338,7 @@ pub(crate) async fn set_pushrule_actions_route(
.set_actions(body.kind.clone(), &body.rule_id, body.actions.clone()) .set_actions(body.kind.clone(), &body.rule_id, body.actions.clone())
.is_err() .is_err()
{ {
return Err(Error::BadRequest(ErrorKind::NotFound, "Push rule not found.")); return Err!(Request(NotFound("Push rule not found.")));
} }
let ty = GlobalAccountDataEventType::PushRules; let ty = GlobalAccountDataEventType::PushRules;
@@ -405,7 +405,7 @@ pub(crate) async fn set_pushrule_enabled_route(
.set_enabled(body.kind.clone(), &body.rule_id, body.enabled) .set_enabled(body.kind.clone(), &body.rule_id, body.enabled)
.is_err() .is_err()
{ {
return Err(Error::BadRequest(ErrorKind::NotFound, "Push rule not found.")); return Err!(Request(NotFound("Push rule not found.")));
} }
let ty = GlobalAccountDataEventType::PushRules; let ty = GlobalAccountDataEventType::PushRules;

View File

@@ -5,17 +5,12 @@ use axum_client_ip::InsecureClientIp;
use rand::Rng; use rand::Rng;
use ruma::{ use ruma::{
EventId, RoomId, UserId, EventId, RoomId, UserId,
api::client::{ api::client::room::{report_content, report_room},
error::ErrorKind,
room::{report_content, report_room},
},
events::room::message, events::room::message,
int, int,
}; };
use tokio::time::sleep; use tokio::time::sleep;
use tuwunel_core::{ use tuwunel_core::{Err, Result, debug_info, info, matrix::pdu::PduEvent, utils::ReadyExt};
Err, Error, Result, debug_info, info, matrix::pdu::PduEvent, utils::ReadyExt,
};
use tuwunel_service::Services; use tuwunel_service::Services;
use crate::Ruma; use crate::Ruma;
@@ -43,9 +38,8 @@ pub(crate) async fn report_room_route(
.as_ref() .as_ref()
.is_some_and(|s| s.len() > 750) .is_some_and(|s| s.len() > 750)
{ {
return Err(Error::BadRequest( return Err!(Request(
ErrorKind::InvalidParam, InvalidParam("Reason too long, should be 750 characters or fewer",)
"Reason too long, should be 750 characters or fewer",
)); ));
} }
@@ -162,23 +156,16 @@ async fn is_event_report_valid(
); );
if room_id != pdu.room_id { if room_id != pdu.room_id {
return Err(Error::BadRequest( return Err!(Request(NotFound("Event ID does not belong to the reported room",)));
ErrorKind::NotFound,
"Event ID does not belong to the reported room",
));
} }
if score.is_some_and(|s| s > int!(0) || s < int!(-100)) { if score.is_some_and(|s| s > int!(0) || s < int!(-100)) {
return Err(Error::BadRequest( return Err!(Request(InvalidParam("Invalid score, must be within 0 to -100",)));
ErrorKind::InvalidParam,
"Invalid score, must be within 0 to -100",
));
} }
if reason.as_ref().is_some_and(|s| s.len() > 750) { if reason.as_ref().is_some_and(|s| s.len() > 750) {
return Err(Error::BadRequest( return Err!(Request(
ErrorKind::InvalidParam, InvalidParam("Reason too long, should be 750 characters or fewer",)
"Reason too long, should be 750 characters or fewer",
)); ));
} }
@@ -189,10 +176,7 @@ async fn is_event_report_valid(
.ready_any(|user_id| user_id == sender_user) .ready_any(|user_id| user_id == sender_user)
.await .await
{ {
return Err(Error::BadRequest( return Err!(Request(NotFound("You are not in the room you are reporting.",)));
ErrorKind::NotFound,
"You are not in the room you are reporting.",
));
} }
Ok(()) Ok(())

View File

@@ -1,7 +1,7 @@
use axum::extract::State; use axum::extract::State;
use futures::StreamExt; use futures::StreamExt;
use ruma::api::client::{error::ErrorKind, room::aliases}; use ruma::api::client::room::aliases;
use tuwunel_core::{Error, Result}; use tuwunel_core::{Err, Result};
use crate::Ruma; use crate::Ruma;
@@ -23,10 +23,7 @@ pub(crate) async fn get_room_aliases_route(
.user_can_see_state_events(sender_user, &body.room_id) .user_can_see_state_events(sender_user, &body.room_id)
.await .await
{ {
return Err(Error::BadRequest( return Err!(Request(Forbidden("You don't have permission to view this room.",)));
ErrorKind::forbidden(),
"You don't have permission to view this room.",
));
} }
Ok(aliases::v3::Response { Ok(aliases::v3::Response {

View File

@@ -4,10 +4,7 @@ use axum::extract::State;
use futures::FutureExt; use futures::FutureExt;
use ruma::{ use ruma::{
CanonicalJsonObject, Int, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomId, RoomVersionId, CanonicalJsonObject, Int, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomId, RoomVersionId,
api::client::{ api::client::room::{self, create_room},
error::ErrorKind,
room::{self, create_room},
},
events::{ events::{
TimelineEventType, TimelineEventType,
room::{ room::{
@@ -27,7 +24,7 @@ use ruma::{
}; };
use serde_json::{json, value::to_raw_value}; use serde_json::{json, value::to_raw_value};
use tuwunel_core::{ use tuwunel_core::{
Err, Error, Result, debug_info, debug_warn, err, error, info, Err, Result, debug_info, debug_warn, err, info,
matrix::{StateKey, pdu::PduBuilder}, matrix::{StateKey, pdu::PduBuilder},
warn, warn,
}; };
@@ -64,10 +61,7 @@ pub(crate) async fn create_room_route(
&& body.appservice_info.is_none() && body.appservice_info.is_none()
&& !services.users.is_admin(sender_user).await && !services.users.is_admin(sender_user).await
{ {
return Err(Error::BadRequest( return Err!(Request(Forbidden("Room creation has been disabled.",)));
ErrorKind::forbidden(),
"Room creation has been disabled.",
));
} }
let room_id: OwnedRoomId = match &body.room_id { let room_id: OwnedRoomId = match &body.room_id {
@@ -83,10 +77,7 @@ pub(crate) async fn create_room_route(
.await .await
.is_ok() .is_ok()
{ {
return Err(Error::BadRequest( return Err!(Request(RoomInUse("Room with that custom room ID already exists",)));
ErrorKind::RoomInUse,
"Room with that custom room ID already exists",
));
} }
if body.visibility == room::Visibility::Public if body.visibility == room::Visibility::Public
@@ -136,10 +127,9 @@ pub(crate) async fn create_room_route(
{ {
room_version room_version
} else { } else {
return Err(Error::BadRequest( return Err!(Request(UnsupportedRoomVersion(
ErrorKind::UnsupportedRoomVersion, "This server does not support that room version."
"This server does not support that room version.", )));
));
}, },
| None => services | None => services
.server .server
@@ -155,16 +145,17 @@ pub(crate) async fn create_room_route(
let mut content = content let mut content = content
.deserialize_as::<CanonicalJsonObject>() .deserialize_as::<CanonicalJsonObject>()
.map_err(|e| { .map_err(|e| {
error!("Failed to deserialise content as canonical JSON: {}", e); err!(Request(BadJson(error!(
Error::bad_database("Failed to deserialise content as canonical JSON.") "Failed to deserialise content as canonical JSON: {e}"
))))
})?; })?;
match room_version { match room_version {
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => { | V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
content.insert( content.insert(
"creator".into(), "creator".into(),
json!(&sender_user).try_into().map_err(|e| { json!(&sender_user).try_into().map_err(|e| {
info!("Invalid creation content: {e}"); err!(Request(BadJson(debug_error!("Invalid creation content: {e}"))))
Error::BadRequest(ErrorKind::BadJson, "Invalid creation content")
})?, })?,
); );
}, },
@@ -176,9 +167,7 @@ pub(crate) async fn create_room_route(
"room_version".into(), "room_version".into(),
json!(room_version.as_str()) json!(room_version.as_str())
.try_into() .try_into()
.map_err(|_| { .map_err(|e| err!(Request(BadJson("Invalid creation content: {e}"))))?,
Error::BadRequest(ErrorKind::BadJson, "Invalid creation content")
})?,
); );
content content
}, },
@@ -373,8 +362,7 @@ pub(crate) async fn create_room_route(
let mut pdu_builder = event let mut pdu_builder = event
.deserialize_as::<PduBuilder>() .deserialize_as::<PduBuilder>()
.map_err(|e| { .map_err(|e| {
warn!("Invalid initial state event: {:?}", e); err!(Request(InvalidParam(warn!("Invalid initial state event: {e:?}"))))
Error::BadRequest(ErrorKind::InvalidParam, "Invalid initial state event.")
})?; })?;
debug_info!("Room creation initial state event: {event:?}"); debug_info!("Room creation initial state event: {event:?}");
@@ -383,7 +371,7 @@ pub(crate) async fn create_room_route(
// state event in there with the content of literally `{}` (not null or empty // state event in there with the content of literally `{}` (not null or empty
// string), let's just skip it over and warn. // string), let's just skip it over and warn.
if pdu_builder.content.get().eq("{}") { if pdu_builder.content.get().eq("{}") {
info!("skipping empty initial state event with content of `{{}}`: {event:?}"); debug_warn!("skipping empty initial state event with content of `{{}}`: {event:?}");
debug_warn!("content: {}", pdu_builder.content.get()); debug_warn!("content: {}", pdu_builder.content.get());
continue; continue;
} }
@@ -540,9 +528,7 @@ fn default_power_levels_content(
if let Some(power_level_content_override) = power_level_content_override { if let Some(power_level_content_override) = power_level_content_override {
let json: JsonObject = serde_json::from_str(power_level_content_override.json().get()) let json: JsonObject = serde_json::from_str(power_level_content_override.json().get())
.map_err(|_| { .map_err(|e| err!(Request(BadJson("Invalid power_level_content_override: {e:?}"))))?;
Error::BadRequest(ErrorKind::BadJson, "Invalid power_level_content_override.")
})?;
for (key, value) in json { for (key, value) in json {
power_levels_content[key] = value; power_levels_content[key] = value;
@@ -560,16 +546,14 @@ async fn room_alias_check(
) -> Result<OwnedRoomAliasId> { ) -> Result<OwnedRoomAliasId> {
// Basic checks on the room alias validity // Basic checks on the room alias validity
if room_alias_name.contains(':') { if room_alias_name.contains(':') {
return Err(Error::BadRequest( return Err!(Request(InvalidParam(
ErrorKind::InvalidParam,
"Room alias contained `:` which is not allowed. Please note that this expects a \ "Room alias contained `:` which is not allowed. Please note that this expects a \
localpart, not the full room alias.", localpart, not the full room alias.",
)); )));
} else if room_alias_name.contains(char::is_whitespace) { } else if room_alias_name.contains(char::is_whitespace) {
return Err(Error::BadRequest( return Err!(Request(InvalidParam(
ErrorKind::InvalidParam,
"Room alias contained spaces which is not a valid room alias.", "Room alias contained spaces which is not a valid room alias.",
)); )));
} }
// check if room alias is forbidden // check if room alias is forbidden
@@ -578,7 +562,7 @@ async fn room_alias_check(
.forbidden_alias_names() .forbidden_alias_names()
.is_match(room_alias_name) .is_match(room_alias_name)
{ {
return Err(Error::BadRequest(ErrorKind::Unknown, "Room alias name is forbidden.")); return Err!(Request(Unknown("Room alias name is forbidden.")));
} }
let server_name = services.globals.server_name(); let server_name = services.globals.server_name();
@@ -598,25 +582,19 @@ async fn room_alias_check(
.await .await
.is_ok() .is_ok()
{ {
return Err(Error::BadRequest(ErrorKind::RoomInUse, "Room alias already exists.")); return Err!(Request(RoomInUse("Room alias already exists.")));
} }
if let Some(info) = appservice_info { if let Some(info) = appservice_info {
if !info.aliases.is_match(full_room_alias.as_str()) { if !info.aliases.is_match(full_room_alias.as_str()) {
return Err(Error::BadRequest( return Err!(Request(Exclusive("Room alias is not in namespace.")));
ErrorKind::Exclusive,
"Room alias is not in namespace.",
));
} }
} else if services } else if services
.appservice .appservice
.is_exclusive_alias(&full_room_alias) .is_exclusive_alias(&full_room_alias)
.await .await
{ {
return Err(Error::BadRequest( return Err!(Request(Exclusive("Room alias reserved by appservice.",)));
ErrorKind::Exclusive,
"Room alias reserved by appservice.",
));
} }
debug_info!("Full room alias: {full_room_alias}"); debug_info!("Full room alias: {full_room_alias}");
@@ -632,20 +610,18 @@ fn custom_room_id_check(services: &Services, custom_room_id: &str) -> Result<Own
.forbidden_alias_names() .forbidden_alias_names()
.is_match(custom_room_id) .is_match(custom_room_id)
{ {
return Err(Error::BadRequest(ErrorKind::Unknown, "Custom room ID is forbidden.")); return Err!(Request(Unknown("Custom room ID is forbidden.")));
} }
if custom_room_id.contains(':') { if custom_room_id.contains(':') {
return Err(Error::BadRequest( return Err!(Request(InvalidParam(
ErrorKind::InvalidParam,
"Custom room ID contained `:` which is not allowed. Please note that this expects a \ "Custom room ID contained `:` which is not allowed. Please note that this expects a \
localpart, not the full room ID.", localpart, not the full room ID.",
)); )));
} else if custom_room_id.contains(char::is_whitespace) { } else if custom_room_id.contains(char::is_whitespace) {
return Err(Error::BadRequest( return Err!(Request(InvalidParam(
ErrorKind::InvalidParam, "Custom room ID contained spaces which is not valid."
"Custom room ID contained spaces which is not valid.", )));
));
} }
let server_name = services.globals.server_name(); let server_name = services.globals.server_name();

View File

@@ -64,7 +64,7 @@ pub(crate) async fn create_invite_route(
} }
let mut signed_event = utils::to_canonical_object(&body.event) let mut signed_event = utils::to_canonical_object(&body.event)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invite event is invalid."))?; .map_err(|_| err!(Request(InvalidParam("Invite event is invalid."))))?;
let invited_user: OwnedUserId = signed_event let invited_user: OwnedUserId = signed_event
.get("state_key") .get("state_key")

View File

@@ -110,10 +110,9 @@ pub(super) async fn handle_outlier_pdu<'a>(
v.insert(auth_event); v.insert(auth_event);
}, },
| hash_map::Entry::Occupied(_) => { | hash_map::Entry::Occupied(_) => {
return Err(Error::BadRequest( return Err!(Request(InvalidParam(
ErrorKind::InvalidParam,
"Auth event's type and state_key combination exists multiple times.", "Auth event's type and state_key combination exists multiple times.",
)); )));
}, },
} }
} }