use std::sync::Mutex;
use std::time::{Duration, Instant};
use serde_json::Value;
use crate::jwt::{Claims, sign_hs256};
const ISSUER: &str = "seamless-portal-api";
const AUDIENCE: &str = "seamless-auth";
const TTL: Duration = Duration::from_secs(60);
pub(crate) const PROXY_SUBJECT: &str = "seamless-auth-rust-adapter";
pub(crate) const DELIVERY_SUBJECT: &str = "seamless-auth-external-delivery";
const PROXY_REUSE: Duration = Duration::from_secs(45);
pub(crate) struct ServiceTokens {
secret: String,
kid: String,
proxy: Mutex<Option<(String, Instant)>>,
}
impl ServiceTokens {
pub fn new(secret: String, kid: String) -> Self {
ServiceTokens {
secret,
kid,
proxy: Mutex::new(None),
}
}
pub fn sign(&self, subject: &str, extra: Claims) -> Option<String> {
let mut claims = extra;
claims.insert("iss".into(), Value::from(ISSUER));
claims.insert("aud".into(), Value::from(AUDIENCE));
claims.insert("sub".into(), Value::from(subject));
sign_hs256(claims, &self.secret, TTL, Some(&self.kid))
.ok()
.map(|token| format!("Bearer {token}"))
}
pub fn proxy_authorization(&self) -> Option<String> {
let mut cached = self.proxy.lock().unwrap_or_else(|e| e.into_inner());
if let Some((token, until)) = cached.as_ref()
&& Instant::now() < *until
{
return Some(token.clone());
}
let token = self.sign(PROXY_SUBJECT, Claims::new())?;
*cached = Some((token.clone(), Instant::now() + PROXY_REUSE));
Some(token)
}
pub fn delivery_authorization(&self) -> Option<String> {
self.sign(DELIVERY_SUBJECT, Claims::new())
}
}