authifier 1.0.16

Opinionated Rust authentication library
Documentation
use revolt_okapi::openapi3::{self, SecurityScheme, SecuritySchemeData};
use revolt_rocket_okapi::{
    gen::OpenApiGenerator,
    request::{OpenApiFromRequest, RequestHeaderInput},
    response::OpenApiResponderInner,
};

use crate::{
    config::ShieldValidationInput,
    models::{Account, MFATicket, Session, UnvalidatedTicket, ValidatedTicket},
    Error,
};

impl OpenApiResponderInner for Error {
    fn responses(
        gen: &mut OpenApiGenerator,
    ) -> std::result::Result<openapi3::Responses, revolt_rocket_okapi::OpenApiError> {
        let mut content = revolt_okapi::Map::new();

        let settings = schemars::gen::SchemaSettings::default().with(|s| {
            s.option_nullable = true;
            s.option_add_null_type = false;
            s.definitions_path = "#/components/schemas/".to_string();
        });

        let mut schema_generator = settings.into_generator();
        let schema = schema_generator.root_schema_for::<Error>();

        let definitions = gen.schema_generator().definitions_mut();
        for (key, value) in schema.definitions {
            definitions.insert(key, value);
        }

        definitions.insert(
            "Authifier Error".to_string(),
            schemars::schema::Schema::Object(schema.schema),
        );

        content.insert(
            "application/json".to_string(),
            openapi3::MediaType {
                schema: Some(schemars::schema::SchemaObject {
                    reference: Some("#/components/schemas/Error".to_string()),
                    ..Default::default()
                }),
                ..Default::default()
            },
        );

        Ok(openapi3::Responses {
            default: Some(openapi3::RefOr::Object(openapi3::Response {
                content,
                description: "An error occurred.".to_string(),
                ..Default::default()
            })),
            ..Default::default()
        })
    }
}

impl<'r> OpenApiFromRequest<'r> for ShieldValidationInput {
    fn from_request_input(
        _gen: &mut OpenApiGenerator,
        _name: String,
        _required: bool,
    ) -> revolt_rocket_okapi::Result<RequestHeaderInput> {
        Ok(RequestHeaderInput::None)
    }
}

macro_rules! from_request {
    ($struct_name:ident, $name:expr, $header_name:expr, $description:expr) => {
        impl<'r> OpenApiFromRequest<'r> for $struct_name {
            fn from_request_input(
                _gen: &mut OpenApiGenerator,
                _name: String,
                _required: bool,
            ) -> revolt_rocket_okapi::Result<RequestHeaderInput> {
                let mut requirements = schemars::Map::new();
                requirements.insert($name.to_owned(), vec![]);

                Ok(RequestHeaderInput::Security(
                    $name.to_owned(),
                    SecurityScheme {
                        data: SecuritySchemeData::ApiKey {
                            name: $header_name.to_owned(),
                            location: "header".to_owned(),
                        },
                        description: Some($description.to_owned()),
                        extensions: schemars::Map::new(),
                    },
                    requirements,
                ))
            }
        }
    };
}

from_request!(
    Session,
    "Session Token",
    "x-session-token",
    "Used to authenticate as a user."
);

from_request!(
    Account,
    "Session Token",
    "x-session-token",
    "Used to authenticate as a user."
);

from_request!(
    MFATicket,
    "MFA Ticket",
    "x-mfa-ticket",
    "Used to authorise a request."
);

from_request!(
    ValidatedTicket,
    "Valid MFA Ticket",
    "x-mfa-ticket",
    "Used to authorise a request."
);

from_request!(
    UnvalidatedTicket,
    "Unvalidated MFA Ticket",
    "x-mfa-ticket",
    "Used to authorise a request."
);