use crate::tick::{Check, Tick};
use serde_json::{json, Map, Value};
use sha2::{Digest, Sha256};
fn sorted_set(v: &[String]) -> Vec<String> {
let mut s: Vec<String> = v.to_vec();
s.sort(); s.dedup();
s
}
fn check_value(c: &Check) -> Value {
match c {
Check::Person { reference } => json!({ "by": "person", "ref": reference }),
Check::Test {
reference,
verified_at_sha,
counter_test,
liveness,
} => {
let mut o = Map::new();
o.insert("by".into(), Value::String("test".into()));
o.insert("ref".into(), Value::String(reference.clone()));
o.insert(
"verified_at_sha".into(),
Value::String(verified_at_sha.clone()),
);
if let Some(ct) = counter_test {
o.insert("counter_test".into(), Value::String(ct.clone()));
}
o.insert(
"liveness".into(),
json!({
"platforms": sorted_set(&liveness.platforms),
"triggered_by": sorted_set(&liveness.triggered_by),
"surfaces": sorted_set(&liveness.surfaces),
}),
);
Value::Object(o)
}
}
}
pub fn hashed_value(t: &Tick) -> Value {
let grounds: Vec<Value> = t
.grounds
.iter()
.map(|g| {
let mut o = Map::new();
o.insert("claim".into(), Value::String(g.claim.clone()));
o.insert("supports".into(), Value::String(g.supports.clone()));
if let Some(c) = &g.check {
o.insert("check".into(), check_value(c));
}
Value::Object(o)
})
.collect();
json!({
"decision": t.decision,
"observe": t.observe,
"grounds": grounds,
"parent_id": t.parent_id,
})
}
pub fn canonical_json(v: &Value) -> String {
serde_json::to_string(v).expect("Value is serializable")
}
pub fn compute_id(t: &Tick) -> String {
let canon = canonical_json(&hashed_value(t));
let full = hex::encode(Sha256::digest(canon.as_bytes()));
full[..12].to_string()
}