Skip to main content

paas_server/
errors.rs

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