mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 18:22:03 -08:00
Update pythonlib & README for beta.11
- Removed warnings for using headless mode - Xvfb is now activated with headless='virtual' - Correctly pass window.screenX & calculate window.screenY - Update documentation on main README and pythonlib README - Bumped pythonlib to 0.2.10
This commit is contained in:
parent
49cea6eca8
commit
b2f74a24f3
10 changed files with 96 additions and 66 deletions
19
README.md
19
README.md
|
|
@ -440,6 +440,18 @@ Miscellaneous (battery status, etc)
|
||||||
- Geolocation, timezone, and locale spoofing
|
- Geolocation, timezone, and locale spoofing
|
||||||
- etc.
|
- etc.
|
||||||
|
|
||||||
|
#### Stealth patches
|
||||||
|
|
||||||
|
- Avoids main world execution leaks. All page agent javascript is sandboxed
|
||||||
|
- Avoids frame execution context leaks
|
||||||
|
- Fixes `navigator.webdriver` detection
|
||||||
|
- Fixes Firefox headless detection via pointer type ([#26](https://github.com/daijro/camoufox/issues/26))
|
||||||
|
- Removed potentially leaking anti-zoom/meta viewport handling patches
|
||||||
|
- Uses non-default screen & window sizes
|
||||||
|
- Re-enable fission content isolations
|
||||||
|
- Re-enable PDF.js
|
||||||
|
- Other leaking config properties changed
|
||||||
|
|
||||||
#### Anti font fingerprinting
|
#### Anti font fingerprinting
|
||||||
|
|
||||||
- Automatically uses the correct system fonts for your User Agent
|
- Automatically uses the correct system fonts for your User Agent
|
||||||
|
|
@ -450,13 +462,6 @@ Miscellaneous (battery status, etc)
|
||||||
|
|
||||||
- Custom implementation of Playwright for the latest Firefox
|
- Custom implementation of Playwright for the latest Firefox
|
||||||
- Various config patches to evade bot detection
|
- Various config patches to evade bot detection
|
||||||
- Fixes leaking Playwright patches:
|
|
||||||
- All page agent javascript is sandboxed
|
|
||||||
- Fixes frame execution context leaks
|
|
||||||
- Fixes `navigator.webdriver` detection
|
|
||||||
- Removed potentially leaking anti-zoom/meta viewport handling patches
|
|
||||||
- Re-enable fission content isolation
|
|
||||||
- Re-enable PDF.js
|
|
||||||
|
|
||||||
#### Debloat/Optimizations
|
#### Debloat/Optimizations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,9 +136,9 @@ Parameters:
|
||||||
ff_version (Optional[int]):
|
ff_version (Optional[int]):
|
||||||
Firefox version to use. Defaults to the current Camoufox version.
|
Firefox version to use. Defaults to the current Camoufox version.
|
||||||
To prevent leaks, only use this for special cases.
|
To prevent leaks, only use this for special cases.
|
||||||
headless (Optional[bool]):
|
headless (Union[bool, Literal['virtual']]):
|
||||||
Whether to run the browser in headless mode. Defaults to False.
|
Whether to run the browser in headless mode. Defaults to False.
|
||||||
WARNING: Please avoid using headless mode until issue #26 is fixed.
|
If you are running linux, passing 'virtual' will use Xvfb.
|
||||||
executable_path (Optional[str]):
|
executable_path (Optional[str]):
|
||||||
Custom Camoufox browser executable path.
|
Custom Camoufox browser executable path.
|
||||||
firefox_user_prefs (Optional[Dict[str, Any]]):
|
firefox_user_prefs (Optional[Dict[str, Any]]):
|
||||||
|
|
@ -270,7 +270,7 @@ with sync_playwright() as p:
|
||||||
|
|
||||||
### Virtual Display
|
### Virtual Display
|
||||||
|
|
||||||
In headless mode, all browsers are prone to being detected by anti-bot services due to the drastic differences in the browser's architecture. It is generally **NOT** recommended to use Camoufox in headless mode on a non-Linux OS.
|
While Camoufox includes patches to prevent headless detection, running in headless mode may still be detectable in the future. It's recommended to use a virtual display buffer to run Camoufox headlessly.
|
||||||
|
|
||||||
If you are running Linux, and would like to run Camoufox headlessly in a virtual display, install `xvfb`:
|
If you are running Linux, and would like to run Camoufox headlessly in a virtual display, install `xvfb`:
|
||||||
|
|
||||||
|
|
@ -293,7 +293,7 @@ $ which Xvfb
|
||||||
/usr/bin/Xvfb
|
/usr/bin/Xvfb
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, passing `headless=True` will spawn a new lightweight virtual display in the background for Camoufox to run in.
|
Now, passing `headless='virtual'` will spawn a new lightweight virtual display in the background for Camoufox to run in.
|
||||||
|
|
||||||
<hr width=50>
|
<hr width=50>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ from playwright.async_api import (
|
||||||
Playwright,
|
Playwright,
|
||||||
PlaywrightContextManager,
|
PlaywrightContextManager,
|
||||||
)
|
)
|
||||||
|
from typing_extensions import Literal
|
||||||
|
|
||||||
from .addons import DefaultAddons
|
from .addons import DefaultAddons
|
||||||
from .utils import ListOrString, _clean_locals, get_launch_options
|
from .utils import ListOrString, _clean_locals, get_launch_options
|
||||||
|
|
@ -51,7 +52,7 @@ async def AsyncNewBrowser(
|
||||||
screen: Optional[Screen] = None,
|
screen: Optional[Screen] = None,
|
||||||
fingerprint: Optional[Fingerprint] = None,
|
fingerprint: Optional[Fingerprint] = None,
|
||||||
ff_version: Optional[int] = None,
|
ff_version: Optional[int] = None,
|
||||||
headless: Optional[bool] = None,
|
headless: Optional[Union[bool, Literal['virtual']]] = None,
|
||||||
executable_path: Optional[str] = None,
|
executable_path: Optional[str] = None,
|
||||||
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
||||||
proxy: Optional[Dict[str, str]] = None,
|
proxy: Optional[Dict[str, str]] = None,
|
||||||
|
|
@ -105,9 +106,9 @@ async def AsyncNewBrowser(
|
||||||
ff_version (Optional[int]):
|
ff_version (Optional[int]):
|
||||||
Firefox version to use. Defaults to the current Camoufox version.
|
Firefox version to use. Defaults to the current Camoufox version.
|
||||||
To prevent leaks, only use this for special cases.
|
To prevent leaks, only use this for special cases.
|
||||||
headless (Optional[bool]):
|
headless (Union[bool, Literal['virtual']]):
|
||||||
Whether to run the browser in headless mode. Defaults to False.
|
Whether to run the browser in headless mode. Defaults to False.
|
||||||
WARNING: Please avoid using headless mode until issue #26 is fixed.
|
If you are running linux, passing 'virtual' will use Xvfb.
|
||||||
executable_path (Optional[str]):
|
executable_path (Optional[str]):
|
||||||
Custom Camoufox browser executable path.
|
Custom Camoufox browser executable path.
|
||||||
firefox_user_prefs (Optional[Dict[str, Any]]):
|
firefox_user_prefs (Optional[Dict[str, Any]]):
|
||||||
|
|
|
||||||
|
|
@ -141,3 +141,11 @@ class CannotExecuteXvfb(VirtualDisplayError):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualDisplayNotSupported(VirtualDisplayError):
|
||||||
|
"""
|
||||||
|
Raised when the user tried to use a virtual display on a non-Linux OS.
|
||||||
|
"""
|
||||||
|
|
||||||
|
...
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import re
|
import re
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
|
from random import randrange
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from browserforge.fingerprints import Fingerprint, FingerprintGenerator
|
from browserforge.fingerprints import Fingerprint, FingerprintGenerator, Screen
|
||||||
|
|
||||||
from camoufox.pkgman import load_yaml
|
from camoufox.pkgman import load_yaml
|
||||||
|
|
||||||
|
|
@ -30,15 +31,38 @@ def _cast_to_properties(
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
_cast_to_properties(camoufox_data, type_key, data, ff_version)
|
_cast_to_properties(camoufox_data, type_key, data, ff_version)
|
||||||
continue
|
continue
|
||||||
# Fix values that are out of bounds
|
|
||||||
if type_key.startswith("screen.") and isinstance(data, int) and data < 0:
|
|
||||||
data = 0
|
|
||||||
# Replace the Firefox versions with ff_version
|
# Replace the Firefox versions with ff_version
|
||||||
if ff_version and isinstance(data, str):
|
if ff_version and isinstance(data, str):
|
||||||
data = re.sub(r'(?<!\d)(1[0-9]{2})(\.0)(?!\d)', rf'{ff_version}\2', data)
|
data = re.sub(r'(?<!\d)(1[0-9]{2})(\.0)(?!\d)', rf'{ff_version}\2', data)
|
||||||
camoufox_data[type_key] = data
|
camoufox_data[type_key] = data
|
||||||
|
|
||||||
|
|
||||||
|
def handle_screenXY(camoufox_data: Dict[str, Any], fp_screen: Screen) -> None:
|
||||||
|
"""
|
||||||
|
Helper method to set window.screenY based on Browserforge's screenX value.
|
||||||
|
"""
|
||||||
|
# Default screenX to 0 if not provided
|
||||||
|
screenX = fp_screen.screenX
|
||||||
|
if not screenX:
|
||||||
|
camoufox_data['window.screenX'] = 0
|
||||||
|
camoufox_data['window.screenY'] = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
# If screenX is within [-50, 50], use the same value for screenY
|
||||||
|
if screenX in range(-50, 51):
|
||||||
|
camoufox_data['window.screenY'] = screenX
|
||||||
|
return
|
||||||
|
|
||||||
|
# Browserforge thinks the browser is windowed. # Randomly generate a screenY value.
|
||||||
|
screenY = fp_screen.availHeight - fp_screen.outerHeight
|
||||||
|
if screenY == 0:
|
||||||
|
camoufox_data['window.screenY'] = 0
|
||||||
|
elif screenY > 0:
|
||||||
|
camoufox_data['window.screenY'] = randrange(0, screenY) # nosec
|
||||||
|
else:
|
||||||
|
camoufox_data['window.screenY'] = randrange(screenY, 0) # nosec
|
||||||
|
|
||||||
|
|
||||||
def from_browserforge(fingerprint: Fingerprint, ff_version: Optional[str] = None) -> Dict[str, Any]:
|
def from_browserforge(fingerprint: Fingerprint, ff_version: Optional[str] = None) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Converts a Browserforge fingerprint to a Camoufox config.
|
Converts a Browserforge fingerprint to a Camoufox config.
|
||||||
|
|
@ -50,6 +74,8 @@ def from_browserforge(fingerprint: Fingerprint, ff_version: Optional[str] = None
|
||||||
bf_dict=asdict(fingerprint),
|
bf_dict=asdict(fingerprint),
|
||||||
ff_version=ff_version,
|
ff_version=ff_version,
|
||||||
)
|
)
|
||||||
|
handle_screenXY(camoufox_data, fingerprint.screen)
|
||||||
|
|
||||||
return camoufox_data
|
return camoufox_data
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ from playwright.sync_api import (
|
||||||
Playwright,
|
Playwright,
|
||||||
PlaywrightContextManager,
|
PlaywrightContextManager,
|
||||||
)
|
)
|
||||||
|
from typing_extensions import Literal
|
||||||
|
|
||||||
from .addons import DefaultAddons
|
from .addons import DefaultAddons
|
||||||
from .utils import ListOrString, _clean_locals, get_launch_options
|
from .utils import ListOrString, _clean_locals, get_launch_options
|
||||||
|
|
@ -51,7 +52,7 @@ def NewBrowser(
|
||||||
screen: Optional[Screen] = None,
|
screen: Optional[Screen] = None,
|
||||||
fingerprint: Optional[Fingerprint] = None,
|
fingerprint: Optional[Fingerprint] = None,
|
||||||
ff_version: Optional[int] = None,
|
ff_version: Optional[int] = None,
|
||||||
headless: Optional[bool] = None,
|
headless: Optional[Union[bool, Literal['virtual']]] = None,
|
||||||
executable_path: Optional[str] = None,
|
executable_path: Optional[str] = None,
|
||||||
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
||||||
proxy: Optional[Dict[str, str]] = None,
|
proxy: Optional[Dict[str, str]] = None,
|
||||||
|
|
@ -61,7 +62,7 @@ def NewBrowser(
|
||||||
i_know_what_im_doing: Optional[bool] = None,
|
i_know_what_im_doing: Optional[bool] = None,
|
||||||
debug: Optional[bool] = None,
|
debug: Optional[bool] = None,
|
||||||
**launch_options: Dict[str, Any]
|
**launch_options: Dict[str, Any]
|
||||||
) -> Browser:
|
) -> Union[Browser, BrowserContext]:
|
||||||
"""
|
"""
|
||||||
Launches a new browser instance for Camoufox.
|
Launches a new browser instance for Camoufox.
|
||||||
Accepts all Playwright Firefox launch options, along with the following:
|
Accepts all Playwright Firefox launch options, along with the following:
|
||||||
|
|
@ -105,9 +106,9 @@ def NewBrowser(
|
||||||
ff_version (Optional[int]):
|
ff_version (Optional[int]):
|
||||||
Firefox version to use. Defaults to the current Camoufox version.
|
Firefox version to use. Defaults to the current Camoufox version.
|
||||||
To prevent leaks, only use this for special cases.
|
To prevent leaks, only use this for special cases.
|
||||||
headless (Optional[bool]):
|
headless (Union[bool, Literal['virtual']]):
|
||||||
Whether to run the browser in headless mode. Defaults to False.
|
Whether to run the browser in headless mode. Defaults to False.
|
||||||
WARNING: Please avoid using headless mode until issue #26 is fixed.
|
If you are running linux, passing 'virtual' will use Xvfb.
|
||||||
executable_path (Optional[str]):
|
executable_path (Optional[str]):
|
||||||
Custom Camoufox browser executable path.
|
Custom Camoufox browser executable path.
|
||||||
firefox_user_prefs (Optional[Dict[str, Any]]):
|
firefox_user_prefs (Optional[Dict[str, Any]]):
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import sys
|
||||||
from os import environ
|
from os import environ
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from random import randrange
|
from random import randrange
|
||||||
from shutil import which
|
|
||||||
from typing import Any, Dict, List, Literal, Optional, Tuple, Union, cast
|
from typing import Any, Dict, List, Literal, Optional, Tuple, Union, cast
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
@ -227,35 +226,6 @@ def _clean_locals(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def handle_headless(
|
|
||||||
headless: Optional[bool],
|
|
||||||
env: Dict[str, Union[str, float, bool]],
|
|
||||||
debug: Optional[bool],
|
|
||||||
i_know_what_im_doing: Optional[bool],
|
|
||||||
) -> bool:
|
|
||||||
"""
|
|
||||||
Handles the headless mode.
|
|
||||||
"""
|
|
||||||
# If headless is not being used, return False
|
|
||||||
if not headless:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Warn the user if headless is being used on a non-Linux OS
|
|
||||||
# https://github.com/daijro/camoufox/issues/26
|
|
||||||
if OS_NAME != 'lin':
|
|
||||||
LeakWarning.warn('headless-non-linux', i_know_what_im_doing)
|
|
||||||
return True
|
|
||||||
|
|
||||||
# If Xvfb is avaliable, use it instead of headless to prevent leaks
|
|
||||||
if which('Xvfb'):
|
|
||||||
env['DISPLAY'] = VIRTUAL_DISPLAY.new_or_reuse(debug=debug)
|
|
||||||
return False
|
|
||||||
|
|
||||||
# If Linux is being used and Xvfb is not avaliable, warn the user
|
|
||||||
LeakWarning.warn('headless-linux', i_know_what_im_doing)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def merge_into(target: Dict[str, Any], source: Dict[str, Any]) -> None:
|
def merge_into(target: Dict[str, Any], source: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Merges new keys/values from the source dictionary into the target dictionary.
|
Merges new keys/values from the source dictionary into the target dictionary.
|
||||||
|
|
@ -335,7 +305,7 @@ def get_launch_options(
|
||||||
allow_webgl: Optional[bool] = None,
|
allow_webgl: Optional[bool] = None,
|
||||||
proxy: Optional[Dict[str, str]] = None,
|
proxy: Optional[Dict[str, str]] = None,
|
||||||
ff_version: Optional[int] = None,
|
ff_version: Optional[int] = None,
|
||||||
headless: Optional[bool] = None,
|
headless: Optional[Union[bool, Literal['virtual']]] = None,
|
||||||
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
||||||
launch_options: Optional[Dict[str, Any]] = None,
|
launch_options: Optional[Dict[str, Any]] = None,
|
||||||
debug: Optional[bool] = None,
|
debug: Optional[bool] = None,
|
||||||
|
|
@ -348,6 +318,8 @@ def get_launch_options(
|
||||||
config = {}
|
config = {}
|
||||||
|
|
||||||
# Set default values for optional arguments
|
# Set default values for optional arguments
|
||||||
|
if headless is None:
|
||||||
|
headless = False
|
||||||
if addons is None:
|
if addons is None:
|
||||||
addons = []
|
addons = []
|
||||||
if args is None:
|
if args is None:
|
||||||
|
|
@ -360,7 +332,9 @@ def get_launch_options(
|
||||||
env = cast(Dict[str, Union[str, float, bool]], environ)
|
env = cast(Dict[str, Union[str, float, bool]], environ)
|
||||||
|
|
||||||
# Handle headless mode cases
|
# Handle headless mode cases
|
||||||
headless = handle_headless(headless, env, debug, i_know_what_im_doing)
|
if headless == 'virtual':
|
||||||
|
env['DISPLAY'] = VIRTUAL_DISPLAY.new_or_reuse(debug=debug)
|
||||||
|
headless = False
|
||||||
|
|
||||||
# Warn the user for manual config settings
|
# Warn the user for manual config settings
|
||||||
if not i_know_what_im_doing:
|
if not i_know_what_im_doing:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,12 @@ from glob import glob
|
||||||
from shutil import which
|
from shutil import which
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from camoufox.exceptions import CannotExecuteXvfb, CannotFindXvfb
|
from camoufox.exceptions import (
|
||||||
|
CannotExecuteXvfb,
|
||||||
|
CannotFindXvfb,
|
||||||
|
VirtualDisplayNotSupported,
|
||||||
|
)
|
||||||
|
from camoufox.pkgman import OS_NAME
|
||||||
|
|
||||||
|
|
||||||
class VirtualDisplay:
|
class VirtualDisplay:
|
||||||
|
|
@ -72,6 +77,8 @@ class VirtualDisplay:
|
||||||
"""
|
"""
|
||||||
Get the display number
|
Get the display number
|
||||||
"""
|
"""
|
||||||
|
self.assert_linux()
|
||||||
|
|
||||||
if self.proc is None:
|
if self.proc is None:
|
||||||
self.execute_xvfb_singleton(debug)
|
self.execute_xvfb_singleton(debug)
|
||||||
elif debug:
|
elif debug:
|
||||||
|
|
@ -116,5 +123,13 @@ class VirtualDisplay:
|
||||||
self._display = self._free_display()
|
self._display = self._free_display()
|
||||||
return self._display
|
return self._display
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def assert_linux():
|
||||||
|
"""
|
||||||
|
Assert that the current OS is Linux
|
||||||
|
"""
|
||||||
|
if OS_NAME != 'lin':
|
||||||
|
raise VirtualDisplayNotSupported("Virtual display is only supported on Linux.")
|
||||||
|
|
||||||
|
|
||||||
VIRTUAL_DISPLAY = VirtualDisplay()
|
VIRTUAL_DISPLAY = VirtualDisplay()
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,3 @@
|
||||||
headless-non-linux: >-
|
|
||||||
Headless mode is only recommended on Linux at this time.
|
|
||||||
Some WAFs are able to detect headless browsers. The issue is currently being investigated.
|
|
||||||
|
|
||||||
headless-linux: >-
|
|
||||||
Headless mode is only recommended on Linux with Xvfb installed.
|
|
||||||
Please see the install guide here:
|
|
||||||
https://github.com/daijro/camoufox/tree/main/pythonlib#virtual-display
|
|
||||||
|
|
||||||
navigator: >-
|
navigator: >-
|
||||||
Manually setting navigator properties is not recommended.
|
Manually setting navigator properties is not recommended.
|
||||||
Device information is automatically generated within Camoufox
|
Device information is automatically generated within Camoufox
|
||||||
|
|
@ -39,4 +30,13 @@ allow_webgl: >-
|
||||||
ff_version: >-
|
ff_version: >-
|
||||||
Spoofing the Firefox version will likely lead to detection.
|
Spoofing the Firefox version will likely lead to detection.
|
||||||
If rotating the Firefox version is absolutely necessary, it would be more advisable to
|
If rotating the Firefox version is absolutely necessary, it would be more advisable to
|
||||||
rotate between older versions of Camoufox instead.
|
rotate between older versions of Camoufox instead.
|
||||||
|
|
||||||
|
# headless-non-linux: >-
|
||||||
|
# Headless mode is only recommended on Linux at this time.
|
||||||
|
# Some WAFs are able to detect headless browsers. The issue is currently being investigated.
|
||||||
|
|
||||||
|
# headless-linux: >-
|
||||||
|
# Headless mode is only recommended on Linux with Xvfb installed.
|
||||||
|
# Please see the install guide here:
|
||||||
|
# https://github.com/daijro/camoufox/tree/main/pythonlib#virtual-display
|
||||||
|
|
@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "camoufox"
|
name = "camoufox"
|
||||||
version = "0.2.9"
|
version = "0.2.10"
|
||||||
description = "Wrapper around Playwright to help launch Camoufox"
|
description = "Wrapper around Playwright to help launch Camoufox"
|
||||||
authors = ["daijro <daijro.dev@gmail.com>"]
|
authors = ["daijro <daijro.dev@gmail.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue