1#![deny(clippy::unwrap_used)]
2#![deny(clippy::expect_used)]
3#![deny(clippy::panic)]
4#![deny(clippy::todo)]
5#![deny(clippy::unimplemented)]
6#![deny(clippy::empty_loop)]
7#![deny(clippy::indexing_slicing)]
8#![deny(unused)]
9mod memory;
43mod models;
44#[cfg(feature = "redis")]
45mod redis;
46
47pub const TOKEN_COOKIE_NAME: &str = "r_token";
48
49#[cfg(feature = "actix")]
50#[derive(Clone, Debug)]
51pub enum TokenSourcePriority {
52 HeaderFirst,
53 CookieFirst,
54}
55
56#[cfg(feature = "actix")]
57#[derive(Clone, Debug)]
58pub struct TokenSourceConfig {
59 pub priority: TokenSourcePriority,
60 pub header_names: Vec<String>,
61 pub cookie_names: Vec<String>,
62}
63
64#[cfg(feature = "actix")]
65impl Default for TokenSourceConfig {
66 fn default() -> Self {
67 Self {
68 priority: TokenSourcePriority::HeaderFirst,
69 header_names: vec!["Authorization".to_string()],
70 cookie_names: vec![TOKEN_COOKIE_NAME.to_string(), "token".to_string()],
71 }
72 }
73}
74
75#[cfg(feature = "actix")]
76pub fn extract_token_from_request(req: &actix_web::HttpRequest) -> Option<String> {
77 use actix_web::web;
78
79 if let Some(cfg) = req.app_data::<web::Data<TokenSourceConfig>>() {
80 extract_token_from_request_with_config(req, cfg.as_ref())
81 } else {
82 let default_cfg = TokenSourceConfig::default();
83 extract_token_from_request_with_config(req, &default_cfg)
84 }
85}
86
87#[cfg(feature = "actix")]
88pub fn extract_token_from_request_with_config(
89 req: &actix_web::HttpRequest,
90 cfg: &TokenSourceConfig,
91) -> Option<String> {
92 let from_headers = || {
93 cfg.header_names.iter().find_map(|name| {
94 req.headers()
95 .get(name)
96 .and_then(|h| h.to_str().ok())
97 .map(|token_str| token_str.strip_prefix("Bearer ").unwrap_or(token_str).to_string())
98 })
99 };
100
101 let from_cookies = || {
102 cfg.cookie_names.iter().find_map(|name| {
103 req.cookie(name)
104 .map(|cookie| cookie.value().to_string())
105 })
106 };
107
108 match cfg.priority {
109 TokenSourcePriority::HeaderFirst => from_headers().or_else(from_cookies),
110 TokenSourcePriority::CookieFirst => from_cookies().or_else(from_headers),
111 }
112}
113
114pub use crate::memory::RTokenManager;
115#[cfg(feature = "actix")]
116pub use crate::memory::RUser;
117pub use crate::models::RTokenError;
118#[cfg(feature = "redis")]
119pub use crate::redis::RTokenRedisManager;
120#[cfg(all(feature = "redis", feature = "actix"))]
121pub use crate::redis::RRedisUser;