use chrono::Duration;
use crate::pool::Pool;
#[cfg(feature = "mail")]
use crate::mail::Mailer;
#[cfg(feature = "_oauth-core")]
use crate::oauth::{OAuthProvider, OAuthRegistry};
#[cfg(feature = "ratelimit")]
#[derive(Debug, Clone)]
pub struct RateLimitConfig {
pub burst: u32,
pub per_second: u64,
}
#[cfg(feature = "ratelimit")]
impl Default for RateLimitConfig {
fn default() -> Self {
Self {
burst: 30,
per_second: 1,
}
}
}
#[derive(Debug, Clone)]
pub struct AuditConfig {
pub capture_ip: bool,
pub capture_user_agent: bool,
pub retention_days: u64,
}
impl Default for AuditConfig {
fn default() -> Self {
Self {
capture_ip: true,
capture_user_agent: true,
retention_days: 90,
}
}
}
#[derive(Clone)]
pub struct AuthConfig {
pub(crate) pool: Pool,
#[cfg(feature = "mail")]
pub(crate) mailer: Mailer,
#[cfg(feature = "_oauth-core")]
pub(crate) oauth: OAuthRegistry,
pub(crate) session_lifetime: Duration,
pub(crate) session_max_lifetime: Duration,
pub(crate) cookie_max_age: Duration,
#[cfg(feature = "ratelimit")]
pub(crate) rate_limit: Option<RateLimitConfig>,
pub(crate) session_table_name: String,
pub(crate) audit: AuditConfig,
pub(crate) hsts: Option<String>,
pub(crate) csp: Option<String>,
pub(crate) cookie_secure: bool,
pub(crate) resource_authority: Option<crate::authz::SharedResourceAuthority>,
}
pub const RECOMMENDED_HSTS: &str = "max-age=63072000; includeSubDomains; preload";
impl AuthConfig {
#[cfg(feature = "mail")]
pub fn builder(pool: Pool, mailer: Mailer) -> AuthConfigBuilder {
AuthConfigBuilder {
pool,
mailer,
#[cfg(feature = "_oauth-core")]
oauth: None,
session_lifetime: Duration::hours(2),
session_max_lifetime: Duration::days(30),
cookie_max_age: Duration::days(30),
#[cfg(feature = "ratelimit")]
rate_limit: Some(RateLimitConfig::default()),
session_table_name: "arium_sessions".to_string(),
audit: AuditConfig::default(),
hsts: None,
csp: None,
cookie_secure: false,
resource_authority: None,
}
}
#[cfg(not(feature = "mail"))]
pub fn builder(pool: Pool) -> AuthConfigBuilder {
AuthConfigBuilder {
pool,
#[cfg(feature = "_oauth-core")]
oauth: None,
session_lifetime: Duration::hours(2),
session_max_lifetime: Duration::days(30),
cookie_max_age: Duration::days(30),
#[cfg(feature = "ratelimit")]
rate_limit: Some(RateLimitConfig::default()),
session_table_name: "arium_sessions".to_string(),
audit: AuditConfig::default(),
hsts: None,
csp: None,
cookie_secure: false,
resource_authority: None,
}
}
}
pub struct AuthConfigBuilder {
pool: Pool,
#[cfg(feature = "mail")]
mailer: Mailer,
#[cfg(feature = "_oauth-core")]
oauth: Option<OAuthRegistry>,
session_lifetime: Duration,
session_max_lifetime: Duration,
cookie_max_age: Duration,
#[cfg(feature = "ratelimit")]
rate_limit: Option<RateLimitConfig>,
session_table_name: String,
audit: AuditConfig,
hsts: Option<String>,
csp: Option<String>,
cookie_secure: bool,
resource_authority: Option<crate::authz::SharedResourceAuthority>,
}
impl AuthConfigBuilder {
#[cfg(feature = "_oauth-core")]
pub fn oauth(mut self, registry: OAuthRegistry) -> Self {
self.oauth = Some(registry);
self
}
#[cfg(feature = "_oauth-core")]
pub fn oauth_provider<P: OAuthProvider>(mut self, provider: P) -> anyhow::Result<Self> {
let reg = match self.oauth.take() {
Some(r) => r,
None => OAuthRegistry::new(self.pool.clone())?,
};
self.oauth = Some(reg.with_provider(provider));
Ok(self)
}
pub fn session_lifetime(mut self, d: Duration) -> Self {
self.session_lifetime = d;
self
}
pub fn session_max_lifetime(mut self, d: Duration) -> Self {
self.session_max_lifetime = d;
self
}
pub fn cookie_max_age(mut self, d: Duration) -> Self {
self.cookie_max_age = d;
self
}
pub fn cookie_secure(mut self, secure: bool) -> Self {
self.cookie_secure = secure;
self
}
#[cfg(feature = "ratelimit")]
pub fn rate_limit(mut self, rl: Option<RateLimitConfig>) -> Self {
self.rate_limit = rl;
self
}
pub fn session_table_name(mut self, name: impl Into<String>) -> Self {
self.session_table_name = name.into();
self
}
pub fn audit(mut self, audit: AuditConfig) -> Self {
self.audit = audit;
self
}
pub fn resource_authority(mut self, authority: crate::authz::SharedResourceAuthority) -> Self {
self.resource_authority = Some(authority);
self
}
pub fn hsts(mut self, value: impl Into<String>) -> Self {
self.hsts = Some(value.into());
self
}
pub fn content_security_policy(mut self, value: impl Into<String>) -> Self {
self.csp = Some(value.into());
self
}
pub fn build(self) -> anyhow::Result<AuthConfig> {
#[cfg(feature = "_oauth-core")]
let oauth = match self.oauth {
Some(reg) => reg,
None => OAuthRegistry::new(self.pool.clone())?,
};
Ok(AuthConfig {
pool: self.pool,
#[cfg(feature = "mail")]
mailer: self.mailer,
#[cfg(feature = "_oauth-core")]
oauth,
session_lifetime: self.session_lifetime,
session_max_lifetime: self.session_max_lifetime,
cookie_max_age: self.cookie_max_age,
#[cfg(feature = "ratelimit")]
rate_limit: self.rate_limit,
session_table_name: self.session_table_name,
audit: self.audit,
hsts: self.hsts,
csp: self.csp,
cookie_secure: self.cookie_secure,
resource_authority: self.resource_authority,
})
}
}