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 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}