Commit Graph

120 Commits

Author SHA1 Message Date
daijro fdaffc03e9 Bump pythonlib to 0.5.1 2026-06-08 07:18:05 -05:00
daijro e8b86fa5c6 fontconfig path compatibility with older releases
Merged from cloverlabs repo
2026-06-08 07:16:54 -05:00
daijro 53e10d3d3b Make alpha versions available through the Camoufox manager
Adds "alpha" releases to the official/prerelease channel, even if the asset isnt marked as a prerelease
2026-06-08 05:19:06 -05:00
daijro 8899b42784 Merge pull request #618 from Young-Lord/wait-xvfb
fix(virtdisplay): wait() Xvfb child process to prevent zombie process
2026-06-06 15:25:38 -05:00
oyaah fafd35a775 Fix fontconfig path typo to fix FileNotFoundError on Linux 2026-06-07 01:49:50 +05:30
LY ce5edf6f5c fix(virtdisplay): wait() Xvfb child process to prevent zombie process 2026-05-20 09:19:24 +08:00
icepaq 0ac611c4ad v150 with Windows Support - Python Package Being Merged Separately (#611)
* fix v150 patches

* screen related patch fixes

* fix juggler issues with 150

* Update grading.py

improved build tester scoring

* fix windows build for v150

- scripts/_mixin.py: switch moz_target from x86_64-pc-mingw32 (no longer
  supported in FF150) to x86_64-pc-windows-msvc
- additions/juggler/screencast/HeadlessWindowCapturer.h: typedef pid_t
  on XP_WIN; libwebrtc headers (video_capture.h, desktop_capturer.h)
  reference pid_t which is POSIX-only
- patches/anti-font-fingerprinting.patch: include mozilla/dom/Document.h
  in gfxTextRun.cpp; on Windows it is not transitively included so
  doc->GetInnerWindow() failed with "incomplete type 'Document'"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* make service test use local binary

* updated ff fingerprint versions

* Update README.md

---------

Co-authored-by: Ubuntu <ubuntu@ip-172-31-15-96.us-east-2.compute.internal>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:34:05 -04:00
Jake Writer 8f9ff07b48 fix(virtdisplay): atomically claim X11 display via Xvfb -displayfd (#597)
Replace the userspace lock-file scan + random-jitter retry loop with
Xvfb's own -displayfd mechanism. Xvfb scans up from :0 and atomically
binds the first free X11 socket (kernel-mediated, no userspace race),
then writes the chosen display number back through an inherited pipe.

This eliminates the duplicate-display race that occurred when many
camoufox processes started concurrently and all observed the same set
of free display numbers before any of them bound.

Adds a 10s read timeout on the displayfd pipe so a hung Xvfb fails
fast instead of blocking forever, and adds tests covering single
launch, idempotent get(), 50 concurrent reservations with uniqueness,
and post-kill display reuse.
2026-05-08 19:12:09 -04:00
Ruben Vereecken 0830d36e47 Add config_overrides to generate_context_fingerprint(), fix font spacing disable (#601)
* Add system-ui font spoofing patch

GetSystemUIFontFamilies() now reads navigator.platform from MaskConfig
and returns the appropriate system font (Helvetica for macOS, Segoe UI
for Windows) before falling through to LookAndFeel::GetFont. Fixes the
CreepJS headless.systemFonts "Sans:Linux" leak when spoofing macOS from
Linux.

* Add patch verification test for system-ui font spoofing

Tests macOS and Windows presets: launches Camoufox with a fingerprint,
measures canvas text width with unquoted system-ui, asserts it matches
the expected system font (Helvetica / Segoe UI).

* Rename test to match patch naming convention

tests/patches/ files should mirror patch names, not use dated prefixes.

* Add config_overrides param to generate_context_fingerprint()

There was no clean way to override config values (like disabling font
spacing perturbation with fonts:spacing_seed=0) because init_script is
rendered inside generate_context_fingerprint() — by the time the caller
gets the config dict back, the init_script string is already baked.

config_overrides is applied after all config building (preset/seeds/
timezone/locale) but before init_script rendering, giving callers a
clean override point without touching the preset (which represents
real device data, not perturbation config).

The longer-term fix is separating config building from init_script
rendering so callers can modify config and re-render. config_overrides
is the minimal API addition that unblocks the use case without that
refactor.

* Rename test to match patch naming convention
2026-05-08 19:04:14 -04:00
LY 65f3454f48 Fix virtual display under Wayland by forcing X11 (#576)
When using Xvfb-backed virtual display, override Wayland env vars
(GDK_BACKEND, WAYLAND_DISPLAY, MOZ_ENABLE_WAYLAND) so Firefox/GTK
honors DISPLAY and reliably uses the X11 virtual screen.

closes #575
2026-04-29 15:51:44 -04:00
Ruben Vereecken 0cd6c782d0 Set FONTCONFIG_FILE to isolate bundled fonts on Linux (#561)
Without FONTCONFIG_FILE, fontconfig loads the system's /etc/fonts/fonts.conf
which includes system font directories. This means system fonts leak into the
rendering pipeline for fallback glyphs (emoji, CJK, etc.), even though the
font enumeration whitelist hides them from JavaScript. The result is
environment-dependent font metrics that differ between machines with different
system font packages installed.

Generate a runtime fontconfig at ~/.cache/camoufox/fontconfig/ that resolves
the bundled font directory absolutely (the bundled fonts.conf uses
prefix="cwd" relative paths which break under Playwright), and point
FONTCONFIG_FILE at it.
2026-04-14 20:21:42 -04:00
Ruben Vereecken 40fbce61e4 Remove init_script system timezone fallback that poisons storage (#560)
The else branch in _build_init_script() reads the system timezone via
Intl.DateTimeFormat().resolvedOptions().timeZone and stores it via
setTimezone(). When geoip resolves a different timezone (set later via
CAMOU_CONFIG/launch_options), the storage value from the init_script
takes precedence — workers read the wrong timezone and the C++ MaskConfig
fallback (PR #546) is never reached.

Fix: only call setTimezone() when an explicit timezone value is provided.
When omitted, timezone propagation is handled entirely by the C++ side
(SetNewDocument + TimezoneManager::GetTimezone MaskConfig fallback).

Companion to #546 (Fix worker timezone leak when using geoip/proxy).

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 14:24:24 -04:00
Ruben Vereecken 2d62ef0a6d Add timezone and locale parameters to generate_context_fingerprint() (#563)
Allow callers to inject pre-resolved timezone/locale into the
fingerprint before init_script generation. When provided, these
take priority over preset data.

In launch_options(), use setdefault for geoip timezone/locale keys
so that values pre-set via generate_context_fingerprint() aren't
overwritten by geoip resolution.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 14:22:43 -04:00
icepaq d6540b52ce Service Test and Contributing Guides (#521)
* example files

* contributing guides

* simple service test

* run tests in sync

* update pr template

* pip updates

* Update README.md

* typo fixes

* undo pip package update lol

* upgraded service test

* undo injections

* test with proxies

* auto set timezone and proxy url

* delete checks bundle

* split up service tests

* split up build tests

* rename service tests to service tester

* Update CONTRIBUTING.md

* fix entry vs exit ip

* allow alpha versions

* fix patch issues on macos

* bidirectional patch

* Add note on experimental pip package
2026-03-15 21:31:49 -04:00
icepaq c6a6c20670 Camoufox 2.0: Hardware Spoofing + Python Package Updates (#519)
* feat: update timezone, geolocation, and locale spoofing patches

- timezone-spoofing.patch: per-context timezone via per-realm DateTimeInfo
- geolocation-spoofing.patch: CAMOU_CONFIG backwards compatibility for geolocation
- locale-spoofing.patch: add camoucfg LOCAL_INCLUDES
- anti-font-fingerprinting.patch: add RoverfoxStorageManager exports to moz.build

* feat: per-context audio fingerprinting and screen spoofing patches

- audio-fingerprint-manager.patch: per-context audio fingerprinting (all 6 API methods)
- screen-spoofing.patch: per-context screen dimensions with global MaskConfig fallback
- Disable webrtc-ip-spoofing.patch (will re-enable after fixing)
- Remove screen-hijacker.patch (superseded by screen-spoofing.patch)

* fix: add global MaskConfig hooks for navigator.platform, hardwareConcurrency, and timezone (#443)

Fixes issue where global CAMOU_CONFIG settings for navigator.platform,
navigator.hardwareConcurrency, and timezone were not applied in the main
window Navigator (only WorkerNavigator was patched via fingerprint-injection.patch).

* fix: run nsJSUtils::SetTimeZoneOverride() after SpiderMonkey has Initialized to prevent SIGSEGV

* Add fingerprint improvements for PR #3

- navigator-spoofing.patch: Global config fixes for platform/hardwareConcurrency/timezone
- timezone-spoofing.patch: Persistence across page navigation via SetNewDocument hook
- audio-fingerprint-manager.patch: Full 6-method coverage with self-destruct pattern
- screen-spoofing.patch: Per-context dimensions with self-destruct pattern
- webrtc-ip-spoofing.patch: Re-enabled with getStats() sanitization + comprehensive IPv6 regex

* fix: simplify userContextId to BrowsingContext + add per-context docs

* feat(navigator): Add per-context spoofing (platform, oscpu, hardwareConcurrency) with global fallback + docs update.

* fix(navigator): use 2-arg GetUint(key, value) for RoverfoxStorageManager

* fix(navigator): header line count build error

* fix(navigator): move NavigatorManager.cpp into SOURCES for leakage error

* fix(navigator): more line count build errors

* fix(navigator): include nsTHashMap and nsHashKeys.h before RoverfoxStorageManager

* feat(webgl): per-context spoofing patch

* fix(webgl): changed GetCanvasElement() to mCanvasElement() for firefox version

* fix(webgl): remove coupled self-destruct

* feat(canvas): per-context spoofing

* feat(font-list): per-context spoofing

* fix(font-list): use GetOwnerWindow() instead of GetOwner()

* feat(speech): per-context spoofing

* fix(speech): add /dom/base inside local_includes

* fix(speech): changed context to avoid conflicts

* feat(navigator): add WorkerNavigator hooks for per-context platform and hardwareConcurrency in workers

* feat(timezone): add per-context timezone override to workers

* fix(canvas): add OffscreenCanvas userContextId support and skip zero pixels in canvas noise

* fix(screen): hook nsMediaFeatures GetDeviceSize for per-context matchMedia device-width/height

* fix(webgl): add OffscreenCanvas userContextId fallback in WebGL GetUserContextId

* fix(canvas): make canvas noise use proper format for BGRA toDataURL path

* fix(canvas): line count fixes

* docs: updated hardware per-context documentation

* Final Per-Context Hardware Fingerprint Spoofing (#9)

* feat(navigator): Add per-context spoofing (platform, oscpu, hardwareConcurrency) with global fallback + docs update.

* fix(navigator): use 2-arg GetUint(key, value) for RoverfoxStorageManager

* fix(navigator): header line count build error

* fix(navigator): move NavigatorManager.cpp into SOURCES for leakage error

* fix(navigator): more line count build errors

* fix(navigator): include nsTHashMap and nsHashKeys.h before RoverfoxStorageManager

* feat(webgl): per-context spoofing patch

* fix(webgl): changed GetCanvasElement() to mCanvasElement() for firefox version

* fix(webgl): remove coupled self-destruct

* feat(canvas): per-context spoofing

* feat(font-list): per-context spoofing

* fix(font-list): use GetOwnerWindow() instead of GetOwner()

* feat(speech): per-context spoofing

* fix(speech): add /dom/base inside local_includes

* fix(speech): changed context to avoid conflicts

* feat(navigator): add WorkerNavigator hooks for per-context platform and hardwareConcurrency in workers

* feat(timezone): add per-context timezone override to workers

* fix(canvas): add OffscreenCanvas userContextId support and skip zero pixels in canvas noise

* fix(screen): hook nsMediaFeatures GetDeviceSize for per-context matchMedia device-width/height

* fix(webgl): add OffscreenCanvas userContextId fallback in WebGL GetUserContextId

* fix(canvas): make canvas noise use proper format for BGRA toDataURL path

* fix(canvas): line count fixes

* docs: updated hardware per-context documentation

* feat(screen): screen avail per context

* fix(font): align userContextId resolution to BrowsingContext

* fix(audio): align userContextId resolution to BrowsingContext

* Avoid macos caching (#11)

* the property to undefined before deleting

* undo webrtc undefined

* feat: userContextId added to WordCacheKey

* fix: hunk line counts for macos cache changes

* fix: add WorkerPrivate fallback in OffscreenCanvas

* fix(audio): transformation added to mSharedChannels path to ensure consistency

* fix(webgl): added WorkerPrivate to ucid

* fix(timezone): add ucid=0 fallback for worker timezone resolution

* fix(audio): move seed lookup outside window guard for all 6 hooks

* fix(canvas): add ucid=0 fallback and WorkerPrivate resolution for workers

* fix(navigator): add setNavigatorUserAgent and ucid=0 fallback and WorkerNavigator for UA spoofing fix

* fix(webgl): add ucid=0 fallback and WorkerPrivate resolution

* fix(webgl): decouple vendor/renderer self-destruct

* fix(navigator): add main-thread navigator.userAgent getter hook

* fix(navigator): add MaskConfig hook for navigator.appVersion in main window

* feat: Add Chakra Petch font for macOS to solidify detection on CreepJS

* fix(fontconfig): rename to match Go launcher, add TTC aliases and update .gitignore

* fix(navigator): oscpu missing MaskConfig global fallback

* feat: add real fingerprint presets (65 firefox profiles) - mainly to test with, more will come when tested.

* feat: use real fingerprint presets as default with BrowserForge as fallback

* feat: add audio:seed and canvas:seed to property schema and validation

* feat: add MaskConfig fallback to seed managers for cross-process worker consistency - don't need to disable fission

* fix(font): moved mUserContextId declaration before mRounding in WordCacheKey so init order matches

* fix(audio): line count correction

* fix(canvas): line count fix

* feat: add per-context fingerprinting API (NewContext/AsyncNewContext) + merge upstream

- fix seed range
- add oscpu derivation from platform, and timezone mapping in from_preset()
- new real fingerprints preset support

* feat: new presets + en-US only, stripped fonts/language, clamp DPR

* feat: random 30-78% font subset generation for NewBrowser and NewContext

* fix: add fission.autostart=true to camoufox.cfg - will be changing this soon with new update so processCount is not 1, so it will be undetectable

* fix: update macos fonts.conf rendering settings

* feat: cross-process fingerprint storage via Firefox Preferences API

Replace RoverfoxStorageManager's per-process static HashMap with Firefox's
built-in Preferences system. Values stored as CString prefs under
"roverfox.s." namespace, auto-synced to all content processes by Firefox.

Content processes can't set prefs directly (ENSURE_PARENT_PROCESS), so a
single IPDL message (RoverfoxStoragePut) routes writes through the parent.
Same public API — all 10 dependent patches require zero changes.

Removes dom.ipc.processCount=1 from camoufox.cfg. Firefox now uses
Playwright's default multi-process model (fresh process per page) with
fission enabled, while fingerprint values remain accessible everywhere.

* fix(cross-process): hunk headers and build fixes

* fix(storage): add local write-through cache to RoverfoxStorageManager

* fix(storage): add sync IPC read fallback for cross-process fingerprint propagation

* fix(storage): add NS_IsMainThread guard to sync IPC fallback - prevent crashes

* fix(storage): sync IPC + pref whitelist for cross-process fingerprint sync

* feat: full documentation update, speech voices generated per context and BrowserForge primary fingerprint generation method for global and per context.

* fix: Direct3D NVIDIA GTX 980 renderers incorrectly appearing on mac because of duplicates

* Update .gitignore

---------

Co-authored-by: PopcornDev1 <e.coiley@icloud.com>
Co-authored-by: Build <build@local>
Co-authored-by: Elliot Coiley <153072396+PopcornDev1@users.noreply.github.com>
2026-03-14 11:29:12 -04:00
daijro be0951543b Update help msg, icon, & bugfix
- Don't fall back to old browsers if the active one isnt installed
- Remade the icon for the gui
- Better exception info
2026-03-07 02:21:15 -06:00
daijro dd798fda87 Support passing channels in remove & fetch cli 2026-03-07 00:31:53 -06:00
daijro 47fbc591ed Camoufox cli docs updates 2026-03-07 00:27:14 -06:00
daijro ce3b93b958 Clean READMEs, clean old data dir on fetch, & more
- Removes the old data directory if Camoufox was installed before 0.5.0
- Fix messy sponsors segment & add repo status info at the top of the README
- Add camoufox/camoufox org as fallback
- Remove (experimental) next to the GeoIP by daijro source
- Format
2026-03-06 07:38:43 -06:00
daijro f046a1e52c Merge remote-tracking branch 'origin/daijro-camoufox-manager' into daijro-camoufox-manager 2026-02-08 01:06:50 -06:00
daijro 1ca7f9982e Better channel switching in UI 2026-02-08 01:05:40 -06:00
daijro cc7277a3f7 Shrink UI image 2026-02-07 23:23:45 -06:00
daijro ac9ee1531a Clean up manager UI & add more info in version cli
- Rewrite `camoufox version` to show storage/path info and more python packages
- In camoufox active/set, show active channels. Fall back to original/stable if none is set
- Remove config files in `camoufox remove --all`
- Spoof the camoufox python library version in UI debug mode
- Fix scrollbar always showing on windows
- Other UI cleanup
2026-02-07 23:16:16 -06:00
daijro b92681759f Remove filters section in gui 2026-02-07 19:55:18 -06:00
daijro febffaa85c Missing geoip support message in gui 2026-02-07 19:53:30 -06:00
daijro 3c13e6ed5f Fix windows strftime 2026-02-07 19:45:31 -06:00
daijro 314b328925 Remove unneeded assets 2026-02-07 04:47:07 -06:00
daijro 5661e0a676 Add more spacing in cli version info 2026-02-07 04:46:47 -06:00
daijro d43b4004f4 Add media to pythonlib docs & cleanup 2026-02-07 04:46:17 -06:00
daijro 1e4dbc5a01 Update pythonlib docs 2026-02-07 04:23:08 -06:00
daijro f843120052 Cli fixes 2026-02-07 04:10:57 -06:00
daijro ee27755bb3 Show active even if not installed 2026-02-07 03:32:03 -06:00
daijro 0923b12194 Exception handling 2026-02-07 03:29:35 -06:00
daijro 61a9e1f9bb Update browserforge (remove manual model downloading) 2026-02-07 03:14:41 -06:00
daijro 4973672d01 Remove canvas anti-fingerprinting 2026-02-07 03:05:50 -06:00
daijro b4d5ae515f Merge branch 'daijro-fixes' into daijro-camoufox-manager 2026-02-07 03:04:31 -06:00
daijro e0e2eeb2f3 Add version manager in python library 2026-02-07 02:47:01 -06:00
icepaq 18e983ad33 Merge pull request #477 from wiremind/executable_path
feat: Add --executable-path flag to the test command
2026-02-06 14:29:15 -05:00
Julien Duponchelle 99f5aaaca2 feat: Add --executable-path flag to the test command
This allow to pass to Camoufox library the executable-path
from the cli test command allowing to use a camoufox from a different
folder during development.

Example:
python -m camoufox test --executable-path="/tmp/camoufox/camoufox-bin"
2026-02-02 09:41:35 +01:00
Julien Duponchelle df51462c43 Set minimum Python to 3.10 to solve Python 3.14 compatibility
When installing package using Poetry on Python 3.14 we have compilation
errors:

```
 copying src/greenlet/platform/setup_switch_x64_masm.cmd -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_aarch64_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_alpha_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_amd64_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_arm32_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_arm32_ios.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_arm64_masm.asm -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_arm64_masm.obj -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_arm64_msvc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_csky_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_loongarch64_linux.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_m68k_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_mips_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_ppc64_aix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_ppc64_linux.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_ppc_aix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_ppc_linux.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_ppc_macosx.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_ppc_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_riscv_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_s390_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_sh_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_sparc_sun_gcc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_x32_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_x64_masm.asm -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_x64_masm.obj -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_x64_msvc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_x86_msvc.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/platform/switch_x86_unix.h -> build/lib.linux-x86_64-cpython-314/greenlet/platform
    | copying src/greenlet/tests/_test_extension.c -> build/lib.linux-x86_64-cpython-314/greenlet/tests
    | copying src/greenlet/tests/_test_extension_cpp.cpp -> build/lib.linux-x86_64-cpython-314/greenlet/tests
    | running build_ext
    | building 'greenlet._greenlet' extension
    | creating build/temp.linux-x86_64-cpython-314/src/greenlet
    | c++ -pthread -fno-strict-overflow -Wsign-compare -Wunreachable-code -DNDEBUG -g -O3 -Wall -O3 -fPIC -fPIC -I/tmp/tmp55zvtgm3/.venv/include -I/home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14 -c src/greenlet/greenlet.cpp -o build/temp.linux-x86_64-cpython-314/src/greenlet/greenlet.o
    | In file included from src/greenlet/greenlet.cpp:31:
    | src/greenlet/TGreenlet.cpp: In member function ‘void greenlet::Greenlet::expose_frames()’:
    | src/greenlet/TGreenlet.cpp:626:29: error: aggregate ‘_PyInterpreterFrame iframe_copy’ has incomplete type and cannot be defined
    |   626 |         _PyInterpreterFrame iframe_copy;
    |       |                             ^~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:627:65: error: invalid application of ‘sizeof’ to incomplete type ‘_PyInterpreterFrame’
    |   627 |         this->stack_state.copy_from_stack(&iframe_copy, iframe, sizeof(*iframe));
    |       |                                                                 ^~~~~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:628:14: error: ‘_PyFrame_IsIncomplete’ was not declared in this scope
    |   628 |         if (!_PyFrame_IsIncomplete(&iframe_copy)) {
    |       |              ^~~~~~~~~~~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:654:24: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   654 |             if (!iframe->frame_obj) {
    |       |                        ^~
    | In file included from /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/pyframe.h:19,
    |                  from /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/Python.h:113,
    |                  from src/greenlet/greenlet.cpp:16:
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:656:37: error: aggregate ‘_PyInterpreterFrame dummy_iframe’ has incomplete type and cannot be defined
    |   656 |                 _PyInterpreterFrame dummy_iframe;
    |       |                                     ^~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:661:38: error: ‘FRAME_OWNED_BY_GENERATOR’ was not declared in this scope
    |   661 |                 dummy_iframe.owner = FRAME_OWNED_BY_GENERATOR;
    |       |                                      ^~~~~~~~~~~~~~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:686:45: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   686 |                 memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
    |       |                                             ^~
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:687:45: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   687 |                        &last_complete_iframe->previous, sizeof(void *));
    |       |                                             ^~
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:688:37: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   688 |                 last_complete_iframe->previous = iframe;
    |       |                                     ^~
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:705:37: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   705 |         memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
    |       |                                     ^~
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:706:37: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   706 |                &last_complete_iframe->previous, sizeof(void *));
    |       |                                     ^~
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | src/greenlet/TGreenlet.cpp:707:29: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   707 |         last_complete_iframe->previous = nullptr;
    |       |                             ^~
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | In file included from src/greenlet/greenlet.cpp:36:
    | src/greenlet/TPythonState.cpp: In member function ‘void greenlet::PythonState::operator<<(const PyThreadState*)’:
    | src/greenlet/TPythonState.cpp:137:31: error: ‘Py_C_RECURSION_LIMIT’ was not declared in this scope
    |   137 |     this->c_recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
    |       |                               ^~~~~~~~~~~~~~~~~~~~
    | src/greenlet/TPythonState.cpp:137:62: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘c_recursion_remaining’; did you mean ‘py_recursion_remaining’?
    |   137 |     this->c_recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
    |       |                                                              ^~~~~~~~~~~~~~~~~~~~~
    |       |                                                              py_recursion_remaining
    | src/greenlet/TPythonState.cpp: In member function ‘void greenlet::PythonState::unexpose_frames()’:
    | src/greenlet/TPythonState.cpp:179:51: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   179 |         _PyInterpreterFrame *prev_exposed = iframe->previous;
    |       |                                                   ^~
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | src/greenlet/TPythonState.cpp:181:23: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   181 |         memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0],
    |       |                       ^~
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | src/greenlet/TPythonState.cpp:181:42: error: invalid use of incomplete type ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |   181 |         memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0],
    |       |                                          ^~
    | /home/jduponchelle/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/include/python3.14/cpython/pyframe.h:25:8: note: forward declaration of ‘_PyInterpreterFrame’ {aka ‘struct _PyInterpreterFrame’}
    |    25 | struct _PyInterpreterFrame;
    |       |        ^~~~~~~~~~~~~~~~~~~
    | src/greenlet/TPythonState.cpp: In member function ‘void greenlet::PythonState::operator>>(PyThreadState*)’:
    | src/greenlet/TPythonState.cpp:212:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘c_recursion_remaining’; did you mean ‘py_recursion_remaining’?
    |   212 |     tstate->c_recursion_remaining = Py_C_RECURSION_LIMIT - this->c_recursion_depth;
    |       |             ^~~~~~~~~~~~~~~~~~~~~
    |       |             py_recursion_remaining
    | src/greenlet/TPythonState.cpp:212:37: error: ‘Py_C_RECURSION_LIMIT’ was not declared in this scope
    |   212 |     tstate->c_recursion_remaining = Py_C_RECURSION_LIMIT - this->c_recursion_depth;
    |       |                                     ^~~~~~~~~~~~~~~~~~~~
    | error: command '/usr/bin/c++' failed with exit code 1

```

This due to the fact we are not installing a recent greenlet version
(3.1.1) due to the Python restriction.

By upgrading the minium Python version to 3.10 (minimum version
supported by the PSF https://devguide.python.org/versions/) the greenlet
module is now 3.3.1, it's the last available release.
2026-01-28 12:15:19 +01:00
daijro e365d42a72 Merge pull request #351 from PierreMesure/patch-1
Use GITHUB_TOKEN if it exists to download Camoufox
2026-01-11 23:40:26 -06:00
daijro fa647700e9 Merge pull request #323 from dozed-dev/main
fix: return correct country from geoip database
2026-01-11 23:39:53 -06:00
daijro 90c916e708 Merge pull request #273 from joaoneves0/fix/xvfb-leak
fix: Ensure virtual_display is killed even if browser.close fails
2026-01-11 23:38:28 -06:00
daijro 2e98b57693 Merge pull request #251 from wv-opt-ai/patch-1
Fix cleanup on exception in sync_api __enter__
2026-01-11 23:37:49 -06:00
daijro b161c24fc9 Merge branch 'fix-ip-exception' into daijro-fixes 2026-01-11 23:34:54 -06:00
daijro 72833eeff9 Merge library fixes from coryking 2026-01-11 23:30:51 -06:00
Pierre 6e6f6736fb Use GITHUB_TOKEN if it exists to download Camoufox 2025-07-10 15:01:19 +02:00
dozed-dev b08a700314 fix: return correct country from geoip database
Return country instead of registered_country for iso code in get_geolocation
2025-06-08 19:53:51 +03:00
joaoneves0 fd1bb2f878 Ensure virtual display cleanup runs on browser close failure 2025-04-14 14:23:38 -03:00
wv-opt-ai e008580521 Fix cleanup on exception in sync_api __enter__
If an exception is raised in the synchronous api during the setup, super().__enter__ has been called but super().__exit__ will not get called, leading to asyncio runloop exceptions further down the line if one tries to create a new context. This commit catches the exception in order to clean up the super().__exit__ calls before reraising.
2025-03-21 16:35:11 +01:00