mirror of
https://github.com/feder-cr/invisible_playwright.git
synced 2026-06-07 08:35:12 +02:00
invisible-playwright: a patched Firefox 150.0.1 for browser-fingerprint
stealth, shipped as a Playwright-compatible Python wrapper.
* Sync + async InvisiblePlaywright launcher (firefox_user_prefs, virtual
desktop on Windows, SOCKS5 auth via patched nsProtocolProxyService)
* fpforge: Bayesian fingerprint sampler over GPU / audio / fonts /
screen / ~400 other navigator fields
* WebRTC stealth: srflx address swap, synthetic srflx fallback,
private-LAN host candidates. No real public IP leak via STUN.
* GPU sandbox fix for FF150 alt-desktop regression
* Bezier-curve mouse motion baked into Juggler
Targets Windows x86_64 + Linux x86_64. Binary fetched on first run from
GitHub Release "firefox-1".
71 lines
2.7 KiB
Python
71 lines
2.7 KiB
Python
import hashlib
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
import responses
|
|
|
|
from invisible_playwright.download import ensure_binary
|
|
from invisible_playwright.constants import BINARY_VERSION
|
|
|
|
|
|
def _make_zip(path: Path, inner_name: str, payload: bytes) -> bytes:
|
|
import io
|
|
import zipfile
|
|
buf = io.BytesIO()
|
|
with zipfile.ZipFile(buf, "w") as zf:
|
|
zf.writestr(inner_name, payload)
|
|
data = buf.getvalue()
|
|
path.write_bytes(data)
|
|
return data
|
|
|
|
|
|
@responses.activate
|
|
def test_ensure_binary_downloads_and_verifies(tmp_path, monkeypatch):
|
|
"""Full path: cache miss -> HTTP GET -> SHA256 check -> extract -> return path."""
|
|
cache = tmp_path / "cache"
|
|
monkeypatch.setattr("invisible_playwright.download.cache_root", lambda: cache)
|
|
|
|
archive_path = tmp_path / "archive.zip"
|
|
archive_bytes = _make_zip(archive_path, "firefox.exe", b"PEX!")
|
|
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
|
|
from invisible_playwright.constants import ARCHIVE_NAME
|
|
asset = ARCHIVE_NAME("win32", "AMD64")
|
|
|
|
url_archive = f"https://github.com/feder-cr/invisible_playwright/releases/download/{BINARY_VERSION}/{asset}"
|
|
url_sums = f"https://github.com/feder-cr/invisible_playwright/releases/download/{BINARY_VERSION}/checksums.txt"
|
|
|
|
responses.add(responses.GET, url_archive, body=archive_bytes, status=200,
|
|
content_type="application/zip")
|
|
responses.add(responses.GET, url_sums,
|
|
body=f"{archive_sha} {asset}\n", status=200)
|
|
|
|
monkeypatch.setattr("sys.platform", "win32")
|
|
import platform
|
|
monkeypatch.setattr(platform, "machine", lambda: "AMD64")
|
|
|
|
path = ensure_binary()
|
|
assert Path(path).exists()
|
|
assert Path(path).name == "firefox.exe"
|
|
|
|
|
|
@responses.activate
|
|
def test_ensure_binary_rejects_sha_mismatch(tmp_path, monkeypatch):
|
|
cache = tmp_path / "cache"
|
|
monkeypatch.setattr("invisible_playwright.download.cache_root", lambda: cache)
|
|
archive_path = tmp_path / "archive.zip"
|
|
archive_bytes = _make_zip(archive_path, "firefox.exe", b"PEX!")
|
|
wrong_sha = "0" * 64
|
|
from invisible_playwright.constants import ARCHIVE_NAME
|
|
asset = ARCHIVE_NAME("win32", "AMD64")
|
|
|
|
url_archive = f"https://github.com/feder-cr/invisible_playwright/releases/download/{BINARY_VERSION}/{asset}"
|
|
url_sums = f"https://github.com/feder-cr/invisible_playwright/releases/download/{BINARY_VERSION}/checksums.txt"
|
|
responses.add(responses.GET, url_archive, body=archive_bytes, status=200)
|
|
responses.add(responses.GET, url_sums, body=f"{wrong_sha} {asset}\n", status=200)
|
|
|
|
monkeypatch.setattr("sys.platform", "win32")
|
|
import platform
|
|
monkeypatch.setattr(platform, "machine", lambda: "AMD64")
|
|
|
|
with pytest.raises(RuntimeError, match="SHA256"):
|
|
ensure_binary()
|