use super::funejson::Value; /// RFC 5280 makes validity inclusive of notAfter, so a certificate is expired /// only after that second, not at it. Thresholds compare whole days left with /// the day counts: fewer than N days (secondsLeft < N * 86400) is exactly /// floor(secondsLeft / 86400) < N, with no multiplication to overflow. /// /// # Panics /// Panics when critical_days is negative or warn_days is below critical_days. pub fn cert_expiry(not_after: i64, now: i64, warn_days: i64, critical_days: i64) -> CertExpiry { if critical_days < 0 { panic!("criticalDays must be a whole number 0 or more, received {}", critical_days); } if warn_days < critical_days { panic!("warnDays must be a whole number at least criticalDays ({}), received {}", critical_days, warn_days); } if now > not_after { return CertExpiry { state: "expired".to_string(), seconds_left: 0, days_left: 0 }; } let seconds_left = not_after - now; let days_left = seconds_left / 86400; let state = if days_left < critical_days { "critical" } else if days_left < warn_days { "warning" } else { "ok" }; CertExpiry { state: state.to_string(), seconds_left, days_left } } pub fn cert_expiry_to_value(c: &CertExpiry) -> Value { Value::obj(vec![ ("state", Value::str(&c.state)), ("secondsLeft", Value::Int(c.seconds_left)), ("daysLeft", Value::Int(c.days_left)), ]) } fn show(v: &Value) -> String { match v { Value::Int(i) => i.to_string(), Value::Float(f) => f.to_string(), _ => "a non-number".to_string(), } } pub fn fune_vector(args: &[Value]) -> Value { if !matches!(args[0], Value::Int(_)) || !matches!(args[1], Value::Int(_)) { panic!("notAfter and now must be whole seconds, received {} and {}", show(&args[0]), show(&args[1])); } let critical = match &args[3] { Value::Int(i) => *i, other => panic!("criticalDays must be a whole number 0 or more, received {}", show(other)), }; let warn = match &args[2] { Value::Int(i) => *i, other => panic!("warnDays must be a whole number at least criticalDays ({}), received {}", critical, show(other)), }; cert_expiry_to_value(&cert_expiry(args[0].as_i64(), args[1].as_i64(), warn, critical)) }