163952e
use std::fmt;
#[derive(Debug)]
pub enum AuthBusinessError {
BadRequest(String),
InvalidCredentials,
Unauthorized,
Forbidden,
NotFound,
Conflict(String),
RateLimited,
Internal(String),
TwoFactorExpired,
TwoFactorCodeInvalid,
RecoveryCodeInvalid,
VerificationCodeExpired,
VerificationCodeInvalid,
ResetTokenInvalid,
}
impl fmt::Display for AuthBusinessError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BadRequest(message) => write!(f, "{message}"),
Self::InvalidCredentials => write!(f, "invalid credentials"),
Self::Unauthorized => write!(f, "unauthorized"),
Self::Forbidden => write!(f, "forbidden"),
Self::NotFound => write!(f, "not found"),
Self::Conflict(message) => write!(f, "{message}"),
Self::RateLimited => write!(f, "rate limit exceeded"),
Self::Internal(message) => write!(f, "{message}"),
Self::TwoFactorExpired => write!(f, "two-factor challenge expired"),
Self::TwoFactorCodeInvalid => write!(f, "invalid two-factor code"),
Self::RecoveryCodeInvalid => write!(f, "invalid or used recovery code"),
Self::VerificationCodeExpired => write!(f, "verification code expired"),
Self::VerificationCodeInvalid => write!(f, "invalid verification code"),
Self::ResetTokenInvalid => write!(f, "invalid or expired reset token"),
}
}
}
impl std::error::Error for AuthBusinessError {}
impl From<deletion::DeletionError> for AuthBusinessError {
fn from(error: deletion::DeletionError) -> Self {
use deletion::DeletionError;
match error {
DeletionError::Database(error) => Self::from(error),
DeletionError::Conflict(message) => Self::Conflict(message),
DeletionError::NotFound(message) => {
tracing::debug!(%message, "deletion target not found");
Self::NotFound
}
DeletionError::KenAuth(message)
| DeletionError::KenShell(message)
| DeletionError::Config(message) => Self::Internal(message),
}
}
}
export::db_error_conversions!(AuthBusinessError);
export::redis_error_conversion!(AuthBusinessError);
export::export_error_conversion!(AuthBusinessError);
export::json_payload_conversion!(AuthBusinessError);
export::api_error! {
log: "auth",
pub enum ApiError {
BadRequest(400, "request failed validation"),
InvalidCredentials(400, "credentials rejected"),
Unauthorized(401, "authentication required"),
Forbidden(403, "operation not allowed"),
NotFound(404, "resource not found"),
Conflict(409, "resource conflict"),
RateLimited(429, "rate limit exceeded"),
Internal(500, "internal server error"),
}
}
impl From<AuthBusinessError> for ApiError {
fn from(error: AuthBusinessError) -> Self {
match error {
AuthBusinessError::BadRequest(msg) => Self::bad_request(msg),
AuthBusinessError::InvalidCredentials => {
Self::build(400, Self::payload(400, "invalid credentials"))
}
AuthBusinessError::Unauthorized => Self::unauthorized(),
AuthBusinessError::Forbidden => Self::forbidden(),
AuthBusinessError::NotFound => Self::not_found("auth resource not found"),
AuthBusinessError::Conflict(msg) => Self::conflict(msg),
AuthBusinessError::RateLimited => Self::rate_limited_exceeded(),
AuthBusinessError::TwoFactorExpired => Self::build(
400,
Self::payload(400, "two-factor challenge expired")
.with_error_code("two_factor_expired"),
),
AuthBusinessError::TwoFactorCodeInvalid => Self::build(
400,
Self::payload(400, "invalid two-factor code")
.with_error_code("two_factor_code_invalid"),
),
AuthBusinessError::RecoveryCodeInvalid => Self::build(
400,
Self::payload(400, "invalid or used recovery code")
.with_error_code("recovery_code_invalid"),
),
AuthBusinessError::VerificationCodeExpired => Self::build(
400,
Self::payload(400, "verification code expired")
.with_error_code("verification_code_expired"),
),
AuthBusinessError::VerificationCodeInvalid => Self::build(
400,
Self::payload(400, "invalid verification code")
.with_error_code("verification_code_invalid"),
),
AuthBusinessError::ResetTokenInvalid => Self::build(
400,
Self::payload(400, "invalid or expired reset token")
.with_error_code("reset_token_invalid"),
),
AuthBusinessError::Internal(message) => Self::internal(message),
}
}
}