1use serde::Serialize;
2use sha2::{Digest, Sha256};
3
4pub fn redact(value: &str) -> String {
5 if value.is_empty() {
6 "<empty>".into()
7 } else {
8 "<redacted>".into()
9 }
10}
11
12#[derive(Debug, Serialize)]
13pub struct Finding {
14 pub variable: String,
15 pub kind: String,
16 pub message: String,
17}
18
19pub fn json<T: Serialize>(value: &T) -> anyhow::Result<String> {
20 Ok(serde_json::to_string_pretty(value)?)
21}
22
23pub fn fingerprint(pepper: &str, value: &str) -> String {
24 let mut key = [0u8; 64];
25 let pepper = pepper.as_bytes();
26 if pepper.len() > key.len() {
27 key[..32].copy_from_slice(&Sha256::digest(pepper));
28 } else {
29 key[..pepper.len()].copy_from_slice(pepper);
30 }
31 let mut inner = Sha256::new();
32 for byte in key {
33 inner.update([byte ^ 0x36]);
34 }
35 inner.update(value.as_bytes());
36 let inner = inner.finalize();
37 let mut outer = Sha256::new();
38 for byte in key {
39 outer.update([byte ^ 0x5c]);
40 }
41 outer.update(inner);
42 hex::encode(&outer.finalize()[..12])
43}
44
45#[derive(Debug, Serialize)]
46pub struct CheckEnvelope<T: Serialize> {
47 pub ok: bool,
48 pub exit: u8,
49 pub findings: T,
50}
51
52#[derive(Debug, Serialize)]
53pub struct DiffEnvelope<T: Serialize> {
54 pub ok: bool,
55 pub exit: u8,
56 pub variables: T,
57}