1use axum::http::StatusCode;
8use axum::response::{IntoResponse, Response};
9use serde::Serialize;
10
11use zvault_core::error::{AppRoleError, BarrierError, DatabaseError, EngineError, LeaseError, MountError, PkiError, PolicyError, SealError, TokenError};
12
13#[derive(Debug)]
15pub enum AppError {
16 Sealed,
18 Unauthorized(String),
20 Forbidden(String),
22 NotFound(String),
24 BadRequest(String),
26 Conflict(String),
28 Internal(String),
30}
31
32#[derive(Serialize)]
34struct ErrorBody {
35 error: &'static str,
36 message: String,
37}
38
39impl IntoResponse for AppError {
40 fn into_response(self) -> Response {
41 let (status, error_type, message) = match self {
42 Self::Sealed => (
43 StatusCode::SERVICE_UNAVAILABLE,
44 "sealed",
45 "vault is sealed".to_owned(),
46 ),
47 Self::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, "unauthorized", msg),
48 Self::Forbidden(msg) => (StatusCode::FORBIDDEN, "forbidden", msg),
49 Self::NotFound(msg) => (StatusCode::NOT_FOUND, "not_found", msg),
50 Self::BadRequest(msg) => (StatusCode::BAD_REQUEST, "bad_request", msg),
51 Self::Conflict(msg) => (StatusCode::CONFLICT, "conflict", msg),
52 Self::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, "internal_error", msg),
53 };
54
55 let body = ErrorBody {
56 error: error_type,
57 message,
58 };
59
60 (status, axum::Json(body)).into_response()
61 }
62}
63
64impl From<SealError> for AppError {
65 fn from(err: SealError) -> Self {
66 match err {
67 SealError::AlreadyInitialized
68 | SealError::AlreadyUnsealed
69 | SealError::AlreadySealed => Self::Conflict(err.to_string()),
70
71 SealError::NotInitialized
72 | SealError::InvalidConfig { .. }
73 | SealError::InvalidShare { .. }
74 | SealError::RecoveryFailed { .. }
75 | SealError::RootKeyDecryption { .. } => Self::BadRequest(err.to_string()),
76
77 SealError::Crypto(_) | SealError::Barrier(_) | SealError::Storage(_) => {
78 Self::Internal(err.to_string())
79 }
80 }
81 }
82}
83
84impl From<BarrierError> for AppError {
85 fn from(err: BarrierError) -> Self {
86 match err {
87 BarrierError::Sealed => Self::Sealed,
88 BarrierError::Crypto(_) | BarrierError::Storage(_) => Self::Internal(err.to_string()),
89 }
90 }
91}
92
93impl From<TokenError> for AppError {
94 fn from(err: TokenError) -> Self {
95 match err {
96 TokenError::NotFound => Self::Unauthorized("invalid token".to_owned()),
97 TokenError::Expired { .. } => Self::Unauthorized(err.to_string()),
98 TokenError::NotRenewable | TokenError::MaxTtlExceeded { .. } => {
99 Self::BadRequest(err.to_string())
100 }
101 TokenError::Barrier(ref inner) => match inner {
102 BarrierError::Sealed => Self::Sealed,
103 BarrierError::Crypto(_) | BarrierError::Storage(_) => {
104 Self::Internal(err.to_string())
105 }
106 },
107 }
108 }
109}
110
111impl From<PolicyError> for AppError {
112 fn from(err: PolicyError) -> Self {
113 match err {
114 PolicyError::NotFound { .. } => Self::NotFound(err.to_string()),
115 PolicyError::Invalid { .. } => Self::BadRequest(err.to_string()),
116 PolicyError::BuiltIn { .. } | PolicyError::Denied { .. } => {
117 Self::Forbidden(err.to_string())
118 }
119 PolicyError::Barrier(ref inner) => match inner {
120 BarrierError::Sealed => Self::Sealed,
121 BarrierError::Crypto(_) | BarrierError::Storage(_) => {
122 Self::Internal(err.to_string())
123 }
124 },
125 }
126 }
127}
128
129impl From<MountError> for AppError {
130 fn from(err: MountError) -> Self {
131 match err {
132 MountError::AlreadyMounted { .. } => Self::Conflict(err.to_string()),
133 MountError::NotFound { .. } => Self::NotFound(err.to_string()),
134 MountError::InvalidPath { .. } | MountError::UnknownEngineType { .. } => {
135 Self::BadRequest(err.to_string())
136 }
137 MountError::Barrier(ref inner) => match inner {
138 BarrierError::Sealed => Self::Sealed,
139 BarrierError::Crypto(_) | BarrierError::Storage(_) => {
140 Self::Internal(err.to_string())
141 }
142 },
143 }
144 }
145}
146
147impl From<EngineError> for AppError {
148 fn from(err: EngineError) -> Self {
149 match err {
150 EngineError::NotFound { .. } => Self::NotFound(err.to_string()),
151 EngineError::InvalidRequest { .. } => Self::BadRequest(err.to_string()),
152 EngineError::Barrier(ref inner) => match inner {
153 BarrierError::Sealed => Self::Sealed,
154 BarrierError::Crypto(_) | BarrierError::Storage(_) => {
155 Self::Internal(err.to_string())
156 }
157 },
158 EngineError::Internal { .. } => Self::Internal(err.to_string()),
159 }
160 }
161}
162
163impl From<LeaseError> for AppError {
164 fn from(err: LeaseError) -> Self {
165 match err {
166 LeaseError::NotFound { .. } => Self::NotFound(err.to_string()),
167 LeaseError::Expired { .. } | LeaseError::NotRenewable { .. } => {
168 Self::BadRequest(err.to_string())
169 }
170 LeaseError::Barrier(ref inner) => match inner {
171 BarrierError::Sealed => Self::Sealed,
172 BarrierError::Crypto(_) | BarrierError::Storage(_) => {
173 Self::Internal(err.to_string())
174 }
175 },
176 }
177 }
178}
179
180impl From<DatabaseError> for AppError {
181 fn from(err: DatabaseError) -> Self {
182 match err {
183 DatabaseError::NotFound { .. } | DatabaseError::RoleNotFound { .. } => {
184 Self::NotFound(err.to_string())
185 }
186 DatabaseError::InvalidConfig { .. } => Self::BadRequest(err.to_string()),
187 DatabaseError::Internal { .. } => Self::Internal(err.to_string()),
188 DatabaseError::Barrier(ref inner) => match inner {
189 BarrierError::Sealed => Self::Sealed,
190 BarrierError::Crypto(_) | BarrierError::Storage(_) => {
191 Self::Internal(err.to_string())
192 }
193 },
194 }
195 }
196}
197
198impl From<PkiError> for AppError {
199 fn from(err: PkiError) -> Self {
200 match err {
201 PkiError::NoRootCa => Self::NotFound(err.to_string()),
202 PkiError::RoleNotFound { .. } => Self::NotFound(err.to_string()),
203 PkiError::InvalidRequest { .. } => Self::BadRequest(err.to_string()),
204 PkiError::CertGeneration { .. } | PkiError::Internal { .. } => {
205 Self::Internal(err.to_string())
206 }
207 PkiError::Barrier(ref inner) => match inner {
208 BarrierError::Sealed => Self::Sealed,
209 BarrierError::Crypto(_) | BarrierError::Storage(_) => {
210 Self::Internal(err.to_string())
211 }
212 },
213 }
214 }
215}
216
217impl From<AppRoleError> for AppError {
218 fn from(err: AppRoleError) -> Self {
219 match err {
220 AppRoleError::RoleNotFound { .. } => Self::NotFound(err.to_string()),
221 AppRoleError::InvalidSecretId { .. } => {
222 Self::Unauthorized(err.to_string())
223 }
224 AppRoleError::InvalidConfig { .. } => Self::BadRequest(err.to_string()),
225 AppRoleError::Internal { .. } => Self::Internal(err.to_string()),
226 AppRoleError::Barrier(ref inner) => match inner {
227 BarrierError::Sealed => Self::Sealed,
228 BarrierError::Crypto(_) | BarrierError::Storage(_) => {
229 Self::Internal(err.to_string())
230 }
231 },
232 }
233 }
234}