use std::time::{SystemTime, UNIX_EPOCH};
use base64::Engine;
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use hmac::{Hmac, Mac};
use sha2::Sha256;
use crate::errors::Error;
use crate::types_gen::DashboardUser;
type HmacSha256 = Hmac<Sha256>;
const DEFAULT_TTL_SECS: i64 = 10 * 60;
pub fn sign_dashboard_user(user: &DashboardUser, hmac_secret: &str) -> Result<String, Error> {
if hmac_secret.is_empty() {
return Err(Error::Key(
"dashboard HMAC secret is required to sign a dashboard user header".into(),
));
}
let mut user = user.clone();
user.exp = Some(unix_now() + DEFAULT_TTL_SECS);
let payload = serde_json::to_vec(&user)?;
let encoded = URL_SAFE_NO_PAD.encode(&payload);
let key = derive_hmac_key(hmac_secret)?;
let mut mac =
HmacSha256::new_from_slice(&key).map_err(|e| Error::Key(e.to_string()))?;
mac.update(encoded.as_bytes());
let sig = URL_SAFE_NO_PAD.encode(mac.finalize().into_bytes());
Ok(format!("{encoded}.{sig}"))
}
fn derive_hmac_key(secret: &str) -> Result<Vec<u8>, Error> {
let mut mac = HmacSha256::new_from_slice(secret.as_bytes())
.map_err(|e| Error::Key(e.to_string()))?;
mac.update(b"dashboard-user");
Ok(mac.finalize().into_bytes().to_vec())
}
fn unix_now() -> i64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs() as i64)
.unwrap_or(0)
}