torii_axum/
error.rs

1use axum::{
2    Json,
3    http::StatusCode,
4    response::{IntoResponse, Response},
5};
6use serde_json::json;
7use thiserror::Error;
8use torii::ToriiError;
9
10#[derive(Debug, Error)]
11pub enum AuthError {
12    #[error("Authentication failed: {0}")]
13    AuthenticationFailed(String),
14
15    #[error("Invalid credentials")]
16    InvalidCredentials,
17
18    #[error("User not found")]
19    UserNotFound,
20
21    #[error("Session not found")]
22    SessionNotFound,
23
24    #[error("Invalid session token")]
25    InvalidSession,
26
27    #[error("Email already registered")]
28    EmailAlreadyRegistered,
29
30    #[error("Invalid request: {0}")]
31    BadRequest(String),
32
33    #[error("Internal server error: {0}")]
34    InternalError(String),
35
36    #[error("Unauthorized")]
37    Unauthorized,
38
39    #[error("Feature not enabled: {0}")]
40    FeatureNotEnabled(String),
41}
42
43impl From<ToriiError> for AuthError {
44    fn from(err: ToriiError) -> Self {
45        match err {
46            ToriiError::AuthError(msg) => {
47                if msg.contains("already exists") || msg.contains("already registered") {
48                    AuthError::EmailAlreadyRegistered
49                } else if msg.contains("Invalid") || msg.contains("incorrect") {
50                    AuthError::InvalidCredentials
51                } else {
52                    AuthError::AuthenticationFailed(msg)
53                }
54            }
55            ToriiError::StorageError(msg) => {
56                if msg.contains("not found") {
57                    if msg.contains("User") {
58                        AuthError::UserNotFound
59                    } else if msg.contains("Session") {
60                        AuthError::SessionNotFound
61                    } else {
62                        AuthError::InternalError(msg)
63                    }
64                } else {
65                    AuthError::InternalError(msg)
66                }
67            }
68        }
69    }
70}
71
72impl IntoResponse for AuthError {
73    fn into_response(self) -> Response {
74        let (status, error_message) = match self {
75            AuthError::AuthenticationFailed(ref msg) => (StatusCode::UNAUTHORIZED, msg.as_str()),
76            AuthError::InvalidCredentials => (StatusCode::UNAUTHORIZED, "Invalid credentials"),
77            AuthError::UserNotFound => (StatusCode::NOT_FOUND, "User not found"),
78            AuthError::SessionNotFound => (StatusCode::NOT_FOUND, "Session not found"),
79            AuthError::InvalidSession => (StatusCode::UNAUTHORIZED, "Invalid session"),
80            AuthError::EmailAlreadyRegistered => (StatusCode::CONFLICT, "Email already registered"),
81            AuthError::BadRequest(ref msg) => (StatusCode::BAD_REQUEST, msg.as_str()),
82            AuthError::InternalError(ref msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg.as_str()),
83            AuthError::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized"),
84            AuthError::FeatureNotEnabled(ref feature) => {
85                (StatusCode::NOT_IMPLEMENTED, feature.as_str())
86            }
87        };
88
89        let body = Json(json!({
90            "error": error_message,
91            "code": status.as_u16()
92        }));
93
94        (status, body).into_response()
95    }
96}
97
98pub type Result<T> = std::result::Result<T, AuthError>;