#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::todo)]
#![deny(clippy::unimplemented)]
#![deny(clippy::empty_loop)]
#![deny(clippy::indexing_slicing)]
#![deny(unused)]
#[cfg(feature = "axum")]
mod axum_support;
mod memory;
mod models;
#[cfg(feature = "redis")]
mod redis;
pub const TOKEN_COOKIE_NAME: &str = "r_token";
#[cfg(any(feature = "actix", feature = "axum"))]
#[derive(Clone, Debug)]
pub enum TokenSourcePriority {
HeaderFirst,
CookieFirst,
}
#[cfg(any(feature = "actix", feature = "axum"))]
#[derive(Clone, Debug)]
pub struct TokenSourceConfig {
pub priority: TokenSourcePriority,
pub header_names: Vec<String>,
pub cookie_names: Vec<String>,
}
#[cfg(any(feature = "actix", feature = "axum"))]
impl Default for TokenSourceConfig {
fn default() -> Self {
Self {
priority: TokenSourcePriority::HeaderFirst,
header_names: vec!["Authorization".to_string()],
cookie_names: vec![TOKEN_COOKIE_NAME.to_string()],
}
}
}
#[cfg(any(feature = "actix", feature = "axum"))]
pub(crate) fn extract_token_with_config(
cfg: &TokenSourceConfig,
mut header_value: impl FnMut(&str) -> Option<String>,
mut cookie_value: impl FnMut(&str) -> Option<String>,
) -> Option<String> {
let mut from_headers = || {
cfg.header_names.iter().find_map(|name| {
header_value(name).map(|token_str| {
token_str
.strip_prefix("Bearer ")
.unwrap_or(token_str.as_str())
.to_string()
})
})
};
let mut from_cookies = || cfg.cookie_names.iter().find_map(|name| cookie_value(name));
match cfg.priority {
TokenSourcePriority::HeaderFirst => from_headers().or_else(from_cookies),
TokenSourcePriority::CookieFirst => from_cookies().or_else(from_headers),
}
}
#[cfg(feature = "actix")]
pub fn extract_token_from_request(req: &actix_web::HttpRequest) -> Option<String> {
use actix_web::web;
if let Some(cfg) = req.app_data::<web::Data<TokenSourceConfig>>() {
extract_token_from_request_with_config(req, cfg.as_ref())
} else {
let default_cfg = TokenSourceConfig::default();
extract_token_from_request_with_config(req, &default_cfg)
}
}
#[cfg(feature = "actix")]
pub fn extract_token_from_request_with_config(
req: &actix_web::HttpRequest,
cfg: &TokenSourceConfig,
) -> Option<String> {
extract_token_with_config(
cfg,
|name| {
req.headers()
.get(name)
.and_then(|h| h.to_str().ok())
.map(|s| s.to_string())
},
|name| req.cookie(name).map(|cookie| cookie.value().to_string()),
)
}
pub use crate::memory::RTokenManager;
#[cfg(any(feature = "actix", feature = "axum"))]
pub use crate::memory::RUser;
pub use crate::models::RTokenError;
#[cfg(all(feature = "redis", any(feature = "actix", feature = "axum")))]
pub use crate::redis::RRedisUser;
#[cfg(feature = "redis")]
pub use crate::redis::RTokenRedisManager;