Compare commits

..
Author SHA1 Message Date
CloakHQ c0ba21faa1 release: v0.3.14 — upgrade Linux binary to .159.6, add binary management CLI
Binary:
- Upgrade Linux build to 145.0.7632.159.6 (32 patches)
- Fix persistent context fingerprint consistency
- Storage quota normalization for persistent context profiles
- Fix window dimension calculation for non-incognito contexts

Wrapper:
- Add CLI for binary management with visible download progress (closes #43)
- Python: python -m cloakbrowser install|info|update|clear-cache
- JavaScript: npx cloakbrowser install|info|update|clear-cache
2026-03-11 23:44:41 +01:00
CloakHQ b501d8f158 chore: gitignore browser profile manager directory 2026-03-11 18:13:19 +01:00
CloakHQ 6007a6e511 feat: add CLI for binary management (Python + JavaScript)
Adds install, info, update, and clear-cache subcommands with visible
download progress. Python: `python -m cloakbrowser install`. JavaScript:
`npx cloakbrowser install`. Useful for Dockerfiles where silent
first-use downloads are hard to debug. Closes #43.
2026-03-11 04:33:37 +01:00
CloakHQ 96c55352e0 ci: remove deployment environments from publish workflow to hide actor identity 2026-03-11 00:22:57 +01:00
CloakHQ 5d35fb9e4c release: v0.3.13 — suppress SwiftShader default arg, upgrade Linux binary to .159.5 2026-03-10 23:11:12 +01:00
CloakHQ c966e046e7 docs: add Docker signature verification, deployment environments, improve troubleshooting
- Add cosign verify command to README Security section for Docker image verification
- Add GitHub deployment environments (pypi, npm, docker) to publish workflow for sidebar status tracking
- Simplify downgrade instructions: version-pinned pip/npm/docker instead of manual binary paths
- Improve troubleshooting section with headings and dividers for readability
- Update Latest section to v0.3.12 with new binary features
2026-03-10 07:27:18 +01:00
14 changed files with 338 additions and 30 deletions
+3
View File
@@ -56,6 +56,9 @@ test-infra/
# Website (deployed separately) # Website (deployed separately)
site/ site/
# Browser profile manager (deployed separately)
manager/
# Release scripts # Release scripts
publish.sh publish.sh
deploy.sh deploy.sh
+12
View File
@@ -6,6 +6,18 @@ Changes are tagged: **[wrapper]** for Python/JS wrapper, **[binary]** for Chromi
--- ---
## [0.3.14] — 2026-03-12
- **[binary]** Upgrade Linux build to 145.0.7632.159.6 — fix persistent context detection by FingerprintJS
- **[binary]** Storage quota normalization for persistent context profiles
- **[binary]** Fix outerHeight calculation for non-incognito contexts
- **[wrapper]** Add CLI for binary management — `python -m cloakbrowser install` / `npx cloakbrowser install` with visible download progress (closes #43)
## [0.3.13] — 2026-03-10
- **[wrapper]** Suppress Playwright's `--enable-unsafe-swiftshader` default arg — eliminates SwiftShader software renderer detection signal, letting the binary's GPU spoofing work cleanly
- **[binary]** Upgrade Linux build to 145.0.7632.159.5 — fix WebGPU adapter limits and features for NVIDIA profiles
## [0.3.12] — 2026-03-10 ## [0.3.12] — 2026-03-10
- **[binary]** Upgrade Linux build to 145.0.7632.159.4 - **[binary]** Upgrade Linux build to 145.0.7632.159.4
+66 -15
View File
@@ -110,7 +110,7 @@ page.goto("https://example.com")
> ⭐ **Star** to show support — **[Watch releases](https://github.com/CloakHQ/CloakBrowser/subscription)** to get notified when new builds drop. > ⭐ **Star** to show support — **[Watch releases](https://github.com/CloakHQ/CloakBrowser/subscription)** to get notified when new builds drop.
## Latest: v0.3.12 (Chromium 145.0.7632.159.4) ## Latest: v0.3.14 (Chromium 145.0.7632.159.6)
- **`humanize=True`** — one flag makes all mouse, keyboard, and scroll interactions behave like a real user. Bézier curves, per-character typing, realistic scroll patterns. Two presets: `default` and `careful` - **`humanize=True`** — one flag makes all mouse, keyboard, and scroll interactions behave like a real user. Bézier curves, per-character typing, realistic scroll patterns. Two presets: `default` and `careful`
- **CDP input behavior mimicking** — input events sent via CDP now produce the same signals as real user interactions. 5 new source-level patches covering pointer, keyboard, and mouse behavior - **CDP input behavior mimicking** — input events sent via CDP now produce the same signals as real user interactions. 5 new source-level patches covering pointer, keyboard, and mouse behavior
@@ -313,6 +313,17 @@ Supports all the same options as `launch_context()`: `proxy`, `user_agent`, `vie
Async version: `launch_persistent_context_async()`. Async version: `launch_persistent_context_async()`.
### CLI
Pre-download the binary or check installation status from the command line:
```bash
python -m cloakbrowser install # Download binary with progress output
python -m cloakbrowser info # Show version, path, platform
python -m cloakbrowser update # Check for and download newer binary
python -m cloakbrowser clear-cache # Remove cached binaries
```
### Utility Functions ### Utility Functions
```python ```python
@@ -706,6 +717,15 @@ COPY your_script.py /app/
CMD ["python", "your_script.py"] CMD ["python", "your_script.py"]
``` ```
**Building your own image from pip** — use `python -m cloakbrowser install` to download the binary during build with visible progress:
```dockerfile
FROM python:3.12-slim
RUN pip install cloakbrowser && python -m cloakbrowser install
COPY your_script.py /app/
CMD ["python", "/app/your_script.py"]
```
**Building from source** — a [`Dockerfile`](Dockerfile) is also included if you prefer to build your own image: **Building from source** — a [`Dockerfile`](Dockerfile) is also included if you prefer to build your own image:
```bash ```bash
@@ -718,7 +738,9 @@ CloakBrowser works identically local, in Docker, and on VPS. No environment-spec
## Troubleshooting ## Troubleshooting
**Still getting blocked on aggressive sites (DataDome, Turnstile)?** ---
### Still getting blocked on aggressive sites (DataDome, Turnstile)?
Some sites detect headless mode even with our C++ patches. Run in **headed mode** with a virtual display: Some sites detect headless mode even with our C++ patches. Run in **headed mode** with a virtual display:
@@ -743,7 +765,9 @@ 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. Datacenter IPs are often flagged by IP reputation regardless of browser fingerprint — a residential proxy makes the difference. 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. Datacenter IPs are often flagged by IP reputation regardless of browser fingerprint — a residential proxy makes the difference.
**Sites challenge fresh sessions but work after first visit** ---
### Sites challenge fresh sessions but work after first visit
Some sites challenge first-time visitors with no cookies over HTTP/2. This affects all Chromium browsers, not just CloakBrowser. Use a persistent profile to warm up cookies once, then reuse across sessions: Some sites challenge first-time visitors with no cookies over HTTP/2. This affects all Chromium browsers, not just CloakBrowser. Use a persistent profile to warm up cookies once, then reuse across sessions:
@@ -777,7 +801,10 @@ ctx = await launchPersistentContext({ userDataDir: './profile' });
For stateless/ephemeral use cases, `launch(args=["--disable-http2"])` forces HTTP/1.1 which bypasses the check. Only use this flag for sites that require it — most work fine with HTTP/2. For stateless/ephemeral use cases, `launch(args=["--disable-http2"])` forces HTTP/1.1 which bypasses the check. Only use this flag for sites that require it — most work fine with HTTP/2.
**Something not working? Make sure you're on the latest version** ---
### Something not working? Make sure you're on the latest version
Older versions may use outdated stealth args or download an older binary: Older versions may use outdated stealth args or download an older binary:
```bash ```bash
pip install -U cloakbrowser # Python pip install -U cloakbrowser # Python
@@ -785,13 +812,19 @@ npm install cloakbrowser@latest # JavaScript
docker pull cloakhq/cloakbrowser:latest # Docker docker pull cloakhq/cloakbrowser:latest # Docker
``` ```
**Binary download fails / timeout** ---
### Binary download fails / timeout
Set a custom download URL or use a local binary: Set a custom download URL or use a local binary:
```bash ```bash
export CLOAKBROWSER_BINARY_PATH=/path/to/your/chrome export CLOAKBROWSER_BINARY_PATH=/path/to/your/chrome
``` ```
**New update broke something? Roll back to the previous version** ---
### New update broke something? Roll back to the previous version
Install a specific wrapper version to downgrade both the wrapper and the binary it downloads: Install a specific wrapper version to downgrade both the wrapper and the binary it downloads:
```bash ```bash
pip install cloakbrowser==0.3.11 # Python pip install cloakbrowser==0.3.11 # Python
@@ -800,23 +833,33 @@ docker pull cloakhq/cloakbrowser:0.3.11 # Docker
``` ```
Each wrapper version pins its own binary version, so downgrading the wrapper automatically gets you the matching binary on next launch. Each wrapper version pins its own binary version, so downgrading the wrapper automatically gets you the matching binary on next launch.
**macOS: "App is damaged" or Gatekeeper blocks launch** ---
### macOS: "App is damaged" or Gatekeeper blocks launch
The binary is ad-hoc signed. macOS quarantines downloaded files. Run once to clear it: The binary is ad-hoc signed. macOS quarantines downloaded files. Run once to clear it:
```bash ```bash
xattr -cr ~/.cloakbrowser/chromium-*/Chromium.app xattr -cr ~/.cloakbrowser/chromium-*/Chromium.app
``` ```
**"playwright install" vs CloakBrowser binary** ---
### "playwright install" vs CloakBrowser binary
You do NOT need `playwright install chromium`. CloakBrowser downloads its own binary. You only need Playwright's system deps: You do NOT need `playwright install chromium`. CloakBrowser downloads its own binary. You only need Playwright's system deps:
```bash ```bash
playwright install-deps chromium playwright install-deps chromium
``` ```
**macOS: Blocked on some sites that pass on Linux** ---
### macOS: Blocked on some sites that pass on Linux
The macOS fingerprint profile has known inconsistencies that aggressive bot detection catches. If a site blocks you on macOS but works on Linux, switch to a Windows fingerprint profile by passing `stealth_args=False` and manually setting `--fingerprint-platform=windows` with matching GPU flags (see [Fingerprint Management](#fingerprint-management) for the full flag list). The macOS fingerprint profile has known inconsistencies that aggressive bot detection catches. If a site blocks you on macOS but works on Linux, switch to a Windows fingerprint profile by passing `stealth_args=False` and manually setting `--fingerprint-platform=windows` with matching GPU flags (see [Fingerprint Management](#fingerprint-management) for the full flag list).
**Site detects incognito / private browsing mode** ---
### Site detects incognito / private browsing mode
By default, `launch()` opens an incognito context. Some sites (like BrowserScan) detect this. Use `launch_persistent_context()` instead — it runs with a real user profile, so incognito detection passes: By default, `launch()` opens an incognito context. Some sites (like BrowserScan) detect this. Use `launch_persistent_context()` instead — it runs with a real user profile, so incognito detection passes:
@@ -838,7 +881,9 @@ const ctx = await launchPersistentContext({
This also gives you cookie and localStorage persistence across sessions. This also gives you cookie and localStorage persistence across sessions.
**reCAPTCHA v3 scores are low (0.10.3)** ---
### reCAPTCHA v3 scores are low (0.10.3)
Avoid `page.wait_for_timeout()` — it sends CDP protocol commands that reCAPTCHA detects. Use native sleep instead: Avoid `page.wait_for_timeout()` — it sends CDP protocol commands that reCAPTCHA detects. Use native sleep instead:
@@ -908,15 +953,21 @@ A: Yes. Pass `proxy="http://user:pass@host:port"` to `launch()`.
## Security ## Security
All binary releases are GPG-signed and include GitHub artifact attestations for supply chain verification. All releases are signed for supply chain verification.
```bash ```bash
# Verify GPG signature # Verify GPG signature (binary release tag)
gpg --keyserver keyserver.ubuntu.com --recv-keys C60C0DDC9D0DE2DD gpg --keyserver keyserver.ubuntu.com --recv-keys C60C0DDC9D0DE2DD
git verify-tag chromium-v145.0.7632.159.4 git verify-tag chromium-v145.0.7632.159.6
# Verify binary attestation # Verify GitHub binary attestation (Sigstore)
gh attestation verify cloakbrowser-linux-x64.tar.gz --repo CloakHQ/cloakbrowser gh attestation verify cloakbrowser-linux-x64.tar.gz --repo CloakHQ/cloakbrowser
# Verify Docker image signature (Cosign/Sigstore)
cosign verify \
--certificate-identity-regexp "https://github.com/CloakHQ/CloakBrowser/" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
cloakhq/cloakbrowser:latest
``` ```
## License ## License
+111
View File
@@ -0,0 +1,111 @@
"""CLI for cloakbrowser — download and manage the stealth Chromium binary.
Usage:
python -m cloakbrowser install # Download binary (with progress)
python -m cloakbrowser info # Show binary version, path, platform
python -m cloakbrowser update # Check for and download newer binary
python -m cloakbrowser clear-cache # Remove cached binaries
"""
from __future__ import annotations
import argparse
import logging
import sys
def _setup_logging() -> None:
"""Route cloakbrowser logger to stderr with clean output."""
logging.basicConfig(
level=logging.INFO,
format="%(message)s",
stream=sys.stderr,
force=True,
)
# Suppress noisy HTTP request logs from httpx
logging.getLogger("httpx").setLevel(logging.WARNING)
def cmd_install(args: argparse.Namespace) -> None:
from .download import ensure_binary
path = ensure_binary()
print(path)
def cmd_info(args: argparse.Namespace) -> None:
from .config import get_local_binary_override
from .download import binary_info
info = binary_info()
override = get_local_binary_override()
print(f"Version: {info['version']}")
print(f"Platform: {info['platform']}")
print(f"Binary: {info['binary_path']}")
print(f"Installed: {info['installed']}")
print(f"Cache: {info['cache_dir']}")
if override:
print(f"Override: {override} (CLOAKBROWSER_BINARY_PATH)")
def cmd_update(args: argparse.Namespace) -> None:
from .download import check_for_update
logger = logging.getLogger("cloakbrowser")
logger.info("Checking for updates...")
new_version = check_for_update()
if new_version:
print(f"Updated to Chromium {new_version}")
else:
print("Already up to date.")
def cmd_clear_cache(args: argparse.Namespace) -> None:
from .config import get_cache_dir
from .download import clear_cache
if not get_cache_dir().exists():
print("No cache to clear.")
return
clear_cache()
print("Cache cleared.")
def main() -> None:
parser = argparse.ArgumentParser(
prog="cloakbrowser",
description="Manage the CloakBrowser stealth Chromium binary.",
)
sub = parser.add_subparsers(dest="command")
sub.add_parser("install", help="Download the Chromium binary")
sub.add_parser("info", help="Show binary version, path, and platform")
sub.add_parser("update", help="Check for and download a newer binary")
sub.add_parser("clear-cache", help="Remove all cached binaries")
args = parser.parse_args()
if not args.command:
parser.print_help()
sys.exit(2)
_setup_logging()
commands = {
"install": cmd_install,
"info": cmd_info,
"update": cmd_update,
"clear-cache": cmd_clear_cache,
}
try:
commands[args.command](args)
except KeyboardInterrupt:
sys.exit(130)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.3.12" __version__ = "0.3.14"
+5 -5
View File
@@ -19,7 +19,7 @@ import os
from typing import Any, Literal, TypedDict from typing import Any, Literal, TypedDict
from urllib.parse import unquote, urlparse, urlunparse from urllib.parse import unquote, urlparse, urlunparse
from .config import DEFAULT_VIEWPORT, get_default_stealth_args from .config import DEFAULT_VIEWPORT, IGNORE_DEFAULT_ARGS, get_default_stealth_args
from .download import ensure_binary from .download import ensure_binary
logger = logging.getLogger("cloakbrowser") logger = logging.getLogger("cloakbrowser")
@@ -111,7 +111,7 @@ def launch(
executable_path=binary_path, executable_path=binary_path,
headless=headless, headless=headless,
args=chrome_args, args=chrome_args,
ignore_default_args=["--enable-automation"], ignore_default_args=IGNORE_DEFAULT_ARGS,
**_build_proxy_kwargs(proxy), **_build_proxy_kwargs(proxy),
**kwargs, **kwargs,
) )
@@ -194,7 +194,7 @@ async def launch_async( # noqa: C901
executable_path=binary_path, executable_path=binary_path,
headless=headless, headless=headless,
args=chrome_args, args=chrome_args,
ignore_default_args=["--enable-automation"], ignore_default_args=IGNORE_DEFAULT_ARGS,
**_build_proxy_kwargs(proxy), **_build_proxy_kwargs(proxy),
**kwargs, **kwargs,
) )
@@ -305,7 +305,7 @@ def launch_persistent_context(
executable_path=binary_path, executable_path=binary_path,
headless=headless, headless=headless,
args=chrome_args, args=chrome_args,
ignore_default_args=["--enable-automation"], ignore_default_args=IGNORE_DEFAULT_ARGS,
**_build_proxy_kwargs(proxy), **_build_proxy_kwargs(proxy),
**context_kwargs, **context_kwargs,
) )
@@ -418,7 +418,7 @@ async def launch_persistent_context_async(
executable_path=binary_path, executable_path=binary_path,
headless=headless, headless=headless,
args=chrome_args, args=chrome_args,
ignore_default_args=["--enable-automation"], ignore_default_args=IGNORE_DEFAULT_ARGS,
**_build_proxy_kwargs(proxy), **_build_proxy_kwargs(proxy),
**context_kwargs, **context_kwargs,
) )
+10 -2
View File
@@ -15,15 +15,23 @@ from ._version import __version__
# CHROMIUM_VERSION is the latest across all platforms (for display/reference). # CHROMIUM_VERSION is the latest across all platforms (for display/reference).
# Use get_chromium_version() for the current platform's actual version. # Use get_chromium_version() for the current platform's actual version.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
CHROMIUM_VERSION = "145.0.7632.159.4" CHROMIUM_VERSION = "145.0.7632.159.6"
PLATFORM_CHROMIUM_VERSIONS: dict[str, str] = { PLATFORM_CHROMIUM_VERSIONS: dict[str, str] = {
"linux-x64": "145.0.7632.159.4", "linux-x64": "145.0.7632.159.6",
"darwin-arm64": "145.0.7632.109.2", "darwin-arm64": "145.0.7632.109.2",
"darwin-x64": "145.0.7632.109.2", "darwin-x64": "145.0.7632.109.2",
"windows-x64": "145.0.7632.109.2", "windows-x64": "145.0.7632.109.2",
} }
# ---------------------------------------------------------------------------
# Playwright default args to suppress — these leak automation signals.
# --enable-automation: exposes navigator.webdriver = true
# --enable-unsafe-swiftshader: forces software WebGL rendering via SwiftShader,
# producing a distinctive renderer string that no real user browser has
# ---------------------------------------------------------------------------
IGNORE_DEFAULT_ARGS = ["--enable-automation", "--enable-unsafe-swiftshader"]
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Default stealth arguments passed to the patched Chromium binary. # Default stealth arguments passed to the patched Chromium binary.
# These activate source-level fingerprint patches compiled into the binary. # These activate source-level fingerprint patches compiled into the binary.
+11
View File
@@ -133,6 +133,17 @@ const browser = await launch({ proxy: 'http://proxy:8080', geoip: true, timezone
> **Note:** For rotating residential proxies, the DNS-resolved IP may differ from the exit IP. Pass explicit `timezone`/`locale` in those cases. > **Note:** For rotating residential proxies, the DNS-resolved IP may differ from the exit IP. Pass explicit `timezone`/`locale` in those cases.
### CLI
Pre-download the binary or check installation status from the command line:
```bash
npx cloakbrowser install # Download binary with progress output
npx cloakbrowser info # Show version, path, platform
npx cloakbrowser update # Check for and download newer binary
npx cloakbrowser clear-cache # Remove cached binaries
```
### Utilities ### Utilities
```javascript ```javascript
+4 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "cloakbrowser", "name": "cloakbrowser",
"version": "0.3.12", "version": "0.3.14",
"description": "Stealth Chromium that passes every bot detection test. Drop-in Playwright/Puppeteer replacement with source-level fingerprint patches.", "description": "Stealth Chromium that passes every bot detection test. Drop-in Playwright/Puppeteer replacement with source-level fingerprint patches.",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
@@ -15,6 +15,9 @@
"import": "./dist/puppeteer.js" "import": "./dist/puppeteer.js"
} }
}, },
"bin": {
"cloakbrowser": "./dist/cli.js"
},
"files": [ "files": [
"dist" "dist"
], ],
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env node
/**
* CLI for cloakbrowser — download and manage the stealth Chromium binary.
*
* Usage:
* npx cloakbrowser install # Download binary (with progress)
* npx cloakbrowser info # Show binary version, path, platform
* npx cloakbrowser update # Check for and download newer binary
* npx cloakbrowser clear-cache # Remove cached binaries
*/
import { ensureBinary, binaryInfo, checkForUpdate, clearCache } from "./download.js";
import { getLocalBinaryOverride, getCacheDir } from "./config.js";
import fs from "node:fs";
const USAGE = `Usage: cloakbrowser <command>
Commands:
install Download the Chromium binary
info Show binary version, path, and platform
update Check for and download a newer binary
clear-cache Remove all cached binaries`;
async function cmdInstall(): Promise<void> {
const binaryPath = await ensureBinary();
console.log(binaryPath);
}
function cmdInfo(): void {
const info = binaryInfo();
const override = getLocalBinaryOverride();
console.log(`Version: ${info.version}`);
console.log(`Platform: ${info.platform}`);
console.log(`Binary: ${info.binaryPath}`);
console.log(`Installed: ${info.installed}`);
console.log(`Cache: ${info.cacheDir}`);
if (override) {
console.log(`Override: ${override} (CLOAKBROWSER_BINARY_PATH)`);
}
}
async function cmdUpdate(): Promise<void> {
console.error("Checking for updates...");
const newVersion = await checkForUpdate();
if (newVersion) {
console.log(`Updated to Chromium ${newVersion}`);
} else {
console.log("Already up to date.");
}
}
function cmdClearCache(): void {
const cacheDir = getCacheDir();
if (!fs.existsSync(cacheDir)) {
console.log("No cache to clear.");
return;
}
clearCache();
console.log("Cache cleared.");
}
async function main(): Promise<void> {
const command = process.argv[2];
if (!command || command === "--help" || command === "-h") {
console.log(USAGE);
process.exit(command ? 0 : 2);
}
try {
switch (command) {
case "install":
await cmdInstall();
break;
case "info":
cmdInfo();
break;
case "update":
await cmdUpdate();
break;
case "clear-cache":
cmdClearCache();
break;
default:
console.error(`Unknown command: ${command}\n`);
console.log(USAGE);
process.exit(2);
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
console.error(`Error: ${message}`);
process.exit(1);
}
}
main();
+10 -2
View File
@@ -27,10 +27,10 @@ export { WRAPPER_VERSION };
// CHROMIUM_VERSION is the latest across all platforms (for display/reference). // CHROMIUM_VERSION is the latest across all platforms (for display/reference).
// Use getChromiumVersion() for the current platform's actual version. // Use getChromiumVersion() for the current platform's actual version.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export const CHROMIUM_VERSION = "145.0.7632.159.4"; export const CHROMIUM_VERSION = "145.0.7632.159.6";
export const PLATFORM_CHROMIUM_VERSIONS: Record<string, string> = { export const PLATFORM_CHROMIUM_VERSIONS: Record<string, string> = {
"linux-x64": "145.0.7632.159.4", "linux-x64": "145.0.7632.159.6",
"darwin-arm64": "145.0.7632.109.2", "darwin-arm64": "145.0.7632.109.2",
"darwin-x64": "145.0.7632.109.2", "darwin-x64": "145.0.7632.109.2",
"windows-x64": "145.0.7632.109.2", "windows-x64": "145.0.7632.109.2",
@@ -188,6 +188,14 @@ export function getLocalBinaryOverride(): string | undefined {
return process.env.CLOAKBROWSER_BINARY_PATH || undefined; return process.env.CLOAKBROWSER_BINARY_PATH || undefined;
} }
// ---------------------------------------------------------------------------
// Playwright default args to suppress — these leak automation signals.
// --enable-automation: exposes navigator.webdriver = true
// --enable-unsafe-swiftshader: forces software WebGL rendering via SwiftShader,
// producing a distinctive renderer string that no real user browser has
// ---------------------------------------------------------------------------
export const IGNORE_DEFAULT_ARGS = ["--enable-automation", "--enable-unsafe-swiftshader"];
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Default stealth arguments // Default stealth arguments
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+3 -3
View File
@@ -5,7 +5,7 @@
import type { Browser, BrowserContext } from "playwright-core"; import type { Browser, BrowserContext } from "playwright-core";
import type { LaunchOptions, LaunchContextOptions, LaunchPersistentContextOptions } from "./types.js"; import type { LaunchOptions, LaunchContextOptions, LaunchPersistentContextOptions } from "./types.js";
import { DEFAULT_VIEWPORT } from "./config.js"; import { DEFAULT_VIEWPORT, IGNORE_DEFAULT_ARGS } from "./config.js";
import { buildArgs } from "./args.js"; import { buildArgs } from "./args.js";
import { ensureBinary } from "./download.js"; import { ensureBinary } from "./download.js";
import { parseProxyUrl } from "./proxy.js"; import { parseProxyUrl } from "./proxy.js";
@@ -45,7 +45,7 @@ export async function launch(options: LaunchOptions = {}): Promise<Browser> {
executablePath: binaryPath, executablePath: binaryPath,
headless: options.headless ?? true, headless: options.headless ?? true,
args, args,
ignoreDefaultArgs: ["--enable-automation"], ignoreDefaultArgs: IGNORE_DEFAULT_ARGS,
...(options.proxy ...(options.proxy
? { proxy: typeof options.proxy === "string" ? parseProxyUrl(options.proxy) : options.proxy } ? { proxy: typeof options.proxy === "string" ? parseProxyUrl(options.proxy) : options.proxy }
: {}), : {}),
@@ -163,7 +163,7 @@ export async function launchPersistentContext(
executablePath: binaryPath, executablePath: binaryPath,
headless: options.headless ?? true, headless: options.headless ?? true,
args, args,
ignoreDefaultArgs: ["--enable-automation"], ignoreDefaultArgs: IGNORE_DEFAULT_ARGS,
...(options.proxy ...(options.proxy
? { proxy: typeof options.proxy === "string" ? parseProxyUrl(options.proxy) : options.proxy } ? { proxy: typeof options.proxy === "string" ? parseProxyUrl(options.proxy) : options.proxy }
: {}), : {}),
+2 -1
View File
@@ -5,6 +5,7 @@
import type { Browser } from "puppeteer-core"; import type { Browser } from "puppeteer-core";
import type { LaunchOptions } from "./types.js"; import type { LaunchOptions } from "./types.js";
import { IGNORE_DEFAULT_ARGS } from "./config.js";
import { buildArgs } from "./args.js"; import { buildArgs } from "./args.js";
import { ensureBinary } from "./download.js"; import { ensureBinary } from "./download.js";
import { parseProxyUrl } from "./proxy.js"; import { parseProxyUrl } from "./proxy.js";
@@ -62,7 +63,7 @@ export async function launch(options: LaunchOptions = {}): Promise<Browser> {
executablePath: binaryPath, executablePath: binaryPath,
headless: options.headless ?? true, headless: options.headless ?? true,
args, args,
ignoreDefaultArgs: ["--enable-automation"], ignoreDefaultArgs: IGNORE_DEFAULT_ARGS,
...options.launchOptions, ...options.launchOptions,
}); });
+3
View File
@@ -58,6 +58,9 @@ geoip = ["geoip2>=4.0"]
patchright = ["patchright>=1.40"] patchright = ["patchright>=1.40"]
dev = ["pytest>=7.0", "pytest-asyncio>=0.23"] dev = ["pytest>=7.0", "pytest-asyncio>=0.23"]
[project.scripts]
cloakbrowser = "cloakbrowser.__main__:main"
[project.urls] [project.urls]
Homepage = "https://github.com/CloakHQ/CloakBrowser" Homepage = "https://github.com/CloakHQ/CloakBrowser"
Documentation = "https://github.com/CloakHQ/CloakBrowser#readme" Documentation = "https://github.com/CloakHQ/CloakBrowser#readme"