use chrono::{DateTime, Utc};
use crate::device::store::SweepConfig;
use crate::device::types::{Device, DeviceTrustLevel};
pub(super) fn ttl_seconds(cfg: &SweepConfig, device: &Device, now: DateTime<Utc>) -> Option<i64> {
let expiry = match device.trust_level {
DeviceTrustLevel::Unknown => return None,
DeviceTrustLevel::Trusted => {
device.last_seen_at + cfg.trusted_idle + cfg.seen_idle + cfg.revoked_grace
}
DeviceTrustLevel::Seen => seen_clock(device) + cfg.seen_idle + cfg.revoked_grace,
DeviceTrustLevel::Revoked => device.revoked_at.unwrap_or(now) + cfg.revoked_grace,
};
Some(expiry.signed_duration_since(now).num_seconds().max(1))
}
fn seen_clock(device: &Device) -> DateTime<Utc> {
device
.demoted_at
.map_or(device.last_seen_at, |d| d.max(device.last_seen_at))
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) enum SweepStep {
Keep,
Demote {
level: DeviceTrustLevel,
trusted_to_seen: bool,
seen_to_revoked: bool,
},
Purge,
}
pub(super) fn plan_sweep(device: &Device, cfg: &SweepConfig, now: DateTime<Utc>) -> SweepStep {
if device.trust_level == DeviceTrustLevel::Revoked {
return match device.revoked_at {
Some(r) if now.signed_duration_since(r) > cfg.revoked_grace => SweepStep::Purge,
_ => SweepStep::Keep,
};
}
let next = cfg.level_after(
device.trust_level,
device.last_seen_at,
device.demoted_at,
now,
);
match (device.trust_level, next) {
(DeviceTrustLevel::Trusted, DeviceTrustLevel::Seen) => SweepStep::Demote {
level: DeviceTrustLevel::Seen,
trusted_to_seen: true,
seen_to_revoked: false,
},
(DeviceTrustLevel::Seen, DeviceTrustLevel::Revoked) => SweepStep::Demote {
level: DeviceTrustLevel::Revoked,
trusted_to_seen: false,
seen_to_revoked: true,
},
_ => SweepStep::Keep,
}
}