mirror of
https://github.com/daijro/camoufox.git
synced 2026-08-21 00:01:07 +00:00
Exclude virtual displays from the display clamp
headless='virtual' reaches launch_options as headless=False with virtual_display set (async_api rewrites it), so the headful gate fired and clamped the fingerprint to Xvfb's 1x1 stub. fix_screen_no_taskbar then drove availHeight to -39 and validate_config rejected the launch outright.
This commit is contained in:
committed by
Jake Writer
parent
2266f27501
commit
fbafbcf9f0
@@ -705,11 +705,11 @@ def launch_options(
|
||||
if not _user_set_navigator:
|
||||
fix_navigator_arch(config, target_os)
|
||||
if not _user_set_screen_window:
|
||||
# Headful only: this bound exists so the real window fits the monitor.
|
||||
# headless has no window to overflow, and headless='virtual' runs a 1x1
|
||||
# Xvfb (see virtdisplay.py) that would otherwise shrink the whole
|
||||
# fingerprint to 1x1.
|
||||
if headless is False and screen_cons:
|
||||
# Headful on a real monitor only: this bound exists so the window fits
|
||||
# the screen it is drawn on. headless has no window to overflow, and
|
||||
# headless='virtual' reaches here as headless=False (see async_api) with
|
||||
# a 1x1 Xvfb (virtdisplay.py) that is not a real screen.
|
||||
if headless is False and not virtual_display and screen_cons:
|
||||
clamp_screen_to_display(config, screen_cons.max_width, screen_cons.max_height)
|
||||
fix_screen_no_taskbar(config, target_os)
|
||||
clamp_window_dimensions(config)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
"""
|
||||
Launch-level guards for the display clamp in launch_options().
|
||||
|
||||
Run with:
|
||||
cd pythonlib && python -m pytest tests/test_launch_geometry.py -v
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from unittest import mock
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
import orjson # noqa: E402
|
||||
from browserforge.fingerprints import Screen # noqa: E402
|
||||
|
||||
from camoufox import utils # noqa: E402
|
||||
|
||||
# What get_screen_cons() reports under the Xvfb that headless='virtual' starts:
|
||||
# virtdisplay.py sizes it "1x1x24", and launch_options mutates os.environ's
|
||||
# DISPLAY, so the parent process enumerates that stub as its only monitor.
|
||||
XVFB_STUB = Screen(max_width=1, max_height=1)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def host(screen_cons):
|
||||
"""Run launch_options() against a stubbed host, without touching the disk."""
|
||||
with mock.patch.object(utils, "get_screen_cons", lambda headless: screen_cons), (
|
||||
mock.patch.object(utils, "installed_verstr", lambda: "150.0.2")
|
||||
), mock.patch.object(utils, "launch_path", lambda **kwargs: "/nonexistent/camoufox"):
|
||||
yield
|
||||
|
||||
|
||||
def config_of(options):
|
||||
"""Reassemble the chunked CAMOU_CONFIG_<n> env vars into a dict."""
|
||||
env = options["env"]
|
||||
chunks = sorted(
|
||||
(int(k.rsplit("_", 1)[1]), v) for k, v in env.items() if k.startswith("CAMOU_CONFIG_")
|
||||
)
|
||||
return orjson.loads("".join(chunk for _, chunk in chunks))
|
||||
|
||||
|
||||
def launch(**kwargs):
|
||||
kwargs.setdefault("os", "windows")
|
||||
kwargs.setdefault("i_know_what_im_doing", True)
|
||||
return config_of(utils.launch_options(**kwargs))
|
||||
|
||||
|
||||
class TestVirtualDisplayIsNotAScreen:
|
||||
"""headless='virtual' arrives here as headless=False (async_api rewrites it),
|
||||
so the headful gate alone would clamp the fingerprint to the 1x1 Xvfb."""
|
||||
|
||||
def test_fingerprint_is_not_shrunk_to_the_xvfb(self):
|
||||
with host(XVFB_STUB):
|
||||
config = launch(headless=False, virtual_display=":99")
|
||||
|
||||
assert config["screen.width"] > 1
|
||||
assert config["screen.height"] > 1
|
||||
assert config["window.outerWidth"] > 1
|
||||
|
||||
def test_screen_dimensions_stay_valid(self):
|
||||
"""Clamping to 1x1 drives availHeight negative once fix_screen_no_taskbar
|
||||
subtracts the taskbar, which validate_config rejects as a uint."""
|
||||
with host(XVFB_STUB):
|
||||
config = launch(headless=False, virtual_display=":99")
|
||||
|
||||
for key, value in config.items():
|
||||
if key.startswith("screen.") or key.startswith("window.outer"):
|
||||
assert value >= 0, f"{key} is negative: {value}"
|
||||
Reference in New Issue
Block a user