use crate::{
calendar::{DateTime, Utc},
collection::Vector,
http::{
SessionError, SessionManager, SessionStore,
cookie::{SameSite, cookie_generic::CookieGeneric},
session::SessionManagerInner,
},
misc::{Secret, SecretContext, sleep},
rng::CryptoRng,
sync::{Arc, AsyncMutex},
};
use alloc::string::String;
use core::{marker::PhantomData, time::Duration};
#[derive(Debug)]
pub struct SessionManagerBuilder {
pub(crate) cookie_def: CookieGeneric<String, Vector<u8>>,
pub(crate) inspection_interval: Duration,
}
impl SessionManagerBuilder {
pub(crate) fn new() -> Self {
Self {
cookie_def: CookieGeneric {
domain: "".into(),
expires: None,
http_only: true,
max_age: None,
name: "id".try_into().unwrap_or_default(),
path: "/".into(),
same_site: Some(SameSite::Strict),
secure: true,
value: Vector::new(),
},
inspection_interval: Duration::from_secs(60 * 30),
}
}
#[inline]
pub fn build_generating_key<CS, E, RNG, SS>(
self,
rng: &mut RNG,
secret_context: SecretContext,
session_store: SS,
) -> crate::Result<(
impl Future<Output = Result<(), E>> + use<CS, E, RNG, SS>,
SessionManager<CS, E>,
)>
where
E: From<crate::Error>,
RNG: CryptoRng,
SS: Clone + SessionStore<CS, E>,
{
let mut session_secret = [0u8; 16];
rng.fill_slice(&mut session_secret);
Self::build_with_key(self, rng, secret_context, &mut session_secret, session_store)
}
#[inline]
pub fn build_with_key<CS, E, RNG, SS>(
self,
rng: &mut RNG,
secret_context: SecretContext,
session_secret: &mut [u8],
mut session_store: SS,
) -> crate::Result<(
impl Future<Output = Result<(), E>> + use<CS, E, RNG, SS>,
SessionManager<CS, E>,
)>
where
E: From<crate::Error>,
RNG: CryptoRng,
SS: SessionStore<CS, E>,
{
if session_secret.len() != 16 {
return Err(SessionError::InvalidSecretLength.into());
}
let Self { cookie_def, inspection_interval } = self;
Ok((
async move {
loop {
session_store.delete_expired().await?;
sleep(inspection_interval).await?;
}
},
SessionManager {
inner: Arc::new((
cookie_def.name,
AsyncMutex::new(SessionManagerInner {
cookie_def,
phantom: PhantomData,
session_secret: Secret::new(session_secret, rng, secret_context)?,
}),
)),
},
))
}
#[inline]
pub fn domain(mut self, elem: String) -> Self {
self.cookie_def.domain = elem;
self
}
#[inline]
pub const fn expires(mut self, elem: Option<DateTime<Utc>>) -> Self {
self.cookie_def.expires = elem;
self
}
#[inline]
pub const fn http_only(mut self, elem: bool) -> Self {
self.cookie_def.http_only = elem;
self
}
#[inline]
pub const fn inspection_interval(mut self, elem: Duration) -> Self {
self.inspection_interval = elem;
self
}
#[inline]
pub const fn max_age(mut self, elem: Option<Duration>) -> Self {
self.cookie_def.max_age = elem;
self
}
#[inline]
pub fn name(mut self, elem: &str) -> crate::Result<Self> {
self.cookie_def.name = elem.try_into()?;
Ok(self)
}
#[inline]
pub fn path(mut self, elem: String) -> Self {
self.cookie_def.path = elem;
self
}
#[inline]
pub const fn same_site(mut self, elem: Option<SameSite>) -> Self {
self.cookie_def.same_site = elem;
self
}
#[inline]
pub const fn secure(mut self, elem: bool) -> Self {
self.cookie_def.secure = elem;
self
}
}