//! API Key authentication middleware. //! //! Validates requests by checking for a valid API key in the X-API-Key header. use crate::{ Responder, middleware::{Middleware, MiddlewareFuture, MiddlewareResult}, }; use http::{Request, Response}; use hyper::body::{Bytes, Incoming}; use log::warn; /// Middleware that validates API key authentication via X-API-Key header. pub struct ApiKeyMiddleware { api_key: String, } impl ApiKeyMiddleware { /// Creates a new ApiKeyMiddleware with the specified expected API key. pub fn new(api_key: &str) -> Self { Self { api_key: api_key.to_string(), } } /// Checks if the given API key is invalid. pub fn is_invalid_key(&self, key: &str) -> bool { key != self.api_key } } impl Middleware for ApiKeyMiddleware { fn run(&self, req: Request) -> MiddlewareFuture<'_> { Box::pin(async move { match req.headers().get("X-API-Key") { Some(header) => { if header == self.api_key.as_str() { MiddlewareResult::Continue(req) } else { warn!("X-API-Key validation failed for request"); let response = Responder::unauthorized().unwrap_or_else(|_| { Response::builder() .status(http::StatusCode::UNAUTHORIZED) .body(http_body_util::Full::new(Bytes::from("Unauthorized"))) .expect("Failed to build fallback response") }); MiddlewareResult::Respond(response) } } None => { warn!("X-API-Key header missing from request"); let response = Responder::unauthorized().unwrap_or_else(|_| { Response::builder() .status(http::StatusCode::UNAUTHORIZED) .body(http_body_util::Full::new(Bytes::from("Unauthorized"))) .expect("Failed to build fallback response") }); MiddlewareResult::Respond(response) } } }) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_api_key_middleware_new() { let middleware = ApiKeyMiddleware::new("test-key"); assert!(!middleware.is_invalid_key("test-key")); assert!(middleware.is_invalid_key("wrong-key")); } }