use crate::{Report, Scanner, ScannerImpl};
use chrono::{DateTime, TimeDelta, Utc};
use web_time::Duration;
impl<S: ScannerImpl> Scanner<S> {
pub(crate) fn evaluate_policy(
&self,
mut report: Report,
current_time: DateTime<Utc>,
) -> Report {
let num_expected_scts = match report.not_after - report.not_before {
time if time <= TimeDelta::days(180) => 2,
_ => 3,
};
let num_scts_from_known_logs = report
.scts
.iter()
.filter(|sct| sct.signature_validation_time.is_some())
.count();
if num_scts_from_known_logs < num_expected_scts {
return report.error_description(format!(
"Insufficient number of SCTs from known logs. Expected {} but got {}",
num_expected_scts, num_scts_from_known_logs
));
}
let mut fresh_inclusion_proofs = 0;
let mut old_inclusion_proofs = 0;
for sct in report.scts.iter_mut() {
if sct.error_description.is_some() {
continue;
}
let Some(latest_sth) = &sct.latest_sth else {
sct.set_error_description("Could not find a fresh STH for this SCT".to_string());
continue;
};
if latest_sth.verification_time
< current_time - time_delta_from_duration(self.config.sth_freshness_threshold)
{
sct.set_error_description(
"This logs latest STH is too old and the log is considered stale".to_string(),
);
continue;
}
let Some(inclusion_proof) = &sct.inclusion_proof else {
continue;
};
if inclusion_proof.verification_time
< current_time - time_delta_from_duration(self.config.sth_freshness_threshold)
{
old_inclusion_proofs += 1;
} else {
fresh_inclusion_proofs += 1;
}
}
if old_inclusion_proofs == 0 && fresh_inclusion_proofs < num_expected_scts {
return report.error_description(
"Insufficient number of inclusion proofs with fresh sths could be verified!"
.to_string(),
);
}
report
}
}
fn time_delta_from_duration(duration: Duration) -> TimeDelta {
TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos())
.expect("Failed to translate duration into timedelta")
}