1use axum::http::StatusCode;
2use axum::response::{IntoResponse, Response};
3use sha2::{Digest, Sha256};
4use thiserror::Error;
5
6pub type AuthResult<T> = Result<T, AuthError>;
7
8#[derive(Error, Debug)]
9pub enum AuthError {
10 #[error("The credentials were missing, or were insufficient to perform the operation requested")]
11 Unauthorized,
12 #[error("The client is not allowed to perform the operation requested")]
13 Forbidden,
14 #[error("The credentials supplied were invalid")]
15 InvalidCredentials,
16 #[error("This operation is not implemented")]
17 Unimplemented,
18 #[error("The requested crate does not exist")]
19 CrateNotFound,
20 #[error("Internal error ({})", error_id(_0))]
21 ServiceError(#[from] anyhow::Error),
22}
23
24impl IntoResponse for AuthError {
25 fn into_response(self) -> Response {
26 let code = match &self {
27 AuthError::Forbidden => StatusCode::FORBIDDEN,
28 AuthError::Unauthorized => StatusCode::UNAUTHORIZED,
29 AuthError::CrateNotFound => StatusCode::NOT_FOUND,
30 AuthError::InvalidCredentials => StatusCode::UNAUTHORIZED,
31 AuthError::Unimplemented => StatusCode::NOT_IMPLEMENTED,
32 AuthError::ServiceError(error) => {
33 tracing::error!(?error, "Encountered service error in auth operation");
34
35 StatusCode::INTERNAL_SERVER_ERROR
36 }
37 };
38 (code, self.to_string()).into_response()
39 }
40}
41
42fn error_id(err: &anyhow::Error) -> String {
45 let msg = err.to_string();
46 format!("{:.6x}", Sha256::digest(msg.as_bytes()))
47}