mirror of
https://github.com/CloakHQ/CloakBrowser.git
synced 2026-06-23 11:41:46 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1315ebcaf6 | ||
|
|
5d7f7360d8 | ||
|
|
4e95822446 | ||
|
|
408a582117 | ||
|
|
fe567d7a5a |
@@ -6,6 +6,32 @@ Changes are tagged: **[wrapper]** for Python/JS wrapper, **[binary]** for Chromi
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [0.3.4] — 2026-03-04
|
||||||
|
|
||||||
|
Binary v14: auto-spoof restored with seed, wrapper simplified to match.
|
||||||
|
|
||||||
|
- **[binary]** Restore full auto-spoof when `--fingerprint=seed` is set — all randomized properties now derive from the seed consistently
|
||||||
|
- **[binary]** Auto-inject random fingerprint seed at startup if none provided. Binary is stealthy with zero flags
|
||||||
|
- **[binary]** 26 source-level C++ patches (up from 25)
|
||||||
|
- **[wrapper]** Simplify default stealth args — remove flags the binary now auto-generates. Wrapper still sets platform profile on Linux and `--no-sandbox`
|
||||||
|
- **[wrapper]** Fix timezone in `launch_context()` — use Playwright's per-context timezone instead of binary flag, fixing mismatch when creating new browser contexts with geoip
|
||||||
|
- **[wrapper]** Clarify README platform detection behavior
|
||||||
|
|
||||||
|
## [0.3.3] — 2026-03-03
|
||||||
|
|
||||||
|
All platforms now run Chromium 145 v2 with 25 patches. Windows x64 added.
|
||||||
|
|
||||||
|
- **[binary]** Auto-spoof by default — binary is stealthy with zero flags. Random fingerprint seed auto-generated at startup, no wrapper or configuration required
|
||||||
|
- **[binary]** Platform-aware auto-detection — GPU, screen dimensions, and User-Agent automatically match the real OS (macOS, Linux, Windows) without explicit flags
|
||||||
|
- **[binary]** Expanded GPU model database for realistic per-session diversity
|
||||||
|
- **[binary]** First macOS v145 builds (arm64 + x64) — 25 patches, up from 16 on v142
|
||||||
|
- **[binary]** First Windows x64 v145 build — 25 patches
|
||||||
|
- **[wrapper]** Add Windows x64 platform support — auto-download, binary path resolution, and platform detection
|
||||||
|
- **[wrapper]** Upgrade macOS (arm64 + x64) from Chromium 142 to 145 — all platforms now ship the same 25-patch build
|
||||||
|
- **[wrapper]** Add explicit Mac GPU flags (`Apple M3 Metal` renderer) to default stealth args for consistent WebGL fingerprints
|
||||||
|
- **[wrapper]** Improve reCAPTCHA stealth test — wait for score element instead of blind sleep
|
||||||
|
- **[wrapper]** JS: add `win32-x64` platform mapping, Windows binary path (`chrome.exe`)
|
||||||
|
|
||||||
## [0.3.1] — 2026-03-03
|
## [0.3.1] — 2026-03-03
|
||||||
|
|
||||||
- **[wrapper]** Auto-check for wrapper updates on startup (PyPI/npm). Notifies users when a newer wrapper version is available. Runs once per process, respects `CLOAKBROWSER_AUTO_UPDATE=false`.
|
- **[wrapper]** Auto-check for wrapper updates on startup (PyPI/npm). Notifies users when a newer wrapper version is available. Runs once per process, respects `CLOAKBROWSER_AUTO_UPDATE=false`.
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ Drop-in Playwright/Puppeteer replacement for Python and JavaScript.<br>
|
|||||||
Same API, same code — just swap the import. <strong>3 lines of code, 30 seconds to unblock.</strong>
|
Same API, same code — just swap the import. <strong>3 lines of code, 30 seconds to unblock.</strong>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
- 🔒 **25 source-level C++ patches** — not JS injection, not config flags
|
- 🔒 **26 source-level C++ patches** — not JS injection, not config flags
|
||||||
- 🛡️ **CDP stealth built-in** — uses [Patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright) to reduce Playwright's automation footprint
|
- 🛡️ **CDP stealth built-in** — uses [Patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright) to reduce Playwright's automation footprint
|
||||||
- 🎯 **0.9 reCAPTCHA v3 score** — human-level, server-verified
|
- 🎯 **0.9 reCAPTCHA v3 score** — human-level, server-verified
|
||||||
- ☁️ **Passes Cloudflare Turnstile**, FingerprintJS, BrowserScan — 30/30 tests
|
- ☁️ **Passes Cloudflare Turnstile**, FingerprintJS, BrowserScan — 30/30 tests
|
||||||
@@ -104,14 +104,16 @@ 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.
|
||||||
|
|
||||||
## What's New in v0.3.0
|
## What's New in v0.3.4
|
||||||
|
|
||||||
- **Chromium 145** (Linux) — latest stable, 25 fingerprint patches (up from 16). macOS v145 coming soon
|
- **All 4 platforms** — Linux x64, macOS arm64, macOS x64, and Windows x64 all on Chromium 145
|
||||||
- **9 new patches** — screen dimensions, device memory, audio, WebGL, and more
|
- **26 fingerprint patches** — 10 new patches since v142 (screen, device memory, audio, WebGL, auto-spoof, and more)
|
||||||
- **SHA-256 checksum verification** — binary downloads are verified for integrity
|
- **Stealthy with zero flags** — binary auto-generates a random fingerprint seed at startup. No configuration required
|
||||||
- **CDP hardening** — audited and patched known automation detection vectors
|
- **Deterministic seeds** — `--fingerprint=seed` produces the same identity across launches for session persistence
|
||||||
- **Full stealth audit** — every patch reviewed for detection vectors, multiple fixes shipped
|
- **Full stealth audit** — every patch reviewed for detection vectors, multiple fixes shipped
|
||||||
- **Timezone & locale from proxy IP** — `launch(proxy="...", geoip=True)` auto-detects timezone and locale
|
- **Timezone & locale from proxy IP** — `launch(proxy="...", geoip=True)` auto-detects timezone and locale
|
||||||
|
- **SHA-256 checksum verification** — binary downloads are verified for integrity
|
||||||
|
- **CDP hardening** — audited and patched known automation detection vectors
|
||||||
|
|
||||||
See the full [CHANGELOG.md](CHANGELOG.md) for details.
|
See the full [CHANGELOG.md](CHANGELOG.md) for details.
|
||||||
|
|
||||||
@@ -175,11 +177,11 @@ All tests verified against live detection services. Last tested: Mar 2026 (Chrom
|
|||||||
CloakBrowser is a thin wrapper (Python + JavaScript) around a custom-built Chromium binary:
|
CloakBrowser is a thin wrapper (Python + JavaScript) around a custom-built Chromium binary:
|
||||||
|
|
||||||
1. **You install** → `pip install cloakbrowser` or `npm install cloakbrowser`
|
1. **You install** → `pip install cloakbrowser` or `npm install cloakbrowser`
|
||||||
2. **First launch** → binary auto-downloads for your platform (Linux x64: Chromium 145, macOS: Chromium 142)
|
2. **First launch** → binary auto-downloads for your platform (Chromium 145)
|
||||||
3. **Every launch** → Playwright or Puppeteer starts with our binary + stealth args
|
3. **Every launch** → Playwright or Puppeteer starts with our binary + stealth args
|
||||||
4. **You write code** → standard Playwright/Puppeteer API, nothing new to learn
|
4. **You write code** → standard Playwright/Puppeteer API, nothing new to learn
|
||||||
|
|
||||||
The binary includes 25 source-level patches covering canvas, WebGL, audio, fonts, GPU, screen properties, hardware reporting, and automation signal removal.
|
The binary includes 26 source-level patches covering canvas, WebGL, audio, fonts, GPU, screen properties, hardware reporting, and automation signal removal.
|
||||||
|
|
||||||
These are compiled into the Chromium binary — not injected via JavaScript, not set via flags.
|
These are compiled into the Chromium binary — not injected via JavaScript, not set via flags.
|
||||||
|
|
||||||
@@ -202,7 +204,7 @@ browser = launch(headless=False)
|
|||||||
browser = launch(proxy="http://user:pass@proxy:8080")
|
browser = launch(proxy="http://user:pass@proxy:8080")
|
||||||
|
|
||||||
# With extra Chrome args
|
# With extra Chrome args
|
||||||
browser = launch(args=["--disable-gpu", "--window-size=1920,1080"])
|
browser = launch(args=["--disable-gpu"])
|
||||||
|
|
||||||
# With timezone and locale (sets both binary flags and Playwright context)
|
# With timezone and locale (sets both binary flags and Playwright context)
|
||||||
browser = launch(timezone="America/New_York", locale="en-US")
|
browser = launch(timezone="America/New_York", locale="en-US")
|
||||||
@@ -283,7 +285,7 @@ const browser = await launch();
|
|||||||
const browser = await launch({
|
const browser = await launch({
|
||||||
headless: false,
|
headless: false,
|
||||||
proxy: 'http://user:pass@proxy:8080',
|
proxy: 'http://user:pass@proxy:8080',
|
||||||
args: ['--window-size=1920,1080'],
|
args: ['--fingerprint=12345'],
|
||||||
timezone: 'America/New_York',
|
timezone: 'America/New_York',
|
||||||
locale: 'en-US',
|
locale: 'en-US',
|
||||||
});
|
});
|
||||||
@@ -342,7 +344,17 @@ clearCache();
|
|||||||
|
|
||||||
## Fingerprint Management
|
## Fingerprint Management
|
||||||
|
|
||||||
Every launch automatically generates a **unique fingerprint**. A random seed (10000–99999) drives all seed-based patches — canvas, WebGL, audio, fonts, and client rects all produce consistent, correlated values derived from that single seed.
|
The binary is **stealthy by default** — no flags needed. It auto-generates a random fingerprint seed at startup and spoofs all detectable values (GPU, hardware specs, screen dimensions, canvas, WebGL, audio, fonts). Every launch produces a fresh, coherent identity.
|
||||||
|
|
||||||
|
**How fingerprinting works:**
|
||||||
|
|
||||||
|
| Scenario | What happens |
|
||||||
|
|----------|-------------|
|
||||||
|
| **No flags** | Random seed auto-generated at startup. GPU, screen, hardware specs, and all noise patches are spoofed automatically. Fresh identity each launch. |
|
||||||
|
| **`--fingerprint=seed`** | Deterministic identity from the seed. Same seed = same fingerprint across launches. Use this for session persistence (returning visitor). |
|
||||||
|
| **`--fingerprint=seed` + explicit flags** | Explicit flags override individual auto-generated values. The seed fills in everything else. |
|
||||||
|
|
||||||
|
The binary detects its platform at compile time — a macOS binary reports as macOS with Apple GPU, a Linux binary reports as Linux with NVIDIA GPU. The **wrapper** overrides this on Linux by passing `--fingerprint-platform=windows`, so sessions appear as Windows desktops (more common fingerprint, harder to cluster). Use `--fingerprint-platform` for cross-platform spoofing when running the binary directly.
|
||||||
|
|
||||||
> **Tip: Use a fixed seed when revisiting the same site.** A random seed makes every session look like a different device — which can be suspicious when hitting the same site repeatedly from the same IP. For reCAPTCHA v3 Enterprise and similar scoring systems, a fixed seed produces a consistent fingerprint across sessions, making you look like a returning visitor:
|
> **Tip: Use a fixed seed when revisiting the same site.** A random seed makes every session look like a different device — which can be suspicious when hitting the same site repeatedly from the same IP. For reCAPTCHA v3 Enterprise and similar scoring systems, a fixed seed produces a consistent fingerprint across sessions, making you look like a returning visitor:
|
||||||
> ```python
|
> ```python
|
||||||
@@ -354,21 +366,20 @@ Every launch automatically generates a **unique fingerprint**. A random seed (10
|
|||||||
|
|
||||||
### Default Fingerprint
|
### Default Fingerprint
|
||||||
|
|
||||||
Every `launch()` call sets these automatically. Defaults are **platform-aware** — macOS runs as a native Mac browser, Linux spoofs Windows:
|
Every `launch()` call sets these automatically. The **wrapper** applies platform-aware defaults — on Linux it spoofs as Windows for a more common fingerprint, on macOS it runs as a native Mac browser:
|
||||||
|
|
||||||
| Flag | Linux Default | macOS Default | Controls |
|
| Flag | Linux/Windows Default | macOS Default | Controls |
|
||||||
|------|--------------|---------------|----------|
|
|------|--------------|---------------|----------|
|
||||||
| `--fingerprint` | Random (10000–99999) | Random (10000–99999) | Master seed for canvas, WebGL, audio, fonts, client rects |
|
| `--fingerprint` | Random (10000–99999) | Random (10000–99999) | Master seed for canvas, WebGL, audio, fonts, client rects |
|
||||||
| `--fingerprint-platform` | `windows` | `macos` | `navigator.platform`, User-Agent OS, GPU pool selection |
|
| `--fingerprint-platform` | `windows` | `macos` | `navigator.platform`, User-Agent OS, GPU pool selection |
|
||||||
| `--fingerprint-hardware-concurrency` | `8` | *(not set — uses real value)* | `navigator.hardwareConcurrency` |
|
| `--fingerprint-gpu-vendor` | `NVIDIA Corporation` | `Google Inc. (Apple)` | WebGL `UNMASKED_VENDOR_WEBGL` |
|
||||||
| `--fingerprint-gpu-vendor` | `NVIDIA Corporation` | *(not set — native Apple GPU)* | WebGL `UNMASKED_VENDOR_WEBGL` |
|
| `--fingerprint-gpu-renderer` | `NVIDIA GeForce RTX 3070` | `ANGLE (Apple, ANGLE Metal Renderer: Apple M3, Unspecified Version)` | WebGL `UNMASKED_RENDERER_WEBGL` |
|
||||||
| `--fingerprint-gpu-renderer` | `NVIDIA GeForce RTX 3070` | *(not set — native Metal renderer)* | WebGL `UNMASKED_RENDERER_WEBGL` |
|
|
||||||
| `--fingerprint-device-memory` | `8` | *(not set)* | `navigator.deviceMemory` |
|
|
||||||
| `--fingerprint-screen-width` | `1920` | *(not set)* | Screen width reporting |
|
|
||||||
| `--fingerprint-screen-height` | `1080` | *(not set)* | Screen height reporting |
|
|
||||||
| `--window-size` | `1920,1080` | *(not set)* | Browser window dimensions |
|
|
||||||
|
|
||||||
> **Important:** `--fingerprint-platform` should always be set. Without it, platform-specific patches (GPU, UA, screen, taskbar) won't activate. The wrapper handles this automatically.
|
The binary auto-generates hardware concurrency (8), device memory (8), and screen dimensions (1920x1080 on Windows/Linux, 1440x900 on macOS) from the seed. Override with explicit flags if needed.
|
||||||
|
|
||||||
|
> **Using the binary directly?** It works out of the box with zero flags — the binary auto-spoofs everything. Pass `--fingerprint=seed` for a persistent identity, or use explicit flags like `--fingerprint-gpu-renderer` to override any auto-generated value.
|
||||||
|
|
||||||
|
> **Production tip:** For better stealth at scale, pass your own GPU, screen, and hardware values instead of relying on defaults. Custom parameters make your sessions harder to cluster by anti-bot systems that look for uniform fingerprint profiles.
|
||||||
|
|
||||||
### Additional Flags
|
### Additional Flags
|
||||||
|
|
||||||
@@ -376,6 +387,10 @@ Supported by the binary but **not set by default** — pass via `args` to custom
|
|||||||
|
|
||||||
| Flag | Controls |
|
| Flag | Controls |
|
||||||
|------|----------|
|
|------|----------|
|
||||||
|
| `--fingerprint-hardware-concurrency` | `navigator.hardwareConcurrency` (auto-generated: `8`) |
|
||||||
|
| `--fingerprint-device-memory` | `navigator.deviceMemory` in GB (auto-generated: `8`) |
|
||||||
|
| `--fingerprint-screen-width` | Screen width (auto-generated: `1920` Win/Linux, `1440` macOS) |
|
||||||
|
| `--fingerprint-screen-height` | Screen height (auto-generated: `1080` Win/Linux, `900` macOS) |
|
||||||
| `--fingerprint-brand` | Browser brand: `Chrome`, `Edge`, `Opera`, `Vivaldi` |
|
| `--fingerprint-brand` | Browser brand: `Chrome`, `Edge`, `Opera`, `Vivaldi` |
|
||||||
| `--fingerprint-brand-version` | Brand version (UA + Client Hints) |
|
| `--fingerprint-brand-version` | Brand version (UA + Client Hints) |
|
||||||
| `--fingerprint-platform-version` | Client Hints platform version |
|
| `--fingerprint-platform-version` | Client Hints platform version |
|
||||||
@@ -397,7 +412,6 @@ browser = launch(args=["--fingerprint=42069"])
|
|||||||
browser = launch(stealth_args=False, args=[
|
browser = launch(stealth_args=False, args=[
|
||||||
"--fingerprint=42069",
|
"--fingerprint=42069",
|
||||||
"--fingerprint-platform=windows",
|
"--fingerprint-platform=windows",
|
||||||
"--fingerprint-hardware-concurrency=8",
|
|
||||||
"--fingerprint-gpu-vendor=NVIDIA Corporation",
|
"--fingerprint-gpu-vendor=NVIDIA Corporation",
|
||||||
"--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070",
|
"--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070",
|
||||||
])
|
])
|
||||||
@@ -425,17 +439,15 @@ browser = launch(args=[
|
|||||||
|
|
||||||
| Platform | Chromium | Patches | Status |
|
| Platform | Chromium | Patches | Status |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| Linux x86_64 | 145 | 25 | ✅ Latest |
|
| Linux x86_64 | 145 | 26 | ✅ Latest |
|
||||||
| macOS arm64 (Apple Silicon) | 142 | 16 | ✅ Available (v145 coming soon) |
|
| macOS arm64 (Apple Silicon) | 145 | 26 | ✅ Latest |
|
||||||
| macOS x86_64 (Intel) | 142 | 16 | ✅ Available (v145 coming soon) |
|
| macOS x86_64 (Intel) | 145 | 26 | ✅ Latest |
|
||||||
| Windows | — | — | Planned |
|
| Windows x86_64 | 145 | 26 | ✅ Latest |
|
||||||
|
|
||||||
The wrapper auto-downloads the correct binary for your platform. Linux gets Chromium 145 with all 25 patches. macOS currently runs Chromium 142 (16 patches) — the v145 macOS build is in progress.
|
The wrapper auto-downloads the correct binary for your platform.
|
||||||
|
|
||||||
**macOS first launch:** The binary is ad-hoc signed. On first run, macOS Gatekeeper will block it. Right-click the app → **Open** → click **Open** in the dialog. This is only needed once.
|
**macOS first launch:** The binary is ad-hoc signed. On first run, macOS Gatekeeper will block it. Right-click the app → **Open** → click **Open** in the dialog. This is only needed once.
|
||||||
|
|
||||||
**On Windows?** You can still use CloakBrowser via Docker or with your own Chromium binary by setting `CLOAKBROWSER_BINARY_PATH=/path/to/chrome`.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
**Python** — see [`examples/`](examples/):
|
**Python** — see [`examples/`](examples/):
|
||||||
@@ -453,13 +465,12 @@ The wrapper auto-downloads the correct binary for your platform. Linux gets Chro
|
|||||||
|
|
||||||
| Feature | Status |
|
| Feature | Status |
|
||||||
|---------|--------|
|
|---------|--------|
|
||||||
| Linux x64 — Chromium 145 (25 patches) | ✅ Released |
|
| Linux x64 — Chromium 145 (26 patches) | ✅ Released |
|
||||||
| macOS arm64/x64 — Chromium 142 (16 patches) | ✅ Released |
|
| macOS arm64/x64 — Chromium 145 (26 patches) | ✅ Released |
|
||||||
| macOS arm64/x64 — Chromium 145 | 🔨 In progress |
|
| Windows x64 — Chromium 145 (26 patches) | ✅ Released |
|
||||||
| JavaScript/Puppeteer + Playwright support | ✅ Released |
|
| JavaScript/Puppeteer + Playwright support | ✅ Released |
|
||||||
| Fingerprint rotation per session | ✅ Released |
|
| Fingerprint rotation per session | ✅ Released |
|
||||||
| Built-in proxy rotation | 📋 Planned |
|
| Built-in proxy rotation | 📋 Planned |
|
||||||
| Windows support | 📋 Planned |
|
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
@@ -543,6 +554,13 @@ const browser = await launch({ args: ['--disable-http2'] });
|
|||||||
|
|
||||||
Only use this flag for sites that require it — most sites work fine with HTTP/2.
|
Only use this flag for sites that require it — most sites work fine with HTTP/2.
|
||||||
|
|
||||||
|
**Something not working? Make sure you're on the latest wrapper**
|
||||||
|
Older versions may use outdated stealth args or download an older binary:
|
||||||
|
```bash
|
||||||
|
pip install -U cloakbrowser # Python
|
||||||
|
npm install cloakbrowser@latest # JavaScript
|
||||||
|
```
|
||||||
|
|
||||||
**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
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.3.1"
|
__version__ = "0.3.4"
|
||||||
|
|||||||
@@ -198,8 +198,11 @@ def launch_context(
|
|||||||
# Resolve geoip BEFORE launch() to avoid double-resolution and ensure
|
# Resolve geoip BEFORE launch() to avoid double-resolution and ensure
|
||||||
# resolved values flow to both binary flags AND context params
|
# resolved values flow to both binary flags AND context params
|
||||||
timezone_id, locale = _maybe_resolve_geoip(geoip, proxy, timezone_id, locale)
|
timezone_id, locale = _maybe_resolve_geoip(geoip, proxy, timezone_id, locale)
|
||||||
|
# Skip --fingerprint-timezone binary flag: it only applies to the default
|
||||||
|
# context and interferes with Playwright's timezone_id on new contexts.
|
||||||
|
# Timezone is set via browser.new_context(timezone_id=...) below instead.
|
||||||
browser = launch(headless=headless, proxy=proxy, args=args, stealth_args=stealth_args,
|
browser = launch(headless=headless, proxy=proxy, args=args, stealth_args=stealth_args,
|
||||||
timezone=timezone_id, locale=locale)
|
timezone=None, locale=locale)
|
||||||
|
|
||||||
context_kwargs: dict[str, Any] = {}
|
context_kwargs: dict[str, Any] = {}
|
||||||
if user_agent:
|
if user_agent:
|
||||||
|
|||||||
+15
-13
@@ -11,8 +11,7 @@ from ._version import __version__
|
|||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Chromium version shipped with this release.
|
# Chromium version shipped with this release.
|
||||||
# Different platforms may ship different versions (e.g. Linux gets v145 first,
|
# Different platforms may ship different versions during transition periods.
|
||||||
# macOS stays on v142 until Mac builds are ready).
|
|
||||||
# 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.
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -20,8 +19,9 @@ CHROMIUM_VERSION = "145.0.7632.109"
|
|||||||
|
|
||||||
PLATFORM_CHROMIUM_VERSIONS: dict[str, str] = {
|
PLATFORM_CHROMIUM_VERSIONS: dict[str, str] = {
|
||||||
"linux-x64": "145.0.7632.109",
|
"linux-x64": "145.0.7632.109",
|
||||||
"darwin-arm64": "142.0.7444.175",
|
"darwin-arm64": "145.0.7632.109",
|
||||||
"darwin-x64": "142.0.7444.175",
|
"darwin-x64": "145.0.7632.109",
|
||||||
|
"windows-x64": "145.0.7632.109",
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -47,18 +47,17 @@ def get_default_stealth_args() -> list[str]:
|
|||||||
# Tell the fingerprint patches we're on macOS so GPU/UA match natively
|
# Tell the fingerprint patches we're on macOS so GPU/UA match natively
|
||||||
return base + [
|
return base + [
|
||||||
"--fingerprint-platform=macos",
|
"--fingerprint-platform=macos",
|
||||||
|
"--fingerprint-gpu-vendor=Google Inc. (Apple)",
|
||||||
|
"--fingerprint-gpu-renderer=ANGLE (Apple, ANGLE Metal Renderer: Apple M3, Unspecified Version)",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Linux: spoof as Windows
|
# Linux/Windows: Windows fingerprint profile
|
||||||
|
# Hardware concurrency, device memory, screen, and window size are
|
||||||
|
# auto-generated by the binary from the seed (v14+).
|
||||||
return base + [
|
return base + [
|
||||||
"--fingerprint-platform=windows",
|
"--fingerprint-platform=windows",
|
||||||
"--fingerprint-hardware-concurrency=8",
|
|
||||||
"--fingerprint-device-memory=8",
|
|
||||||
"--fingerprint-gpu-vendor=NVIDIA Corporation",
|
"--fingerprint-gpu-vendor=NVIDIA Corporation",
|
||||||
"--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070",
|
"--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070",
|
||||||
"--fingerprint-screen-width=1920",
|
|
||||||
"--fingerprint-screen-height=1080",
|
|
||||||
"--window-size=1920,1080",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -77,6 +76,8 @@ SUPPORTED_PLATFORMS: dict[tuple[str, str], str] = {
|
|||||||
("Linux", "aarch64"): "linux-arm64",
|
("Linux", "aarch64"): "linux-arm64",
|
||||||
("Darwin", "arm64"): "darwin-arm64",
|
("Darwin", "arm64"): "darwin-arm64",
|
||||||
("Darwin", "x86_64"): "darwin-x64",
|
("Darwin", "x86_64"): "darwin-x64",
|
||||||
|
("Windows", "AMD64"): "windows-x64",
|
||||||
|
("Windows", "x86_64"): "windows-x64",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Platforms with pre-built binaries available for download (derived from version map).
|
# Platforms with pre-built binaries available for download (derived from version map).
|
||||||
@@ -130,6 +131,8 @@ def get_binary_path(version: str | None = None) -> Path:
|
|||||||
if platform.system() == "Darwin":
|
if platform.system() == "Darwin":
|
||||||
# macOS: Chromium.app bundle
|
# macOS: Chromium.app bundle
|
||||||
return binary_dir / "Chromium.app" / "Contents" / "MacOS" / "Chromium"
|
return binary_dir / "Chromium.app" / "Contents" / "MacOS" / "Chromium"
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
return binary_dir / "chrome.exe"
|
||||||
else:
|
else:
|
||||||
# Linux: flat binary
|
# Linux: flat binary
|
||||||
return binary_dir / "chrome"
|
return binary_dir / "chrome"
|
||||||
@@ -148,9 +151,8 @@ def check_platform_available() -> None:
|
|||||||
available = ", ".join(sorted(AVAILABLE_PLATFORMS))
|
available = ", ".join(sorted(AVAILABLE_PLATFORMS))
|
||||||
import sys
|
import sys
|
||||||
sys.exit(
|
sys.exit(
|
||||||
f"\n\033[1mCloakBrowser\033[0m — Pre-built binaries are currently only available for: {available}.\n"
|
f"\n\033[1mCloakBrowser\033[0m — Pre-built binaries are currently only available for: {available}.\n\n"
|
||||||
f"Windows builds are coming soon.\n\n"
|
f"To use CloakBrowser now, set CLOAKBROWSER_BINARY_PATH to a local Chromium binary."
|
||||||
f"To use CloakBrowser now, run in Docker (see README) or set CLOAKBROWSER_BINARY_PATH."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -330,7 +330,9 @@ def _is_executable(path: Path) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
def _make_executable(path: Path) -> None:
|
def _make_executable(path: Path) -> None:
|
||||||
"""Make a file executable (chmod +x)."""
|
"""Make a file executable (chmod +x). Skipped on Windows (no-op / AV lock risk)."""
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
return
|
||||||
current = path.stat().st_mode
|
current = path.stat().st_mode
|
||||||
path.chmod(current | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
path.chmod(current | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||||
|
|
||||||
|
|||||||
@@ -143,11 +143,15 @@ def test_recaptcha(page):
|
|||||||
"""recaptcha-demo.appspot.com — Google's official reCAPTCHA v3 score."""
|
"""recaptcha-demo.appspot.com — Google's official reCAPTCHA v3 score."""
|
||||||
page.goto(
|
page.goto(
|
||||||
"https://recaptcha-demo.appspot.com/recaptcha-v3-request-scores.php",
|
"https://recaptcha-demo.appspot.com/recaptcha-v3-request-scores.php",
|
||||||
wait_until="networkidle",
|
wait_until="domcontentloaded",
|
||||||
timeout=30000,
|
timeout=30000,
|
||||||
)
|
)
|
||||||
# Page auto-submits via grecaptcha.execute() — wait for backend response
|
# Wait for backend response (step3 element appears when score arrives)
|
||||||
time.sleep(8)
|
try:
|
||||||
|
page.wait_for_selector("li.step3", timeout=20000)
|
||||||
|
time.sleep(1)
|
||||||
|
except Exception:
|
||||||
|
time.sleep(10) # fallback
|
||||||
|
|
||||||
results = page.evaluate("""() => {
|
results = page.evaluate("""() => {
|
||||||
const text = document.body.innerText;
|
const text = document.body.innerText;
|
||||||
|
|||||||
+3
-5
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
Drop-in Playwright/Puppeteer replacement. Same API — just swap the import. Scores **0.9 on reCAPTCHA v3**, passes **Cloudflare Turnstile**, and clears **30/30** stealth detection tests.
|
Drop-in Playwright/Puppeteer replacement. Same API — just swap the import. Scores **0.9 on reCAPTCHA v3**, passes **Cloudflare Turnstile**, and clears **30/30** stealth detection tests.
|
||||||
|
|
||||||
- 🔒 **25 source-level C++ patches** — not JS injection, not config flags
|
- 🔒 **26 source-level C++ patches** — not JS injection, not config flags
|
||||||
- 🎯 **0.9 reCAPTCHA v3 score** — human-level, server-verified
|
- 🎯 **0.9 reCAPTCHA v3 score** — human-level, server-verified
|
||||||
- ☁️ **Passes Cloudflare Turnstile**, FingerprintJS, BrowserScan — 30/30 tests
|
- ☁️ **Passes Cloudflare Turnstile**, FingerprintJS, BrowserScan — 30/30 tests
|
||||||
- 🔄 **Drop-in replacement** — works with both Playwright and Puppeteer
|
- 🔄 **Drop-in replacement** — works with both Playwright and Puppeteer
|
||||||
@@ -72,7 +72,7 @@ const browser = await launch({ headless: false });
|
|||||||
|
|
||||||
// Extra Chrome args
|
// Extra Chrome args
|
||||||
const browser = await launch({
|
const browser = await launch({
|
||||||
args: ['--window-size=1920,1080'],
|
args: ['--fingerprint=12345'],
|
||||||
});
|
});
|
||||||
|
|
||||||
// With timezone and locale (sets --fingerprint-timezone and --lang binary flags)
|
// With timezone and locale (sets --fingerprint-timezone and --lang binary flags)
|
||||||
@@ -176,9 +176,7 @@ const page = await browser.newPage();
|
|||||||
| Linux x86_64 | ✅ Available |
|
| Linux x86_64 | ✅ Available |
|
||||||
| macOS arm64 (Apple Silicon) | ✅ Available |
|
| macOS arm64 (Apple Silicon) | ✅ Available |
|
||||||
| macOS x86_64 (Intel) | ✅ Available |
|
| macOS x86_64 (Intel) | ✅ Available |
|
||||||
| Windows | Planned |
|
| Windows x86_64 | ✅ Available |
|
||||||
|
|
||||||
**On Windows?** You can still use CloakBrowser via Docker or with your own Chromium binary by setting `CLOAKBROWSER_BINARY_PATH=/path/to/chrome`.
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cloakbrowser",
|
"name": "cloakbrowser",
|
||||||
"version": "0.3.1",
|
"version": "0.3.4",
|
||||||
"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",
|
||||||
|
|||||||
+20
-14
@@ -23,8 +23,7 @@ export { WRAPPER_VERSION };
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Chromium version shipped with this release.
|
// Chromium version shipped with this release.
|
||||||
// Different platforms may ship different versions (e.g. Linux gets v145 first,
|
// Different platforms may ship different versions during transition periods.
|
||||||
// macOS stays on v142 until Mac builds are ready).
|
|
||||||
// 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.
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -32,8 +31,9 @@ export const CHROMIUM_VERSION = "145.0.7632.109";
|
|||||||
|
|
||||||
export const PLATFORM_CHROMIUM_VERSIONS: Record<string, string> = {
|
export const PLATFORM_CHROMIUM_VERSIONS: Record<string, string> = {
|
||||||
"linux-x64": "145.0.7632.109",
|
"linux-x64": "145.0.7632.109",
|
||||||
"darwin-arm64": "142.0.7444.175",
|
"darwin-arm64": "145.0.7632.109",
|
||||||
"darwin-x64": "142.0.7444.175",
|
"darwin-x64": "145.0.7632.109",
|
||||||
|
"windows-x64": "145.0.7632.109",
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -44,6 +44,7 @@ const SUPPORTED_PLATFORMS: Record<string, string> = {
|
|||||||
"linux-arm64": "linux-arm64",
|
"linux-arm64": "linux-arm64",
|
||||||
"darwin-arm64": "darwin-arm64",
|
"darwin-arm64": "darwin-arm64",
|
||||||
"darwin-x64": "darwin-x64",
|
"darwin-x64": "darwin-x64",
|
||||||
|
"win32-x64": "windows-x64",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Platforms with pre-built binaries available for download (derived from version map).
|
// Platforms with pre-built binaries available for download (derived from version map).
|
||||||
@@ -64,6 +65,7 @@ export function getPlatformTag(): string {
|
|||||||
else if (platform === "linux" && arch === "arm64") key = "linux-arm64";
|
else if (platform === "linux" && arch === "arm64") key = "linux-arm64";
|
||||||
else if (platform === "darwin" && arch === "arm64") key = "darwin-arm64";
|
else if (platform === "darwin" && arch === "arm64") key = "darwin-arm64";
|
||||||
else if (platform === "darwin" && arch === "x64") key = "darwin-x64";
|
else if (platform === "darwin" && arch === "x64") key = "darwin-x64";
|
||||||
|
else if (platform === "win32" && arch === "x64") key = "win32-x64";
|
||||||
else {
|
else {
|
||||||
const supported = Object.values(SUPPORTED_PLATFORMS).join(", ");
|
const supported = Object.values(SUPPORTED_PLATFORMS).join(", ");
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -92,6 +94,9 @@ export function getBinaryPath(version?: string): string {
|
|||||||
if (process.platform === "darwin") {
|
if (process.platform === "darwin") {
|
||||||
return path.join(binaryDir, "Chromium.app", "Contents", "MacOS", "Chromium");
|
return path.join(binaryDir, "Chromium.app", "Contents", "MacOS", "Chromium");
|
||||||
}
|
}
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
return path.join(binaryDir, "chrome.exe");
|
||||||
|
}
|
||||||
return path.join(binaryDir, "chrome");
|
return path.join(binaryDir, "chrome");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +107,8 @@ export function checkPlatformAvailable(): void {
|
|||||||
if (!AVAILABLE_PLATFORMS.has(tag)) {
|
if (!AVAILABLE_PLATFORMS.has(tag)) {
|
||||||
const available = [...AVAILABLE_PLATFORMS].sort().join(", ");
|
const available = [...AVAILABLE_PLATFORMS].sort().join(", ");
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`CloakBrowser — Pre-built binaries are currently only available for: ${available}.\n` +
|
`CloakBrowser — Pre-built binaries are currently only available for: ${available}.\n\n` +
|
||||||
`Windows builds are coming soon.\n\n` +
|
`To use CloakBrowser now, set CLOAKBROWSER_BINARY_PATH to a local Chromium binary.`
|
||||||
`To use CloakBrowser now, run in Docker (see README) or set CLOAKBROWSER_BINARY_PATH.`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,19 +202,21 @@ export function getDefaultStealthArgs(): string[] {
|
|||||||
|
|
||||||
if (isMac) {
|
if (isMac) {
|
||||||
// macOS: run as native Mac browser — GPU/UA match natively
|
// macOS: run as native Mac browser — GPU/UA match natively
|
||||||
return [...base, "--fingerprint-platform=macos"];
|
return [
|
||||||
|
...base,
|
||||||
|
"--fingerprint-platform=macos",
|
||||||
|
"--fingerprint-gpu-vendor=Google Inc. (Apple)",
|
||||||
|
"--fingerprint-gpu-renderer=ANGLE (Apple, ANGLE Metal Renderer: Apple M3, Unspecified Version)",
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linux: spoof as Windows
|
// Linux/Windows: spoof as Windows desktop
|
||||||
|
// Hardware concurrency, device memory, screen, and window size are
|
||||||
|
// auto-generated by the binary from the seed (v14+).
|
||||||
return [
|
return [
|
||||||
...base,
|
...base,
|
||||||
"--fingerprint-platform=windows",
|
"--fingerprint-platform=windows",
|
||||||
"--fingerprint-hardware-concurrency=8",
|
|
||||||
"--fingerprint-device-memory=8",
|
|
||||||
"--fingerprint-gpu-vendor=NVIDIA Corporation",
|
"--fingerprint-gpu-vendor=NVIDIA Corporation",
|
||||||
"--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070",
|
"--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070",
|
||||||
"--fingerprint-screen-width=1920",
|
|
||||||
"--fingerprint-screen-height=1080",
|
|
||||||
"--window-size=1920,1080",
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -363,9 +363,9 @@ async function extractArchive(
|
|||||||
// Flatten single subdirectory if needed
|
// Flatten single subdirectory if needed
|
||||||
flattenSingleSubdir(destDir);
|
flattenSingleSubdir(destDir);
|
||||||
|
|
||||||
// Make binary executable
|
// Make binary executable (skip on Windows — no-op / AV lock risk)
|
||||||
const bp = binaryPath || getBinaryPath();
|
const bp = binaryPath || getBinaryPath();
|
||||||
if (fs.existsSync(bp)) {
|
if (process.platform !== "win32" && fs.existsSync(bp)) {
|
||||||
fs.chmodSync(bp, 0o755);
|
fs.chmodSync(bp, 0o755);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ describe("binaryInfo", () => {
|
|||||||
const info = binaryInfo();
|
const info = binaryInfo();
|
||||||
|
|
||||||
expect(info.version).toBe(getChromiumVersion());
|
expect(info.version).toBe(getChromiumVersion());
|
||||||
expect(info.platform).toMatch(/^(linux|darwin)-(x64|arm64)$/);
|
expect(info.platform).toMatch(/^(linux|darwin|windows)-(x64|arm64)$/);
|
||||||
expect(info.binaryPath).toBeTruthy();
|
expect(info.binaryPath).toBeTruthy();
|
||||||
expect(typeof info.installed).toBe("boolean");
|
expect(typeof info.installed).toBe("boolean");
|
||||||
expect(info.cacheDir).toContain("cloakbrowser");
|
expect(info.cacheDir).toContain("cloakbrowser");
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ describe("latest version (platform-aware)", () => {
|
|||||||
{
|
{
|
||||||
tag_name: "chromium-v145.0.7718.0",
|
tag_name: "chromium-v145.0.7718.0",
|
||||||
draft: false,
|
draft: false,
|
||||||
assets: makeAssets(["linux-x64", "darwin-arm64", "darwin-x64"]),
|
assets: makeAssets(["linux-x64", "darwin-arm64", "darwin-x64", "windows-x64"]),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expect(await getLatestChromiumVersion()).toBe("145.0.7718.0");
|
expect(await getLatestChromiumVersion()).toBe("145.0.7718.0");
|
||||||
@@ -116,7 +116,7 @@ describe("latest version (platform-aware)", () => {
|
|||||||
{
|
{
|
||||||
tag_name: "chromium-v142.0.7444.175",
|
tag_name: "chromium-v142.0.7444.175",
|
||||||
draft: false,
|
draft: false,
|
||||||
assets: makeAssets(["linux-x64", "darwin-arm64", "darwin-x64"]),
|
assets: makeAssets(["linux-x64", "darwin-arm64", "darwin-x64", "windows-x64"]),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const result = await getLatestChromiumVersion();
|
const result = await getLatestChromiumVersion();
|
||||||
@@ -133,14 +133,14 @@ describe("latest version (platform-aware)", () => {
|
|||||||
{
|
{
|
||||||
tag_name: "chromium-v145.0.7718.0",
|
tag_name: "chromium-v145.0.7718.0",
|
||||||
draft: false,
|
draft: false,
|
||||||
assets: [{ name: "cloakbrowser-windows-x64.tar.gz" }],
|
assets: [{ name: "cloakbrowser-freebsd-x64.tar.gz" }],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expect(await getLatestChromiumVersion()).toBeNull();
|
expect(await getLatestChromiumVersion()).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips draft releases", async () => {
|
it("skips draft releases", async () => {
|
||||||
const all = ["linux-x64", "darwin-arm64", "darwin-x64"];
|
const all = ["linux-x64", "darwin-arm64", "darwin-x64", "windows-x64"];
|
||||||
mockFetch([
|
mockFetch([
|
||||||
{ tag_name: "chromium-v999.0.0.0", draft: true, assets: makeAssets(all) },
|
{ tag_name: "chromium-v999.0.0.0", draft: true, assets: makeAssets(all) },
|
||||||
{ tag_name: "chromium-v145.0.7718.0", draft: false, assets: makeAssets(all) },
|
{ tag_name: "chromium-v145.0.7718.0", draft: false, assets: makeAssets(all) },
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ class TestGetLatestVersion:
|
|||||||
{
|
{
|
||||||
"tag_name": "chromium-v145.0.7718.0",
|
"tag_name": "chromium-v145.0.7718.0",
|
||||||
"draft": False,
|
"draft": False,
|
||||||
"assets": self._make_assets(["linux-x64", "darwin-arm64", "darwin-x64"]),
|
"assets": self._make_assets(["linux-x64", "darwin-arm64", "darwin-x64", "windows-x64"]),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
mock_response.raise_for_status = MagicMock()
|
mock_response.raise_for_status = MagicMock()
|
||||||
@@ -187,7 +187,7 @@ class TestGetLatestVersion:
|
|||||||
{
|
{
|
||||||
"tag_name": "chromium-v142.0.7444.175",
|
"tag_name": "chromium-v142.0.7444.175",
|
||||||
"draft": False,
|
"draft": False,
|
||||||
"assets": self._make_assets(["linux-x64", "darwin-arm64", "darwin-x64"]),
|
"assets": self._make_assets(["linux-x64", "darwin-arm64", "darwin-x64", "windows-x64"]),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
mock_response.raise_for_status = MagicMock()
|
mock_response.raise_for_status = MagicMock()
|
||||||
@@ -202,7 +202,7 @@ class TestGetLatestVersion:
|
|||||||
|
|
||||||
def test_skips_draft_releases(self):
|
def test_skips_draft_releases(self):
|
||||||
mock_response = MagicMock()
|
mock_response = MagicMock()
|
||||||
all_platforms = ["linux-x64", "darwin-arm64", "darwin-x64"]
|
all_platforms = ["linux-x64", "darwin-arm64", "darwin-x64", "windows-x64"]
|
||||||
mock_response.json.return_value = [
|
mock_response.json.return_value = [
|
||||||
{"tag_name": "chromium-v999.0.0.0", "draft": True, "assets": self._make_assets(all_platforms)},
|
{"tag_name": "chromium-v999.0.0.0", "draft": True, "assets": self._make_assets(all_platforms)},
|
||||||
{"tag_name": "chromium-v145.0.7718.0", "draft": False, "assets": self._make_assets(all_platforms)},
|
{"tag_name": "chromium-v145.0.7718.0", "draft": False, "assets": self._make_assets(all_platforms)},
|
||||||
@@ -215,7 +215,7 @@ class TestGetLatestVersion:
|
|||||||
|
|
||||||
def test_skips_non_chromium_tags(self):
|
def test_skips_non_chromium_tags(self):
|
||||||
mock_response = MagicMock()
|
mock_response = MagicMock()
|
||||||
all_platforms = ["linux-x64", "darwin-arm64", "darwin-x64"]
|
all_platforms = ["linux-x64", "darwin-arm64", "darwin-x64", "windows-x64"]
|
||||||
mock_response.json.return_value = [
|
mock_response.json.return_value = [
|
||||||
{"tag_name": "v0.2.0", "draft": False, "assets": self._make_assets(all_platforms)},
|
{"tag_name": "v0.2.0", "draft": False, "assets": self._make_assets(all_platforms)},
|
||||||
{"tag_name": "chromium-v145.0.7718.0", "draft": False, "assets": self._make_assets(all_platforms)},
|
{"tag_name": "chromium-v145.0.7718.0", "draft": False, "assets": self._make_assets(all_platforms)},
|
||||||
@@ -233,7 +233,7 @@ class TestGetLatestVersion:
|
|||||||
{
|
{
|
||||||
"tag_name": "chromium-v145.0.7718.0",
|
"tag_name": "chromium-v145.0.7718.0",
|
||||||
"draft": False,
|
"draft": False,
|
||||||
"assets": [{"name": "cloakbrowser-windows-x64.tar.gz"}],
|
"assets": [{"name": "cloakbrowser-freebsd-x64.tar.gz"}],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
mock_response.raise_for_status = MagicMock()
|
mock_response.raise_for_status = MagicMock()
|
||||||
|
|||||||
Reference in New Issue
Block a user