use std::io::{Read, Write};
use std::net::TcpListener;
use std::sync::mpsc;
mod common;
fn serve_capturing_ua(listener: TcpListener, tx: mpsc::Sender<String>) {
std::thread::spawn(move || {
if let Some(Ok(mut s)) = listener.incoming().next() {
let mut buf = [0u8; 4096];
let n = s.read(&mut buf).unwrap_or(0);
let req = String::from_utf8_lossy(&buf[..n]);
let ua = req
.lines()
.find(|l| l.to_ascii_lowercase().starts_with("user-agent:"))
.map(|l| l[l.find(':').unwrap() + 1..].trim().to_string())
.unwrap_or_default();
let _ = tx.send(ua);
let body = "<!doctype html><html><body>ok</body></html>";
let resp = format!(
"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
body.len(),
body
);
let _ = s.write_all(resp.as_bytes());
let _ = s.flush();
}
});
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn apply_stealth_keeps_ua_coherent_and_hides_webdriver() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
let (tx, rx) = mpsc::channel();
serve_capturing_ua(listener, tx);
let browser = common::launch_browser().await;
let page = browser.new_page("about:blank").await.unwrap();
captchaforge::apply_stealth(page).await.unwrap();
page.goto(&format!("http://{addr}/"))
.await
.expect("navigate");
let http_ua = rx
.recv_timeout(std::time::Duration::from_secs(10))
.expect("server captured a request User-Agent");
let js_ua: String = page
.evaluate("navigator.userAgent")
.await
.unwrap()
.into_value()
.unwrap();
eprintln!("[coherence] HTTP UA: {http_ua}");
eprintln!("[coherence] JS UA: {js_ua}");
assert!(!http_ua.is_empty(), "server must see a User-Agent header");
assert!(
js_ua.contains("Firefox/"),
"real Firefox UA expected, got {js_ua}"
);
assert_eq!(
http_ua, js_ua,
"max-coherence default must keep the HTTP User-Agent header IN SYNC with \
navigator.userAgent (no spoof-induced desync)"
);
let webdriver_ok: bool = page
.evaluate("navigator.webdriver === false || navigator.webdriver === undefined")
.await
.unwrap()
.into_value()
.unwrap();
assert!(webdriver_ok, "navigator.webdriver must be scrubbed");
browser.close().await.unwrap();
}