use chrono::{DateTime, Duration, Utc};
use serde::{Deserialize, Serialize};
pub const CACHE_TTL: Duration = Duration::minutes(30);
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct Credential {
#[serde(default)]
pub token: String,
#[serde(default)]
pub expires_at: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub cached_at: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub provider: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub env: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub realm: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub identity: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub sub: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub account_type: String,
}
impl Credential {
#[must_use]
pub fn effective_expiry(&self) -> String {
if let Ok(cached_at) = DateTime::parse_from_rfc3339(&self.cached_at) {
return (cached_at.with_timezone(&Utc) + CACHE_TTL)
.to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
}
self.expires_at.clone()
}
#[must_use]
pub fn is_expired(&self) -> bool {
if let Ok(cached_at) = DateTime::parse_from_rfc3339(&self.cached_at) {
return Utc::now() > cached_at.with_timezone(&Utc) + CACHE_TTL;
}
if self.expires_at.is_empty() {
return false;
}
match DateTime::parse_from_rfc3339(&self.expires_at) {
Ok(expires_at) => Utc::now() > expires_at.with_timezone(&Utc),
Err(_) => true,
}
}
}