feat(pr2): HTTP/2+HTTP/3 fingerprint extractors — JA4H, H2 SETTINGS, JA4-QUIC
This commit is contained in:
@@ -29,11 +29,12 @@ class TestExtractFpSummaries:
|
||||
|
||||
def test_empty_input_returns_all_none(self):
|
||||
result = extract_fp_summaries([])
|
||||
assert result == {
|
||||
"ja3_hashes": None,
|
||||
"hassh_hashes": None,
|
||||
"tls_cert_sha256": None,
|
||||
}
|
||||
assert all(v is None for v in result.values())
|
||||
assert "ja3_hashes" in result
|
||||
assert "hassh_hashes" in result
|
||||
assert "tls_cert_sha256" in result
|
||||
assert "ja4h_hashes" in result
|
||||
assert "ja4_quic_hashes" in result
|
||||
|
||||
def test_single_row_single_cert(self):
|
||||
row = _row_with(_bounty("tls_certificate", cert_sha256="ab" * 32))
|
||||
@@ -139,3 +140,50 @@ class TestExtractFpSummaries:
|
||||
assert json.loads(result["ja3_hashes"]) == sorted(
|
||||
["ja3-shared", "ja3-second", "ja3-third"]
|
||||
)
|
||||
|
||||
# ── ja4h + ja4_quic (PR2 columns) ────────────────────────────────
|
||||
|
||||
def test_ja4h_single_value(self):
|
||||
row = _row_with(_bounty("ja4h", ja4h="GE11nn0000_02_abc_000"))
|
||||
result = extract_fp_summaries([row])
|
||||
assert json.loads(result["ja4h_hashes"]) == ["GE11nn0000_02_abc_000"]
|
||||
|
||||
def test_ja4_quic_single_value(self):
|
||||
row = _row_with(_bounty("ja4_quic", ja4_quic="q13d0310h2_002f_0403_h3"))
|
||||
result = extract_fp_summaries([row])
|
||||
assert json.loads(result["ja4_quic_hashes"]) == ["q13d0310h2_002f_0403_h3"]
|
||||
|
||||
def test_ja4h_dedup_across_rows(self):
|
||||
a = _row_with(_bounty("ja4h", ja4h="GE11nn0000_02_abc_000"))
|
||||
b = _row_with(_bounty("ja4h", ja4h="GE11nn0000_02_abc_000"))
|
||||
c = _row_with(_bounty("ja4h", ja4h="GE20nn0000_04_def_000"))
|
||||
result = extract_fp_summaries([a, b, c])
|
||||
hashes = json.loads(result["ja4h_hashes"])
|
||||
assert len(hashes) == 2
|
||||
assert "GE11nn0000_02_abc_000" in hashes
|
||||
assert "GE20nn0000_04_def_000" in hashes
|
||||
|
||||
def test_ja4h_and_ja4_quic_coexist(self):
|
||||
row = _row_with(
|
||||
_bounty("ja4h", ja4h="GE11nn0000_02_abc_000"),
|
||||
_bounty("ja4_quic", ja4_quic="q13d0310h2_002f_0403_h3"),
|
||||
)
|
||||
result = extract_fp_summaries([row])
|
||||
assert json.loads(result["ja4h_hashes"]) == ["GE11nn0000_02_abc_000"]
|
||||
assert json.loads(result["ja4_quic_hashes"]) == ["q13d0310h2_002f_0403_h3"]
|
||||
|
||||
def test_ja4h_missing_payload_key_skipped(self):
|
||||
# bounty shaped like a fingerprint but missing the 'ja4h' key
|
||||
row = _row_with({
|
||||
"bounty_type": "fingerprint",
|
||||
"payload": {"fingerprint_type": "ja4h", "protocol": "h1"},
|
||||
})
|
||||
result = extract_fp_summaries([row])
|
||||
assert result["ja4h_hashes"] is None
|
||||
|
||||
def test_empty_returns_none_for_new_columns(self):
|
||||
result = extract_fp_summaries([])
|
||||
assert "ja4h_hashes" in result
|
||||
assert result["ja4h_hashes"] is None
|
||||
assert "ja4_quic_hashes" in result
|
||||
assert result["ja4_quic_hashes"] is None
|
||||
|
||||
Reference in New Issue
Block a user