paas_server/
errors.rs

1use actix_web::{http::StatusCode, HttpResponse, ResponseError};
2use log::{error, warn};
3use serde_json::json;
4use thiserror::Error;
5
6#[derive(Error, Debug)]
7pub enum PAASServerError {
8    #[error("User not authenticated")]
9    NotAuthenticated,
10
11    #[error("Could not start, end or retrieve session")]
12    SessionError(#[source] Box<dyn std::error::Error + Send + Sync>),
13
14    #[error("Invalid session format: {0}")]
15    InvalidSessionFormat(String),
16
17    #[error("Unknown or expired session: {0}")]
18    InvalidSession(String),
19
20    #[error("Unauthorized session access")]
21    UnauthorizedSession,
22
23    #[error("Access denied: not allowed to transcrypt from {from} to {to}")]
24    AccessDenied { from: String, to: String },
25}
26
27impl ResponseError for PAASServerError {
28    fn status_code(&self) -> StatusCode {
29        match &self {
30            Self::NotAuthenticated => StatusCode::UNAUTHORIZED,
31            Self::SessionError(_) => StatusCode::INTERNAL_SERVER_ERROR,
32            Self::InvalidSessionFormat(_) => StatusCode::BAD_REQUEST,
33            Self::InvalidSession(_) => StatusCode::NOT_FOUND,
34            Self::UnauthorizedSession => StatusCode::FORBIDDEN,
35            Self::AccessDenied { .. } => StatusCode::FORBIDDEN,
36        }
37    }
38
39    fn error_response(&self) -> HttpResponse {
40        let status = self.status_code();
41        let error_message = self.to_string();
42
43        match self {
44            Self::NotAuthenticated => {
45                warn!(
46                    "Authentication failure: status_code={}, error={}",
47                    status.as_u16(),
48                    error_message
49                );
50            }
51            Self::SessionError(source) => {
52                error!(
53                    "Session operation error: status_code={}, error={}, source={:?}",
54                    status.as_u16(),
55                    error_message,
56                    source
57                );
58            }
59            Self::InvalidSessionFormat(format) => {
60                warn!(
61                    "Invalid session format: status_code={}, error={}, format={}",
62                    status.as_u16(),
63                    error_message,
64                    format
65                );
66            }
67            Self::InvalidSession(session) => {
68                warn!(
69                    "Invalid session: status_code={}, error={}, session={}",
70                    status.as_u16(),
71                    error_message,
72                    session
73                );
74            }
75            Self::UnauthorizedSession => {
76                warn!(
77                    "Unauthorized session access: status_code={}, error={}",
78                    status.as_u16(),
79                    error_message
80                );
81            }
82            Self::AccessDenied { from, to } => {
83                warn!(
84                    "Access denied for transcryption: status_code={}, error={}, from={}, to={}",
85                    status.as_u16(),
86                    error_message,
87                    from,
88                    to
89                );
90            }
91        }
92
93        // For security, don't expose internal error details in production
94        let response_body = if status == StatusCode::INTERNAL_SERVER_ERROR {
95            json!({
96                "error": "An internal server error occurred"
97            })
98        } else {
99            json!({
100                "error": error_message
101            })
102        };
103
104        HttpResponse::build(status)
105            .content_type("application/json")
106            .json(response_body)
107    }
108}
109
110impl From<Box<dyn std::error::Error + Send + Sync>> for PAASServerError {
111    fn from(source: Box<dyn std::error::Error + Send + Sync>) -> Self {
112        error!(
113            "Converting generic error to PAASServerError: error={:?}",
114            source
115        );
116        PAASServerError::SessionError(source)
117    }
118}