1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
use crate::{IntoResponseError, Response};
use gotham::{hyper::StatusCode, mime::TEXT_PLAIN_UTF_8};
use gotham_restful_derive::ResourceError;
#[cfg(feature = "openapi")]
use openapi_type::{OpenapiSchema, OpenapiType};
/// This is an error type that always yields a _403 Forbidden_ response. This type
/// is best used in combination with [`AuthSuccess`] or [`AuthResult`].
#[derive(Clone, Debug)]
pub struct AuthError(String);
impl AuthError {
pub fn new<T: Into<String>>(msg: T) -> Self {
Self(msg.into())
}
}
impl IntoResponseError for AuthError {
// TODO why does this need to be serde_json::Error ?!?
type Err = serde_json::Error;
fn into_response_error(self) -> Result<Response, Self::Err> {
Ok(Response::new(
StatusCode::FORBIDDEN,
self.0,
Some(TEXT_PLAIN_UTF_8)
))
}
#[cfg(feature = "openapi")]
fn status_codes() -> Vec<StatusCode> {
vec![StatusCode::FORBIDDEN]
}
#[cfg(feature = "openapi")]
fn schema(code: StatusCode) -> OpenapiSchema {
assert_eq!(code, StatusCode::FORBIDDEN);
<super::Raw<String> as OpenapiType>::schema()
}
}
/// This return type can be used to wrap any type implementing [IntoResponse](crate::IntoResponse)
/// that can only be returned if the client is authenticated. Otherwise, an empty _403 Forbidden_
/// response will be issued.
///
/// Use can look something like this (assuming the `auth` feature is enabled):
///
/// ```rust
/// # #[macro_use] extern crate gotham_restful_derive;
/// # #[cfg(feature = "auth")]
/// # mod auth_feature_enabled {
/// # use gotham::state::State;
/// # use gotham_restful::*;
/// # use serde::Deserialize;
/// #
/// # #[derive(Resource)]
/// # #[resource(read_all)]
/// # struct MyResource;
/// #
/// # #[derive(Clone, Deserialize)]
/// # struct MyAuthData { exp : u64 }
/// #
/// #[read_all]
/// fn read_all(auth: AuthStatus<MyAuthData>) -> AuthSuccess<NoContent> {
/// let auth_data = auth.ok()?;
/// // do something
/// Ok(NoContent::default())
/// }
/// # }
/// ```
pub type AuthSuccess<T> = Result<T, AuthError>;
/// This is an error type that either yields a _403 Forbidden_ response if produced
/// from an authentication error, or delegates to another error type. This type is
/// best used with [`AuthResult`].
#[derive(Debug, Clone, ResourceError)]
pub enum AuthErrorOrOther<E> {
Forbidden(#[from] AuthError),
#[status(INTERNAL_SERVER_ERROR)]
#[display("{0}")]
Other(E)
}
mod private {
use gotham::handler::HandlerError;
pub trait Sealed {}
impl<E: Into<HandlerError>> Sealed for E {}
}
impl<E, F> From<F> for AuthErrorOrOther<E>
where
// TODO https://github.com/msrd0/gotham_restful/issues/20
F: private::Sealed + Into<E>
{
fn from(err: F) -> Self {
Self::Other(err.into())
}
}
/// This return type can be used to wrap any type implementing [IntoResponse](crate::IntoResponse)
/// that can only be returned if the client is authenticated. Otherwise, an empty _403 Forbidden_
/// response will be issued.
///
/// Use can look something like this (assuming the `auth` feature is enabled):
///
/// ```
/// # #[macro_use] extern crate gotham_restful_derive;
/// # #[cfg(feature = "auth")]
/// # mod auth_feature_enabled {
/// # use gotham::state::State;
/// # use gotham_restful::*;
/// # use serde::Deserialize;
/// # use std::io;
/// #
/// # #[derive(Resource)]
/// # #[resource(read_all)]
/// # struct MyResource;
/// #
/// # #[derive(Clone, Deserialize)]
/// # struct MyAuthData { exp : u64 }
/// #
/// #[read_all]
/// fn read_all(auth: AuthStatus<MyAuthData>) -> AuthResult<NoContent, io::Error> {
/// let auth_data = auth.ok()?;
/// // do something
/// Ok(NoContent::default().into())
/// }
/// # }
/// ```
pub type AuthResult<T, E> = Result<T, AuthErrorOrOther<E>>;