use std::sync::Arc;
use axum_extra::extract::PrivateCookieJar;
use super::session::{SessionResolution, SessionResolver};
use super::sv::adapter::{SvDriverPorts, drive};
use super::sv_cache::{MemorySvBackend, SvCachePort};
use super::traits::{SessionStore, SvAware};
use crate::pas_port::PasAuthPort;
use crate::session_liveness::TokenCipher;
use crate::types::SessionId;
pub struct SessionValidator<S, P, B = MemorySvBackend>
where
S: SessionStore,
P: PasAuthPort,
B: SvCachePort,
{
base: SessionResolver<S>,
store: Arc<S>,
pas: Arc<P>,
cache: Arc<B>,
cipher: Option<Arc<TokenCipher>>,
}
impl<S, P, B> Clone for SessionValidator<S, P, B>
where
S: SessionStore,
P: PasAuthPort,
B: SvCachePort,
{
fn clone(&self) -> Self {
Self {
base: self.base.clone(),
store: Arc::clone(&self.store),
pas: Arc::clone(&self.pas),
cache: Arc::clone(&self.cache),
cipher: self.cipher.as_ref().map(Arc::clone),
}
}
}
impl<S, P, B> SessionValidator<S, P, B>
where
S: SessionStore,
P: PasAuthPort,
B: SvCachePort,
{
pub fn new(
base: SessionResolver<S>,
store: Arc<S>,
pas: Arc<P>,
cache: Arc<B>,
cipher: Option<Arc<TokenCipher>>,
) -> Self {
Self { base, store, pas, cache, cipher }
}
pub async fn validate(
&self,
jar: &PrivateCookieJar,
) -> Result<SessionResolution<S::AuthContext>, S::Error> {
let resolution = self.base.resolve(jar).await?;
let session = match resolution {
SessionResolution::Authenticated(s) => s,
other => return Ok(other),
};
let Some(token_sv) = session.sv() else {
return Ok(SessionResolution::Authenticated(session));
};
let Some(cookie) = jar.get(self.base.cookie_name()) else {
return Ok(SessionResolution::Expired);
};
let session_id = SessionId(cookie.value().to_string());
let ppnum_id = session.ppnum_id().to_string();
let ports = SvDriverPorts {
store: &self.store,
pas: &self.pas,
cache: &self.cache,
cipher: self.cipher.as_ref().map(Arc::as_ref),
};
drive::<S, P, B>(ports, session_id, ppnum_id, token_sv, session).await
}
}