use std::{ future::{ready, Ready}, task::{Context, Poll}, }; use actix_web::{ dev::{Service, ServiceRequest, ServiceResponse, Transform}, web, Error, HttpMessage, }; use ovunto_security::client::JWT; use crate::app::state::{AppState, User}; #[doc(hidden)] pub struct AuthService { service: S, enabled: bool, } fn extract_user(req: &ServiceRequest) -> Option { if let Some(header) = req.headers().get("Authentication") { let mut split = header.to_str().ok()?.split_ascii_whitespace(); let username = split.next()?.to_string(); let jwt = JWT(split.next()?.to_string()); let state: &web::Data = req.app_data()?; let users = state.users.lock().unwrap(); let user = users.get(&username)?; if let Ok(jwt_username) = jwt.verify(&user.public_key) { if username == jwt_username { return Some(user.clone()); } } } None } impl Service for AuthService where S: Service, Error = Error>, { type Response = ServiceResponse; type Error = Error; type Future = S::Future; fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { self.service.poll_ready(ctx) } fn call(&self, req: ServiceRequest) -> Self::Future { if self.enabled { if let Some(user) = extract_user(&req) { req.extensions_mut().insert(user); } } self.service.call(req) } } #[derive(Clone, Debug)] pub struct Auth { enabled: bool, } impl Auth { pub fn enabled() -> Self { Self { enabled: true } } pub fn _disabled() -> Self { Self { enabled: false } } } impl Transform for Auth where S: Service, Error = Error>, { type Response = ServiceResponse; type Error = Error; type Transform = AuthService; type InitError = (); type Future = Ready>; fn new_transform(&self, service: S) -> Self::Future { ready(Ok(AuthService { service, enabled: self.enabled, })) } }