You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
3.6 KiB
Rust

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<T> = std::result::Result<T, Error>;
#[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<BoxBody> {
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<sqlx::Error> for Error {
fn from(e: sqlx::Error) -> Error {
match e {
sqlx::Error::RowNotFound => Error::NotFound,
_ => Error::Database(e),
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Error {
Error::Io(e)
}
}
impl From<validate::Error> for Error {
fn from(e: validate::Error) -> Error {
Error::Invalid(e)
}
}
impl From<header::ToStrError> for Error {
fn from(e: header::ToStrError) -> Error {
Error::MalformedHeader(e)
}
}
impl From<jsonwebtoken::errors::Error> for Error {
fn from(e: jsonwebtoken::errors::Error) -> Error {
Error::BadToken(e)
}
}
impl From<reqwest::Error> for Error {
fn from(e: reqwest::Error) -> Error {
Error::Reqwest(e)
}
}
impl From<crypto::Error> for Error {
fn from(e: crypto::Error) -> Error {
Error::Crypto(e)
}
}
impl Serialize for Error {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut fields = serializer.serialize_map(Some(1))?;
fields.serialize_entry("msg", format!("{}", self).as_str())?;
fields.end()
}
}