Files
wehub-resource-sync 0af812490d
CI / python (push) Failing after 0s
CI / javascript (push) Failing after 1s
CI / dotnet (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:12:36 +08:00

230 lines
8.2 KiB
Python

"""Test against fingerprint-scan.com and CreepJS.
Tests the specific headless detection signals flagged by the community:
- noTaskbar, noContentIndex, noContactsManager, noDownlinkMax
- Bot risk score (fingerprint-scan.com)
- Headless/stealth percentages (CreepJS)
- Full CreepJS signal breakdown (likeHeadless, headless, stealth)
Usage:
python examples/fingerprint_scan_test.py
python examples/fingerprint_scan_test.py --proxy http://10.50.96.5:8888
python examples/fingerprint_scan_test.py --headless
"""
import sys
import time
from cloakbrowser import launch_context
HEADLESS = "--headless" in sys.argv
PROXY = None
for i, arg in enumerate(sys.argv):
if arg == "--proxy" and i + 1 < len(sys.argv):
PROXY = sys.argv[i + 1]
def test_fingerprint_scan(page):
"""fingerprint-scan.com — bot risk score + headless detection signals."""
print("=== fingerprint-scan.com ===")
page.goto("https://fingerprint-scan.com/", wait_until="domcontentloaded", timeout=30000)
time.sleep(20) # Castle.js needs time to compute score
# Check bot risk score
score = page.evaluate(
'document.getElementById("fingerprintScore")?.textContent || "Score not rendered"'
)
print(f"Bot Risk Score: {score}")
# Check headless detection signals
apis = page.evaluate("""() => ({
noTaskbar: screen.height === screen.availHeight,
taskbarSize: screen.height - screen.availHeight,
noContentIndex: typeof window.ContentIndex === "undefined",
noContactsManager: !("contacts" in navigator),
noDownlinkMax: !("downlinkMax" in (navigator.connection || {})),
downlinkMax: navigator.connection?.downlinkMax ?? null,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
webdriver: navigator.webdriver,
isPlaywright: "__pwInitScripts" in window || "__playwright__binding__" in window,
webgpu: typeof navigator.gpu !== "undefined" ? "available" : "NOT_AVAILABLE",
scrollbarWidth: (() => { const d = document.createElement("div"); d.style.cssText = "overflow:scroll;width:100px;height:100px;position:absolute;top:-999px"; document.body.appendChild(d); const w = d.offsetWidth - d.clientWidth; d.remove(); return w; })()
})""")
print("\nHeadless detection signals:")
headless_fails = 0
for k, v in apis.items():
is_fail = k.startswith("no") and v is True
if is_fail:
headless_fails += 1
flag = "FAIL" if is_fail else ""
print(f" {k}: {v} {flag}")
# Extract bot test results from page
bot_tests = page.evaluate("""() => {
const text = document.body.innerText;
const tests = {};
for (const key of ['WebDriver', 'Is Selenium Chrome', 'CDP Check', 'Is Playwright']) {
const match = text.match(new RegExp(key + '\\\\s+(true|false)'));
if (match) tests[key] = match[1];
}
return tests;
}""")
print("\nBot Detection Tests:")
for k, v in bot_tests.items():
status = "PASS" if v == "false" else "FAIL"
print(f" {k}: {v} [{status}]")
page.screenshot(path="/results/fingerprint-scan.png", full_page=True)
print("\nScreenshot: /results/fingerprint-scan.png")
return {
"score": score,
"headless_fails": headless_fails,
"apis": apis,
"bot_tests": bot_tests,
}
def test_creepjs(page):
"""abrahamjuliot.github.io/creepjs — comprehensive fingerprint analysis."""
print("\n=== CreepJS ===")
page.goto(
"https://abrahamjuliot.github.io/creepjs/", wait_until="domcontentloaded", timeout=30000
)
print("Waiting 30s for CreepJS analysis...")
time.sleep(30)
# Extract % scores from page text (matches test-infra/matrix_tests/group3_bot_detection.py)
scores = page.evaluate("""() => {
const text = document.body.innerText;
const likeMatch = text.match(/(\\d+)%\\s*like headless/i);
const headlessMatch = text.match(/(\\d+)%\\s*headless:/i);
const stealthMatch = text.match(/(\\d+)%\\s*stealth:/i);
return {
likeHeadlessPct: likeMatch ? parseInt(likeMatch[1]) : null,
headlessPct: headlessMatch ? parseInt(headlessMatch[1]) : null,
stealthPct: stealthMatch ? parseInt(stealthMatch[1]) : null,
};
}""")
print(f"\nScores:")
print(f" like-headless: {scores['likeHeadlessPct']}% (target: <=30%)")
print(f" headless: {scores['headlessPct']}% (target: 0%)")
print(f" stealth: {scores['stealthPct']}% (target: 0%)")
# Extract full signal breakdown from window.Fingerprint.headless (CreepJS internal object)
signals = page.evaluate("""() => {
try {
const fp = window.Fingerprint;
if (!fp || !fp.headless) return null;
return {
likeHeadless: fp.headless.likeHeadless || null,
headless: fp.headless.headless || null,
stealth: fp.headless.stealth || null,
};
} catch { return null; }
}""")
if signals:
if signals.get("likeHeadless"):
print("\nlikeHeadless signals:")
fails = 0
for k, v in signals["likeHeadless"].items():
is_fail = v is True
if is_fail:
fails += 1
flag = " FAIL" if is_fail else ""
print(f" {k}: {v}{flag}")
print(f" ({fails} fails)")
if signals.get("headless"):
print("\nheadless signals:")
for k, v in signals["headless"].items():
flag = " FAIL" if v is True else ""
print(f" {k}: {v}{flag}")
if signals.get("stealth"):
print("\nstealth signals:")
for k, v in signals["stealth"].items():
flag = " FAIL" if v is True else ""
print(f" {k}: {v}{flag}")
else:
print("\n(window.Fingerprint.headless not available — signals not extracted)")
# Extract platform estimate
platform = page.evaluate("""() => {
try {
const fp = window.Fingerprint;
if (!fp || !fp.platformEstimate) return null;
return fp.platformEstimate;
} catch { return null; }
}""")
if platform:
print(f"\nPlatform estimate: {platform}")
passed = (
scores["headlessPct"] is not None
and scores["headlessPct"] <= 30
and scores["stealthPct"] is not None
and scores["stealthPct"] <= 30
)
print(f"\nVerdict: {'PASS' if passed else 'FAIL'} (<=30% headless, <=30% stealth)")
page.screenshot(path="/results/creepjs.png", full_page=True)
print("Screenshot: /results/creepjs.png")
return {**scores, "signals": signals, "platform": platform}
def main():
print("=" * 60)
print("CloakBrowser — Fingerprint & Headless Detection Tests")
print("=" * 60)
print(f"Mode: {'headless' if HEADLESS else 'headed'}")
print(f"Proxy: {PROXY or 'none'}")
print()
print("Launching stealth browser...", flush=True)
context = launch_context(
headless=HEADLESS,
proxy=PROXY,
args=[
"--fingerprint-screen-width=1920",
"--fingerprint-screen-height=1080",
"--fingerprint-timezone=Asia/Jerusalem",
],
)
page = context.new_page()
try:
fp_result = test_fingerprint_scan(page)
creep_result = test_creepjs(page)
finally:
context.close()
# Summary
print("\n" + "=" * 60)
print("SUMMARY")
print("=" * 60)
print(f"fingerprint-scan.com: {fp_result['score']}")
print(f" Headless signal fails: {fp_result['headless_fails']}")
like = creep_result["likeHeadlessPct"]
headless = creep_result["headlessPct"]
stealth = creep_result["stealthPct"]
print(f"CreepJS: like-headless={like}%, headless={headless}%, stealth={stealth}%")
# Count CreepJS signal fails
sigs = creep_result.get("signals")
if sigs and sigs.get("likeHeadless"):
fail_names = [k for k, v in sigs["likeHeadless"].items() if v is True]
if fail_names:
print(f" likeHeadless fails: {', '.join(fail_names)}")
print("=" * 60)
return 0
if __name__ == "__main__":
sys.exit(main())