use actix_web::{ body::BoxBody, http::{header, StatusCode}, HttpResponse, ResponseError, }; use serde::{ser::SerializeMap, Serialize, Serializer}; use std::{fmt, io}; use crate::util::{crypto, validate}; pub type Result = std::result::Result; #[derive(Debug)] pub enum Error { BadBearcap, BadCredentials, BadRequest, BadSignature, BadToken(jsonwebtoken::errors::Error), Crypto(crypto::Error), Database(sqlx::Error), Invalid(validate::Error), Io(io::Error), MalformedApub(String), MalformedHeader(header::ToStrError), NotFound, Reqwest(reqwest::Error), } impl ResponseError for Error { fn status_code(&self) -> StatusCode { match self { Error::BadBearcap => StatusCode::UNPROCESSABLE_ENTITY, Error::BadCredentials => StatusCode::UNAUTHORIZED, Error::BadRequest => StatusCode::BAD_REQUEST, Error::BadSignature => StatusCode::UNAUTHORIZED, Error::BadToken(_) => StatusCode::UNAUTHORIZED, Error::Invalid(_) => StatusCode::UNPROCESSABLE_ENTITY, Error::MalformedApub(_) => StatusCode::UNPROCESSABLE_ENTITY, Error::MalformedHeader(_) => StatusCode::BAD_REQUEST, Error::NotFound => StatusCode::NOT_FOUND, _ => StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { HttpResponse::build(self.status_code()).json(self) } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::BadBearcap => write!(f, "Invalid bearcap URL"), Error::BadCredentials => write!(f, "Invalid user name or password"), Error::BadRequest => write!(f, "Bad request"), Error::BadSignature => write!(f, "Bad signature"), Error::BadToken(jwt_error) => jwt_error.fmt(f), Error::Crypto(crypto_error) => crypto_error.fmt(f), Error::Database(sqlx_error) => sqlx_error.fmt(f), Error::Invalid(validate_error) => validate_error.fmt(f), Error::Io(io_error) => io_error.fmt(f), Error::NotFound => write!(f, "Not found"), Error::MalformedApub(msg) => write!(f, "Malformed ActivityPub: {msg}"), Error::MalformedHeader(to_str_error) => to_str_error.fmt(f), Error::Reqwest(reqwest_error) => reqwest_error.fmt(f), } } } impl From for Error { fn from(e: sqlx::Error) -> Error { match e { sqlx::Error::RowNotFound => Error::NotFound, _ => Error::Database(e), } } } impl From for Error { fn from(e: io::Error) -> Error { Error::Io(e) } } impl From for Error { fn from(e: validate::Error) -> Error { Error::Invalid(e) } } impl From for Error { fn from(e: header::ToStrError) -> Error { Error::MalformedHeader(e) } } impl From for Error { fn from(e: jsonwebtoken::errors::Error) -> Error { Error::BadToken(e) } } impl From for Error { fn from(e: reqwest::Error) -> Error { Error::Reqwest(e) } } impl From for Error { fn from(e: crypto::Error) -> Error { Error::Crypto(e) } } impl Serialize for Error { fn serialize(&self, serializer: S) -> std::result::Result where S: Serializer, { let mut fields = serializer.serialize_map(Some(1))?; fields.serialize_entry("msg", format!("{}", self).as_str())?; fields.end() } }