use std::sync::Arc;
use crate::auth::session::data::Session;
use crate::auth::session::store::SessionStore;
use crate::cookie::{Key, key_from_config};
use crate::db::Database;
use crate::{Error, Result};
use super::CookieSessionsConfig;
#[derive(Clone)]
pub struct CookieSessionService {
inner: Arc<Inner>,
}
struct Inner {
store: SessionStore,
config: CookieSessionsConfig,
cookie_key: Key,
}
impl CookieSessionService {
pub fn new(db: Database, config: CookieSessionsConfig) -> Result<Self> {
let cookie_key = key_from_config(&config.cookie)
.map_err(|e| Error::internal(format!("cookie key: {e}")))?;
let store = SessionStore::new(db, config.clone());
Ok(Self {
inner: Arc::new(Inner {
store,
config,
cookie_key,
}),
})
}
#[cfg(any(test, feature = "test-helpers"))]
pub fn store(&self) -> &SessionStore {
&self.inner.store
}
#[cfg(not(any(test, feature = "test-helpers")))]
pub(crate) fn store(&self) -> &SessionStore {
&self.inner.store
}
pub(crate) fn config(&self) -> &CookieSessionsConfig {
&self.inner.config
}
pub(crate) fn cookie_key(&self) -> &Key {
&self.inner.cookie_key
}
pub async fn list(&self, user_id: &str) -> Result<Vec<Session>> {
let raws = self.inner.store.list_for_user(user_id).await?;
Ok(raws.into_iter().map(Session::from).collect())
}
pub async fn revoke(&self, user_id: &str, id: &str) -> Result<()> {
let row = self.inner.store.read(id).await?.ok_or_else(|| {
Error::not_found("session not found").with_code("auth:session_not_found")
})?;
if row.user_id != user_id {
return Err(Error::not_found("session not found").with_code("auth:session_not_found"));
}
self.inner.store.destroy(id).await
}
pub async fn revoke_all(&self, user_id: &str) -> Result<()> {
self.inner.store.destroy_all_for_user(user_id).await
}
pub async fn revoke_all_except(&self, user_id: &str, keep_id: &str) -> Result<()> {
self.inner.store.destroy_all_except(user_id, keep_id).await
}
pub async fn cleanup_expired(&self) -> Result<u64> {
self.inner.store.cleanup_expired().await
}
pub fn layer(&self) -> super::middleware::CookieSessionLayer {
super::middleware::layer(self.clone())
}
}