1use crate::tick::{Check, Tick};
7use serde_json::{json, Map, Value};
8use sha2::{Digest, Sha256};
9
10fn sorted_set(v: &[String]) -> Vec<String> {
11 let mut s: Vec<String> = v.to_vec();
12 s.sort(); s.dedup();
14 s
15}
16
17fn check_value(c: &Check) -> Value {
18 match c {
19 Check::Person { reference } => json!({ "by": "person", "ref": reference }),
20 Check::Test {
21 reference,
22 verified_at_sha,
23 counter_test,
24 liveness,
25 } => json!({
26 "by": "test",
27 "ref": reference,
28 "verified_at_sha": verified_at_sha,
29 "counter_test": counter_test,
30 "liveness": {
31 "platforms": sorted_set(&liveness.platforms),
32 "triggered_by": sorted_set(&liveness.triggered_by),
33 "surfaces": sorted_set(&liveness.surfaces),
34 }
35 }),
36 }
37}
38
39pub fn hashed_value(t: &Tick) -> Value {
41 let grounds: Vec<Value> = t
42 .grounds
43 .iter()
44 .map(|g| {
45 let mut o = Map::new();
48 o.insert("claim".into(), Value::String(g.claim.clone()));
49 o.insert("supports".into(), Value::String(g.supports.clone()));
50 if let Some(c) = &g.check {
51 o.insert("check".into(), check_value(c));
52 }
53 Value::Object(o)
54 })
55 .collect();
56 json!({
57 "decision": t.decision,
58 "observe": t.observe,
59 "grounds": grounds,
60 "parent_id": t.parent_id,
61 })
62}
63
64pub fn canonical_json(v: &Value) -> String {
69 serde_json::to_string(v).expect("Value is serializable")
70}
71
72pub fn compute_id(t: &Tick) -> String {
74 let canon = canonical_json(&hashed_value(t));
75 let full = hex::encode(Sha256::digest(canon.as_bytes()));
76 full[..12].to_string()
77}