lan-party-backend/src/api/auth.rs

73 lines
2.3 KiB
Rust

use lazy_static::lazy_static;
use okapi::openapi3::{Object, SecurityRequirement, SecurityScheme, SecuritySchemeData};
use rocket::{
http::Status,
request::{self, FromRequest},
Request,
};
use rocket_okapi::{
gen::OpenApiGenerator,
request::{OpenApiFromRequest, RequestHeaderInput},
};
lazy_static! {
static ref API_KEYS: Vec<String> = {
serde_json::from_str(
&std::fs::read_to_string("api_keys.json").expect("api_keys.json does not exist"),
)
.expect("api_keys.json is not valid")
};
}
#[derive(Clone, Copy, Debug)]
pub struct ApiKey;
#[rocket::async_trait]
impl<'r> FromRequest<'r> for ApiKey {
type Error = ApiKey;
async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
if req
.headers()
.get("X-API-Key")
.any(|k| API_KEYS.contains(&String::from(k)))
{
request::Outcome::Success(ApiKey)
} else {
request::Outcome::Failure((Status::Unauthorized, ApiKey))
}
}
}
impl<'a> OpenApiFromRequest<'a> for ApiKey {
fn from_request_input(
_gen: &mut OpenApiGenerator,
_name: String,
_required: bool,
) -> rocket_okapi::Result<RequestHeaderInput> {
// Setup global requirement for Security scheme
let security_scheme = SecurityScheme {
description: Some("Requires an API key to access".to_owned()),
// Setup data requirements.
// This can be part of the `header`, `query` or `cookie`.
// In this case the header `x-api-key: mykey` needs to be set.
data: SecuritySchemeData::ApiKey {
name: "x-api-key".to_owned(),
location: "header".to_owned(),
},
extensions: Object::default(),
};
// Add the requirement for this route/endpoint
// This can change between routes.
let mut security_req = SecurityRequirement::new();
// Each security requirement needs to be met before access is allowed.
security_req.insert("ApiKeyAuth".to_owned(), Vec::new());
// These vvvvvvv-----^^^^^^^^^^ values need to match exactly!
Ok(RequestHeaderInput::Security(
"ApiKeyAuth".to_owned(),
security_scheme,
security_req,
))
}
}