1use clawser_browser::Browser;
4
5fn load_dotenv() {
6 for path in ["clawser-browser/.env", ".env"] {
7 if let Ok(content) = std::fs::read_to_string(path) {
8 for line in content.lines() {
9 let line = line.trim();
10 if line.is_empty() || line.starts_with('#') { continue; }
11 if let Some((k, v)) = line.split_once('=') {
12 std::env::set_var(k.trim(), v.trim());
13 }
14 }
15 break;
16 }
17 }
18}
19
20#[tokio::main]
21async fn main() {
22 load_dotenv();
23 println!("=== TLS/HTTP2 Fingerprint Check ===\n");
24
25 let browser = Browser::builder()
26 .headful()
27 .random()
28 .build()
29 .await
30 .expect("browser launch failed");
31
32 let page = browser.new_page("about:blank").await.expect("page failed");
33
34 println!("--- tls.peet.ws ---");
36 page.goto("https://tls.peet.ws/api/all").await.expect("nav failed");
37 tokio::time::sleep(std::time::Duration::from_secs(3)).await;
38
39 let body = page.js("document.body.innerText").await.unwrap_or_default();
40 if let Ok(v) = serde_json::from_str::<serde_json::Value>(&body) {
41 if let Some(tls) = v.get("tls") {
43 println!("JA3 hash: {}", tls.get("ja3_hash").and_then(|v| v.as_str()).unwrap_or("N/A"));
44 println!("JA3: {}", tls.get("ja3").and_then(|v| v.as_str()).unwrap_or("N/A"));
45 println!("JA4: {}", tls.get("ja4").and_then(|v| v.as_str()).unwrap_or("N/A"));
46 println!("TLS version: {}", tls.get("version").and_then(|v| v.as_str()).unwrap_or("N/A"));
47 }
48
49 println!();
51 if let Some(h2) = v.get("http2") {
52 println!("HTTP2 fingerprint: {}", h2.get("akamai_fingerprint").and_then(|v| v.as_str()).unwrap_or("N/A"));
53 println!("Pseudo-header order: {}", h2.get("sent_pseudo_header_fields_order").unwrap_or(&serde_json::Value::Null));
54 if let Some(settings) = h2.get("sent_settings") {
55 println!("SETTINGS: {}", settings);
56 }
57 }
58
59 println!();
61 if let Some(ip) = v.get("ip") {
62 println!("Client IP: {}", ip.as_str().unwrap_or("N/A"));
63 }
64 if let Some(http_version) = v.get("http_version") {
65 println!("HTTP version: {}", http_version.as_str().unwrap_or("N/A"));
66 }
67
68 println!();
70 if let Some(h1) = v.get("http1") {
71 if let Some(headers) = h1.get("headers") {
72 if let Some(arr) = headers.as_array() {
73 for h in arr {
74 let name = h.get("name").and_then(|n| n.as_str()).unwrap_or("");
75 let val = h.get("value").and_then(|n| n.as_str()).unwrap_or("");
76 if name.to_lowercase() == "user-agent" {
77 println!("User-Agent: {}", val);
78 }
79 }
80 }
81 }
82 }
83 } else {
84 println!("Failed to parse response: {}", &body[..body.len().min(500)]);
85 }
86
87 println!("\n--- Expected Chrome 134 stock values ---");
89 println!("JA3 hash: cd49876058a26ccf43e241ccc4e4b5d3 (Chrome 134 Windows)");
90 println!("JA4: t13d1517h2_8daaf6152771_02713d6af8 (Chrome 134 Windows)");
91 println!("HTTP2 Akamai: 1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p");
92
93 println!("\nBrowser still open. Press Ctrl+C to exit.");
94 loop {
95 tokio::time::sleep(std::time::Duration::from_secs(60)).await;
96 }
97}