9a3b8a8
use std::fmt;
#[derive(Debug)]
pub enum UserError {
BadRequest(String),
Unauthorized,
Forbidden,
NotFound,
Conflict(String),
Internal(String),
}
impl fmt::Display for UserError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BadRequest(message) => write!(f, "{message}"),
Self::Unauthorized => write!(f, "unauthorized"),
Self::Forbidden => write!(f, "forbidden"),
Self::NotFound => write!(f, "not found"),
Self::Conflict(message) => write!(f, "{message}"),
Self::Internal(message) => write!(f, "{message}"),
}
}
}
impl std::error::Error for UserError {}
export::access_error_conversion!(UserError, BadRequest);
export::db_error_conversions!(UserError);
export::storage_error_conversion!(UserError);
export::redis_error_conversion!(UserError);
export::export_error_conversion!(UserError);
export::json_payload_conversion!(UserError);
export::api_error! {
log: "user",
pub enum ApiError {
BadRequest(400, "request failed validation"),
Unauthorized(401, "authentication required"),
Forbidden(403, "operation not allowed"),
NotFound(404, "resource not found"),
Conflict(409, "resource conflict"),
RateLimited(429, "rate limit exceeded"),
PreconditionFailed(412, "precondition failed"),
Unavailable(503, "service unavailable"),
Internal(500, "internal server error"),
}
}
impl From<UserError> for ApiError {
fn from(error: UserError) -> Self {
match error {
UserError::BadRequest(msg) => Self::bad_request(msg),
UserError::Unauthorized => Self::unauthorized(),
UserError::Forbidden => Self::forbidden(),
UserError::NotFound => Self::not_found("user resource not found"),
UserError::Conflict(msg) => Self::conflict(msg),
UserError::Internal(message) => Self::internal(message),
}
}
}
impl From<auth::AuthError> for ApiError {
fn from(error: auth::AuthError) -> Self {
let status = error.status_code().as_u16();
if error.is_internal() {
tracing::warn!(%error, "user SSH key handler failed");
}
let mut response = export::rest::AppResponseData::err(i32::from(status), error.message())
.with_error_code(error.code());
if let auth::AuthError::RateLimited { retry_after_secs } = &error {
response = response.with_retry_after(*retry_after_secs);
}
Self::build(status, response)
}
}