Compare commits

...
6 Commits
Author SHA1 Message Date
CloakHQ 23ae521832 docs: add headed mode guide, JS roadmap, bump to 0.1.5
- Add Headed Mode section for DataDome/Cloudflare Turnstile sites
- Add Xvfb setup instructions + residential proxy tip
- Add JavaScript/Puppeteer support to roadmap
2026-02-23 18:13:07 +01:00
CloakHQ c2eb0ef21a feat: stealth hardening + test suite rewrite, bump to 0.1.4
- Remove --enable-automation via ignore_default_args (matches agent-browser
  Playwright patch — fixes connectionRTT, enables --fingerprint-* flags)
- Randomize fingerprint seed per launch (unique canvas/WebGL/audio per session)
- Change default GPU to RTX 3070 (higher market share = better blending)
- Rewrite stealth_test.py with JS evaluation for 6 detection sites
- Add --proxy flag to test script for Helper VPS routing
- All 6/6 tests passing (verified on VPS with v142 binary)
2026-02-23 07:58:50 +01:00
CloakHQ 2d7894ad68 docs: add Docker section to README, expand Dockerfile deps, bump to 0.1.3 2026-02-23 07:16:02 +01:00
CloakHQ efab732142 fix: use absolute image URLs for PyPI, bump to 0.1.2
PyPI doesn't render relative image paths — switched to raw GitHub URLs.
Also updated pyproject.toml metadata (author, URLs).
2026-02-23 02:53:36 +01:00
CloakHQ 924f401265 docs: improve README for launch — logo, scannable bullets, roadmap, troubleshooting
- Add cloaked Chrome logo as hero banner
- Replace dense blockquote intro with 6 emoji feature bullets
- Move reCAPTCHA proof image above the fold
- Tighten "Why CloakBrowser?" to 3 bullet points
- Add 3 badges (stars, downloads, last commit)
- Add Roadmap section with star CTA
- Add Troubleshooting section (4 common issues)
- Fix version references from 145 to 142
2026-02-22 23:32:02 +01:00
Durafen 6ea8391fac docs: add reCAPTCHA v3 score 0.9 screenshot to README 2026-02-22 20:19:27 +01:00
12 changed files with 381 additions and 72 deletions
+4
View File
@@ -45,3 +45,7 @@ AGENTS.md
# Private docs (launch posts, strategy)
docs/
# Release scripts
publish.sh
.env
+5 -2
View File
@@ -1,11 +1,14 @@
FROM python:3.12-slim
# Playwright system deps
# Chromium system deps (matches fingerprint-chromium 142+ requirements)
RUN apt-get update && apt-get install -y --no-install-recommends \
libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 \
libdbus-1-3 libdrm2 libxkbcommon0 libatspi2.0-0 libxcomposite1 \
libxdamage1 libxfixes3 libxrandr2 libgbm1 libpango-1.0-0 \
libcairo2 libasound2 libx11-xcb1 \
libcairo2 libasound2 libx11-xcb1 libfontconfig1 libx11-6 \
libxcb1 libxext6 libxshmfence1 \
libglib2.0-0 libgtk-3-0 libpangocairo-1.0-0 libcairo-gobject2 \
libgdk-pixbuf-2.0-0 libxss1 libxtst6 fonts-liberation \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
+106 -23
View File
@@ -1,24 +1,25 @@
<p align="center">
<img src="https://raw.githubusercontent.com/CloakHQ/CloakBrowser/main/images/logo.png" width="500" alt="CloakBrowser">
</p>
# CloakBrowser
[![PyPI](https://img.shields.io/pypi/v/cloakbrowser)](https://pypi.org/project/cloakbrowser/)
[![Python](https://img.shields.io/pypi/pyversions/cloakbrowser)](https://pypi.org/project/cloakbrowser/)
[![License](https://img.shields.io/github/license/CloakHQ/CloakBrowser)](LICENSE)
[![Stars](https://img.shields.io/github/stars/CloakHQ/CloakBrowser)](https://github.com/CloakHQ/CloakBrowser)
[![Last Commit](https://img.shields.io/github/last-commit/CloakHQ/CloakBrowser)](https://github.com/CloakHQ/CloakBrowser)
**Stealth Chromium that passes every bot detection test.**
Drop-in Playwright replacement. Same API, same code — just swap the import. Your browser now scores **0.9 on reCAPTCHA v3**, passes **Cloudflare Turnstile**, and clears **14 out of 14** stealth detection tests.
> CloakBrowser is an open-source Python library that gives you an undetectable browser for web automation and data collection. It wraps a custom-built Chromium binary with 16 source-level fingerprint patches — modifications compiled directly into the browser's C++ code, not bolted on via JavaScript injection or config flags.
>
> Most stealth tools (playwright-stealth, undetected-chromedriver, puppeteer-extra) work at the config level: they override JavaScript properties, set browser flags, or inject scripts to mask automation signals. These approaches break every time Chrome updates its detection surface — and Cloudflare, reCAPTCHA, and other bot detection systems update constantly.
>
> CloakBrowser takes a fundamentally different approach. The fingerprint patches modify Chromium's rendering pipeline at the source level: canvas output, WebGL renderer strings, audio processing fingerprints, font enumeration, hardware concurrency, client rectangles, GPU info, timezone handling, and the WebDriver flag are all patched in C++ before compilation. The resulting binary produces fingerprints indistinguishable from a real user's Chrome installation. TLS fingerprints (ja3n, ja4, akamai hash) match genuine Chrome exactly because the browser IS Chrome — just with different fingerprint values compiled in.
>
> The result: a 0.9 score on Google's reCAPTCHA v3 (human-level, versus 0.1 for stock Playwright), clean passes on Cloudflare Turnstile managed challenges, zero bot flags on FingerprintJS, BrowserScan, and deviceandbrowserinfo.com, and undetected CDP (Chrome DevTools Protocol) usage. 14 out of 14 major detection tests passed.
>
> CloakBrowser fills the vacuum left by Camoufox (the popular Firefox-based stealth browser whose maintainer stepped down in 2025). Unlike Camoufox, CloakBrowser is Chromium-based — meaning native Playwright API support, a massive ecosystem of existing tools and scripts, and TLS fingerprints that match the browser 65%+ of the internet actually uses.
>
> Install with pip, write standard Playwright code, and let the binary handle the stealth. No new API to learn. No configuration to tune. No CAPTCHA-solving services to pay for. Just a browser that works on sites where others get blocked.
- 🔒 **16 source-level C++ patches** — not JS injection, not config flags
- 🎯 **0.9 reCAPTCHA v3 score** — human-level, server-verified
- ☁️ **Passes Cloudflare Turnstile**, FingerprintJS, BrowserScan — 14/14 tests
- 🔄 **Drop-in Playwright replacement** — same API, swap one import
- 📦 **`pip install cloakbrowser`** — binary auto-downloads, zero config
- 🦊 **Fills the Camoufox vacuum** — Chromium-based, actively maintained
```python
from cloakbrowser import launch
@@ -39,15 +40,13 @@ On first run, the stealth Chromium binary is automatically downloaded (~200MB, c
## Why CloakBrowser?
Every bot detection system — reCAPTCHA, Cloudflare Turnstile, ShieldSquare, FingerprintJS — identifies automation browsers through **browser fingerprinting**: canvas rendering, WebGL output, audio processing, font enumeration, and dozens of other signals.
Tools like `playwright-stealth` or `undetected-chromedriver` try to fix this with **config-level patches**JavaScript overrides, flag tweaks, UA spoofing. These work until the next Chrome update breaks them.
CloakBrowser patches **Chromium source code** — the fingerprint signals are modified at the C++ level, compiled into the binary. Detection sites see a real browser because, at the binary level, it *is* a real browser with different fingerprint values.
- **Config-level patches break** — `playwright-stealth`, `undetected-chromedriver`, and `puppeteer-extra` inject JavaScript or tweak flags. Every Chrome update breaks them. Antibot systems detect the patches themselves.
- **CloakBrowser patches Chromium source code** — fingerprints are modified at the C++ level, compiled into the binary. Detection sites see a real browser because it *is* a real browser.
- **One line to switch** — same Playwright API, no new abstractions, no CAPTCHA-solving services.
## Test Results
All tests verified against live detection services. Last tested: Feb 2026 (Chromium 145).
All tests verified against live detection services. Last tested: Feb 2026 (Chromium 142).
| Detection Service | Stock Playwright | CloakBrowser | Notes |
|---|---|---|---|
@@ -62,7 +61,7 @@ All tests verified against live detection services. Last tested: Feb 2026 (Chrom
| `navigator.webdriver` | `true` | **`false`** | Source-level patch |
| `navigator.plugins.length` | 0 | **5** | Real plugin list |
| `window.chrome` | `undefined` | **`object`** | Present like real Chrome |
| UA string | `HeadlessChrome` | **`Chrome/145.0.0.0`** | No headless leak |
| UA string | `HeadlessChrome` | **`Chrome/142.0.0.0`** | No headless leak |
| CDP detection | Detected | **Not detected** | `isAutomatedWithCDP: false` |
| TLS fingerprint | Mismatch | **Identical to Chrome** | ja3n/ja4/akamai match |
@@ -71,17 +70,22 @@ All tests verified against live detection services. Last tested: Feb 2026 (Chrom
### Proof
<p align="center">
<img src="images/turnstile_non_interactive.png" width="600" alt="Cloudflare Turnstile — Success">
<img src="https://raw.githubusercontent.com/CloakHQ/CloakBrowser/main/images/recaptcha_v3_score_09.png" width="600" alt="reCAPTCHA v3 — Score 0.9">
<br><em>reCAPTCHA v3 score 0.9 — server-side verified (human-level)</em>
</p>
<p align="center">
<img src="https://raw.githubusercontent.com/CloakHQ/CloakBrowser/main/images/turnstile_non_interactive.png" width="600" alt="Cloudflare Turnstile — Success">
<br><em>Cloudflare Turnstile non-interactive challenge — auto-resolved</em>
</p>
<p align="center">
<img src="images/browserscan_normal.png" width="600" alt="BrowserScan — Normal">
<img src="https://raw.githubusercontent.com/CloakHQ/CloakBrowser/main/images/browserscan_normal.png" width="600" alt="BrowserScan — Normal">
<br><em>BrowserScan bot detection — NORMAL (4/4 checks passed)</em>
</p>
<p align="center">
<img src="images/fingerprintjs_pass.png" width="600" alt="FingerprintJS — Passed">
<img src="https://raw.githubusercontent.com/CloakHQ/CloakBrowser/main/images/fingerprintjs_pass.png" width="600" alt="FingerprintJS — Passed">
<br><em>FingerprintJS web-scraping demo — data served, not blocked</em>
</p>
@@ -172,7 +176,7 @@ from cloakbrowser import binary_info, clear_cache, ensure_binary
# Check binary installation status
print(binary_info())
# {'version': '145.0.7723.116', 'platform': 'darwin-arm64', 'installed': True, ...}
# {'version': '142.0.7444.175', 'platform': 'linux-x64', 'installed': True, ...}
# Force re-download
clear_cache()
@@ -233,6 +237,85 @@ See the [`examples/`](examples/) directory:
- [`recaptcha_score.py`](examples/recaptcha_score.py) — Check your reCAPTCHA v3 score
- [`stealth_test.py`](examples/stealth_test.py) — Run against all detection services
## Roadmap
| Feature | Status |
|---------|--------|
| Linux x64 binary | ✅ Released |
| macOS arm64 (Apple Silicon) | 🔜 In progress |
| Chromium 145 build | 🔜 In progress |
| JavaScript/Puppeteer support (`cloakbrowser-js`) | 📋 Planned |
| Fingerprint rotation per session | 📋 Planned |
| Built-in proxy rotation | 📋 Planned |
| Windows support | 📋 Planned |
> ⭐ **Star this repo** to get notified when Chromium 145 and macOS builds drop.
## Docker
A ready-to-use [`Dockerfile`](Dockerfile) is included. It installs system deps, the package, and pre-downloads the stealth binary during build:
```bash
docker build -t cloakbrowser .
docker run --rm cloakbrowser python examples/basic.py
```
The key steps in the Dockerfile:
1. **System deps** — Chromium requires ~15 shared libraries (`libnss3`, `libgbm1`, etc.)
2. **`pip install .`** — installs CloakBrowser + Playwright
3. **`ensure_binary()`** — downloads the stealth Chromium binary at build time (~200MB), so containers start instantly
To extend with your own script, just add a `COPY` + `CMD`:
```dockerfile
FROM cloakbrowser
COPY your_script.py /app/
CMD ["python", "your_script.py"]
```
**Note:** If you run CloakBrowser inside a web server with uvloop (e.g., `uvicorn[standard]`), use `--loop asyncio` to avoid subprocess pipe hangs.
## Headed Mode (for aggressive bot detection)
Some sites using advanced bot detection (e.g., DataDome, Cloudflare Turnstile) can detect headless mode even with our C++ patches. For these sites, run in **headed mode** with a virtual display:
```bash
# Install Xvfb (virtual framebuffer)
sudo apt install xvfb
# Start virtual display
Xvfb :99 -screen 0 1920x1080x24 &
export DISPLAY=:99
```
```python
from cloakbrowser import launch
# Headed mode + residential proxy for maximum stealth
browser = launch(headless=False, proxy="http://your-residential-proxy:port")
page = browser.new_page()
page.goto("https://heavily-protected-site.com") # passes DataDome, etc.
browser.close()
```
This runs a real headed browser rendered on a virtual display — no physical monitor needed. Combined with a residential proxy, this passes even the most aggressive detection services.
> **Tip:** Datacenter IPs are often flagged by IP reputation databases regardless of browser fingerprint. For sites with strict bot detection, a residential proxy makes the difference.
## Troubleshooting
**Binary download fails / timeout**
Set a custom download URL or use a local binary:
```bash
export CLOAKBROWSER_BINARY_PATH=/path/to/your/chrome
```
**"playwright install" vs CloakBrowser binary**
You do NOT need `playwright install chromium`. CloakBrowser downloads its own binary. You only need Playwright's system deps:
```bash
playwright install-deps chromium
```
## FAQ
**Q: Is this legal?**
@@ -248,7 +331,7 @@ A: Possibly. Bot detection is an arms race. Source-level patches are harder to d
A: Yes. Pass `proxy="http://user:pass@host:port"` to `launch()`.
**Q: Can I use this with Docker?**
A: Yes. Use `ensure_binary()` in your Dockerfile to pre-download the binary during image build.
A: Yes. A ready-to-use Dockerfile is included — see the [Docker](#docker) section above.
## License
+2 -2
View File
@@ -12,7 +12,7 @@ Usage:
"""
from .browser import launch, launch_async, launch_context
from .config import CHROMIUM_VERSION, DEFAULT_STEALTH_ARGS
from .config import CHROMIUM_VERSION, get_default_stealth_args
from .download import binary_info, clear_cache, ensure_binary
from ._version import __version__
@@ -24,6 +24,6 @@ __all__ = [
"clear_cache",
"binary_info",
"CHROMIUM_VERSION",
"DEFAULT_STEALTH_ARGS",
"get_default_stealth_args",
"__version__",
]
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.1.0"
__version__ = "0.1.5"
+4 -2
View File
@@ -17,7 +17,7 @@ from __future__ import annotations
import logging
from typing import Any
from .config import DEFAULT_STEALTH_ARGS
from .config import get_default_stealth_args
from .download import ensure_binary
logger = logging.getLogger("cloakbrowser")
@@ -63,6 +63,7 @@ def launch(
executable_path=binary_path,
headless=headless,
args=chrome_args,
ignore_default_args=["--enable-automation"],
**_build_proxy_kwargs(proxy),
**kwargs,
)
@@ -123,6 +124,7 @@ async def launch_async(
executable_path=binary_path,
headless=headless,
args=chrome_args,
ignore_default_args=["--enable-automation"],
**_build_proxy_kwargs(proxy),
**kwargs,
)
@@ -209,7 +211,7 @@ def _build_args(stealth_args: bool, extra_args: list[str] | None) -> list[str]:
"""Combine stealth args with user-provided args."""
result = []
if stealth_args:
result.extend(DEFAULT_STEALTH_ARGS)
result.extend(get_default_stealth_args())
if extra_args:
result.extend(extra_args)
return result
+13 -10
View File
@@ -4,6 +4,7 @@ from __future__ import annotations
import os
import platform
import random
from pathlib import Path
from ._version import __version__
@@ -17,16 +18,18 @@ CHROMIUM_VERSION = "142.0.7444.175"
# Default stealth arguments passed to the patched Chromium binary.
# These activate source-level fingerprint patches compiled into the binary.
# ---------------------------------------------------------------------------
DEFAULT_STEALTH_ARGS: list[str] = [
"--no-sandbox",
"--disable-blink-features=AutomationControlled",
# Fingerprint overrides (activate compiled C++ patches)
"--fingerprint=98765",
"--fingerprint-platform=windows",
"--fingerprint-hardware-concurrency=8",
"--fingerprint-gpu-vendor=NVIDIA Corporation",
"--fingerprint-gpu-renderer=NVIDIA GeForce RTX 4070",
]
def get_default_stealth_args() -> list[str]:
"""Build stealth args with a random fingerprint seed per launch."""
seed = random.randint(10000, 99999)
return [
"--no-sandbox",
"--disable-blink-features=AutomationControlled",
f"--fingerprint={seed}",
"--fingerprint-platform=windows",
"--fingerprint-hardware-concurrency=8",
"--fingerprint-gpu-vendor=NVIDIA Corporation",
"--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070",
]
# ---------------------------------------------------------------------------
# Platform detection
+241 -27
View File
@@ -1,57 +1,271 @@
"""Run stealth tests against major bot detection services.
Tests cloakbrowser against multiple detection sites and reports results.
Tests cloakbrowser against multiple detection sites, extracts pass/fail
verdicts via JS evaluation, and reports results with screenshots.
Usage:
python examples/stealth_test.py
python examples/stealth_test.py --headed # watch in real-time
python examples/stealth_test.py --no-screenshots
python examples/stealth_test.py --proxy http://10.50.96.5:8888
"""
import json
import sys
import time
from cloakbrowser import launch
HEADED = "--headed" in sys.argv
SCREENSHOTS = "--no-screenshots" not 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_bot_sannysoft(page):
"""bot.sannysoft.com — classic bot detection checks."""
page.goto("https://bot.sannysoft.com", wait_until="networkidle", timeout=30000)
page.wait_for_timeout(3000)
results = page.evaluate("""() => {
const rows = document.querySelectorAll('table tr');
const data = {};
rows.forEach(r => {
const cells = r.querySelectorAll('td');
if (cells.length >= 2) {
const key = cells[0].innerText.trim();
const val = cells[1].innerText.trim();
const cls = cells[1].className || '';
data[key] = {value: val, passed: !cls.includes('failed')};
}
});
return data;
}""")
failed = [k for k, v in results.items() if not v["passed"]]
total = len(results)
passed = total - len(failed)
return {"passed": passed, "total": total, "failed": failed}
def test_bot_incolumitas(page):
"""bot.incolumitas.com — comprehensive 30+ check bot detection."""
page.goto("https://bot.incolumitas.com", wait_until="networkidle", timeout=30000)
page.wait_for_timeout(12000) # needs time to run all detection tests
# Site outputs JSON blocks in page text, not HTML tables
results = page.evaluate("""() => {
const text = document.body.innerText;
const okMatches = text.match(/"\\w+":\\s*"OK"/g) || [];
const failMatches = text.match(/"\\w+":\\s*"FAIL"/g) || [];
const failedTests = failMatches.map(m => m.match(/"(\\w+)"/)[1]);
return {
passed: okMatches.length,
failed: failMatches.length,
failedTests,
total: okMatches.length + failMatches.length
};
}""")
return results
def test_browserscan(page):
"""browserscan.net/bot-detection — WebDriver, UA, CDP, Navigator checks."""
page.goto("https://www.browserscan.net/bot-detection", wait_until="networkidle", timeout=30000)
page.wait_for_timeout(5000)
results = page.evaluate("""() => {
const items = document.querySelectorAll('[class*="result"], [class*="item"], [class*="check"]');
let normal = 0, abnormal = 0;
const text = document.body.innerText;
// Count "Normal" vs "Abnormal" verdicts
const normalMatches = text.match(/Normal/g);
const abnormalMatches = text.match(/Abnormal/g);
return {
normal: normalMatches ? normalMatches.length : 0,
abnormal: abnormalMatches ? abnormalMatches.length : 0,
pageText: text.substring(0, 500)
};
}""")
return results
def test_deviceandbrowserinfo(page):
"""deviceandbrowserinfo.com/are_you_a_bot — fingerprint + behavioral detection."""
page.goto("https://deviceandbrowserinfo.com/are_you_a_bot", wait_until="domcontentloaded", timeout=30000)
page.wait_for_timeout(8000)
results = page.evaluate("""() => {
const text = document.body.innerText;
// Site outputs JSON with "isBot": false and detail checks
const botMatch = text.match(/"isBot":\\s*(true|false)/);
const isBot = botMatch ? botMatch[1] === 'true' : null;
const checks = {};
const patterns = [
'isBot', 'hasBotUserAgent', 'hasWebdriverTrue',
'isHeadlessChrome', 'isAutomatedWithCDP', 'hasSuspiciousWeakSignals',
'isPlaywright', 'hasInconsistentChromeObject'
];
patterns.forEach(p => {
const match = text.match(new RegExp('"' + p + '":\\s*(true|false)'));
if (match) checks[p] = match[1] === 'true';
});
return {isBot, checks};
}""")
return results
def test_fingerprintjs(page):
"""demo.fingerprint.com/web-scraping — industry-standard bot detection."""
page.goto("https://demo.fingerprint.com/web-scraping", wait_until="networkidle", timeout=30000)
page.wait_for_timeout(5000)
# Click search to trigger bot detection — bots get blocked, humans see flights
try:
page.click("button:has-text('Search')", timeout=5000)
page.wait_for_timeout(5000)
except Exception:
pass
results = page.evaluate("""() => {
const text = document.body.innerText;
// Bots see error messages; humans see flight prices
const hasFlights = text.includes('Price per adult') || text.includes('$');
const isBlocked = text.includes('request was blocked') || text.includes('bot visit detected');
return {passed: hasFlights && !isBlocked, isBlocked, hasFlights};
}""")
return results
def test_recaptcha(page):
"""recaptcha-demo.appspot.com — Google's official reCAPTCHA v3 score."""
page.goto(
"https://recaptcha-demo.appspot.com/recaptcha-v3-request-scores.php",
wait_until="networkidle",
timeout=30000,
)
# Page auto-submits via grecaptcha.execute() — wait for backend response
page.wait_for_timeout(8000)
results = page.evaluate("""() => {
const text = document.body.innerText;
// Score appears in JSON response block: "score": 0.9
const scoreMatch = text.match(/"score":\\s*(\\d+\\.\\d+)/);
return {
score: scoreMatch ? parseFloat(scoreMatch[1]) : null,
pageText: text.substring(0, 500)
};
}""")
return results
TESTS = [
{
"name": "bot.sannysoft.com",
"url": "https://bot.sannysoft.com",
"runner": test_bot_sannysoft,
"verdict": lambda r: f"{r['passed']}/{r['total']} passed"
+ (f" (FAILED: {', '.join(r['failed'])})" if r["failed"] else " — ALL GREEN"),
"pass": lambda r: len(r["failed"]) == 0,
},
{
"name": "bot.incolumitas.com",
"url": "https://bot.incolumitas.com",
"check": "Bot detection analysis",
"runner": test_bot_incolumitas,
"verdict": lambda r: f"{r['passed']}/{r['total']} passed"
+ (f" (FAILED: {', '.join(r.get('failedTests', []))})" if r.get("failed", 0) > 0 else " — ALL GREEN"),
"pass": lambda r: r.get("failed", 0) <= 1, # fpscanner.WEBDRIVER false positive expected (all builds)
},
{
"name": "BrowserScan",
"url": "https://www.browserscan.net/bot-detection",
"check": "Bot detection status",
"runner": test_browserscan,
"verdict": lambda r: f"Normal: {r['normal']}, Abnormal: {r['abnormal']}",
"pass": lambda r: r.get("abnormal", 1) == 0,
},
{
"name": "deviceandbrowserinfo.com",
"url": "https://deviceandbrowserinfo.com/are_you_a_bot",
"check": "isBot flag",
"runner": test_deviceandbrowserinfo,
"verdict": lambda r: f"isBot: {r.get('isBot', 'unknown')}"
+ (f" checks: {json.dumps(r.get('checks', {}))}" if r.get("checks") else ""),
"pass": lambda r: not r.get("isBot", True),
},
{
"name": "FingerprintJS",
"url": "https://demo.fingerprint.com/web-scraping",
"check": "Bot detection result",
"runner": test_fingerprintjs,
"verdict": lambda r: "PASSED (flights shown)" if r.get("passed") else "BLOCKED" if r.get("isBlocked") else "NO FLIGHTS",
"pass": lambda r: r.get("passed", False),
},
{
"name": "reCAPTCHA v3 (Google)",
"url": "https://recaptcha-demo.appspot.com/recaptcha-v3-request-scores.php",
"runner": test_recaptcha,
"verdict": lambda r: f"Score: {r.get('score', 'N/A')}",
"pass": lambda r: (r.get("score") or 0) >= 0.7,
},
]
browser = launch(headless=True)
page = browser.new_page()
print("=" * 60)
print("CloakBrowser Stealth Test Suite")
print("=" * 60)
def main():
print("=" * 60)
print("CloakBrowser Stealth Test Suite")
print("=" * 60)
print(f"Mode: {'headed' if HEADED else 'headless'}")
print(f"Screenshots: {'on' if SCREENSHOTS else 'off'}")
print(f"Proxy: {PROXY or 'none'}")
print()
for test in TESTS:
print(f"\n--- {test['name']} ---")
print(f"URL: {test['url']}")
try:
page.goto(test["url"], wait_until="networkidle", timeout=30000)
page.wait_for_timeout(3000)
browser = launch(headless=not HEADED, proxy=PROXY)
page = browser.new_page()
# Screenshot each test
filename = f"stealth_test_{test['name'].replace('.', '_').replace(' ', '_')}.png"
page.screenshot(path=filename)
print(f"Screenshot: {filename}")
print(f"Title: {page.title()}")
except Exception as e:
print(f"Error: {e}")
results_summary = []
browser.close()
for test in TESTS:
name = test["name"]
print(f"--- {name} ---")
print(f"URL: {test['url']}")
print("\n" + "=" * 60)
print("Tests complete. Check screenshots for results.")
print("=" * 60)
try:
result = test["runner"](page)
passed = test["pass"](result)
verdict = test["verdict"](result)
status = "PASS" if passed else "FAIL"
results_summary.append((name, status, verdict))
print(f"Result: [{status}] {verdict}")
if SCREENSHOTS:
filename = f"stealth_test_{name.replace('.', '_').replace(' ', '_').replace('/', '_')}.png"
page.screenshot(path=filename)
print(f"Screenshot: {filename}")
except Exception as e:
results_summary.append((name, "ERROR", str(e)))
print(f"Error: {e}")
print()
browser.close()
# Summary table
print("=" * 60)
print("RESULTS SUMMARY")
print("=" * 60)
for name, status, verdict in results_summary:
icon = {"PASS": "+", "FAIL": "!", "ERROR": "x"}[status]
print(f" [{icon}] {name}: {verdict}")
passed_count = sum(1 for _, s, _ in results_summary if s == "PASS")
total = len(results_summary)
print(f"\n {passed_count}/{total} tests passed")
print("=" * 60)
return 0 if passed_count == total else 1
if __name__ == "__main__":
sys.exit(main())
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

+5 -5
View File
@@ -10,7 +10,7 @@ readme = "README.md"
license = "MIT"
requires-python = ">=3.9"
authors = [
{ name = "cloakbrowser" },
{ name = "CloakHQ", email = "cloakhq@pm.me" },
]
keywords = [
"stealth",
@@ -47,10 +47,10 @@ dependencies = [
]
[project.urls]
Homepage = "https://github.com/CloakHQ/cloakbrowser"
Documentation = "https://github.com/CloakHQ/cloakbrowser#readme"
Repository = "https://github.com/CloakHQ/cloakbrowser"
Issues = "https://github.com/CloakHQ/cloakbrowser/issues"
Homepage = "https://github.com/CloakHQ/CloakBrowser"
Documentation = "https://github.com/CloakHQ/CloakBrowser#readme"
Repository = "https://github.com/CloakHQ/CloakBrowser"
Issues = "https://github.com/CloakHQ/CloakBrowser/issues"
[tool.hatch.version]
path = "cloakbrowser/_version.py"