Skip to main content

leyline/audit/
mod.rs

1#![forbid(unsafe_code)]
2mod ja3;
3mod ja4;
4mod ja4h;
5mod ja4t;
6
7pub use ja3::{Ja3Input, compute_ja3};
8pub use ja4::{Ja4Input, compute_ja4};
9pub use ja4h::{Ja4hInput, compute_ja4h};
10pub use ja4t::compute_ja4t;
11
12use sha2::{Digest, Sha256};
13
14use crate::iana::{cipher_id, curve_id, is_grease};
15
16fn non_grease_cipher_ids(ciphers: &[String]) -> Vec<u16> {
17    ciphers
18        .iter()
19        .filter_map(|c| cipher_id(c))
20        .filter(|id| !is_grease(*id))
21        .collect()
22}
23
24fn non_grease_ext_ids(extension_ids: &[u16]) -> Vec<u16> {
25    extension_ids
26        .iter()
27        .copied()
28        .filter(|id| !is_grease(*id))
29        .collect()
30}
31
32fn non_grease_curve_ids(curves: &[String]) -> Vec<u16> {
33    curves
34        .iter()
35        .filter_map(|c| curve_id(c))
36        .filter(|id| !is_grease(*id))
37        .collect()
38}
39
40fn hash12(s: &str) -> String {
41    if s.is_empty() {
42        "000000000000".to_owned()
43    } else {
44        let digest = Sha256::digest(s.as_bytes());
45        hex::encode(digest)[..12].to_owned()
46    }
47}
48
49#[derive(Debug, Clone)]
50#[non_exhaustive]
51pub struct AuditData {
52    pub ja4: String,
53    pub ja3: String,
54    pub h2_fingerprint: String,
55    pub ja4t: String,
56    pub ja4h: String,
57}
58
59#[derive(Debug, Clone)]
60pub(crate) struct AuditTlsCache {
61    pub(crate) ja4: String,
62    pub(crate) ja3: String,
63    pub(crate) h2_fingerprint: String,
64    pub(crate) ja4t: String,
65}