use crate::error::LsError;
use crate::service::auth::{Auth, AuthContext, LsAuthService};
use crate::service::jwt::LsJwtService;
use ::http::{HeaderMap, Request};
use log::*;
use std::sync::Arc;
#[cfg(feature = "axum")]
pub mod axum;
pub mod types;
pub const JWT_TOKEN_HEADER: &str = "Authorization";
pub const JWT_TOKEN_HEADER_SUFFIX: &str = "Bearer ";
pub const JWT_TOKEN_HEADER_SUFFIX_LEN: usize = JWT_TOKEN_HEADER_SUFFIX.len();
pub trait Headers {
fn get_as_str(&self, header_name: &str) -> Option<Result<&str, LsError>>;
}
impl Headers for HeaderMap {
fn get_as_str(&self, header_name: &str) -> Option<Result<&str, LsError>> {
self.get(header_name)
.map(|header| header.to_str().map_err(|err| LsError::ParseAuthHeaderError { message: format!("{err:?}") }))
}
}
impl<T> Headers for Request<T> {
fn get_as_str(&self, header_name: &str) -> Option<Result<&str, LsError>> {
self.headers().get_as_str(header_name)
}
}
#[derive(Clone)]
pub struct WebAuthService {
auth_service: Arc<LsAuthService>,
jwt_service: Arc<LsJwtService>,
}
impl WebAuthService {
pub fn new(auth_service: Arc<LsAuthService>, jwt_service: Arc<LsJwtService>) -> Self {
Self { auth_service, jwt_service }
}
pub fn token_string_from_request<'a, H: Headers>(&self, req: &'a H) -> Result<&'a str, LsError> {
if let Some(header) = req.get_as_str(JWT_TOKEN_HEADER) {
header.map_err(|err| LsError::ParseAuthHeaderError { message: format!("{err:?}") }).and_then(|header| {
trace!("Token found in request: [{header}]");
if header.len() > JWT_TOKEN_HEADER_SUFFIX_LEN {
Ok(&header[JWT_TOKEN_HEADER_SUFFIX_LEN..])
} else {
Err(LsError::ParseAuthHeaderError { message: format!("Unexpected auth header: {header}") })
}
})
} else {
Err(LsError::MissingAuthTokenError)
}
}
pub fn token_from_auth(&self, auth: &Auth) -> Result<String, LsError> {
Ok(self.jwt_service.generate_from_payload(auth)?.1)
}
pub fn auth_from_request<H: Headers>(&self, req: &H) -> Result<AuthContext<'_>, LsError> {
self.token_string_from_request(req).and_then(|token| self.auth_from_token_string(token))
}
pub fn auth_from_token_string(&self, token: &str) -> Result<AuthContext<'_>, LsError> {
let auth = self.jwt_service.parse_payload::<Auth>(token);
trace!("Auth built from request: [{auth:?}]");
Ok(self.auth_service.auth(auth?))
}
}