mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 06:52:04 -08:00
pythonlib: Add more leak warnings 0.2.8
Warns the user for when the passed parameters are likely to cause a leak.
This commit is contained in:
parent
4a1cd7ec64
commit
351e99ed18
8 changed files with 171 additions and 36 deletions
30
.gitignore
vendored
30
.gitignore
vendored
|
|
@ -1,20 +1,32 @@
|
||||||
|
# Local builds
|
||||||
/camoufox-*
|
/camoufox-*
|
||||||
/firefox-*
|
/firefox-*
|
||||||
/mozilla-unified
|
/mozilla-unified
|
||||||
/extra-docs
|
|
||||||
/.vscode
|
|
||||||
_old/
|
|
||||||
dist/
|
dist/
|
||||||
bin/
|
bin/
|
||||||
venv/
|
|
||||||
/bundle/fonts/extra
|
|
||||||
launch
|
launch
|
||||||
launch.exe
|
launch.exe
|
||||||
|
|
||||||
|
# Internal testing
|
||||||
|
/extra-docs
|
||||||
|
/tests
|
||||||
|
/.vscode
|
||||||
|
/bundle/fonts/extra
|
||||||
|
pythonlib/*.png
|
||||||
|
scripts/*.png
|
||||||
|
test*
|
||||||
|
|
||||||
|
# Old data
|
||||||
|
_old/
|
||||||
*.old
|
*.old
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
# Logs
|
||||||
wget-log
|
wget-log
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
*.log
|
*.log
|
||||||
test.py
|
|
||||||
*.mmdb
|
# Python interface
|
||||||
|
venv/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.mmdb
|
||||||
|
|
@ -116,11 +116,3 @@ class InvalidOS(ValueError):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
class DetectionWarning(RuntimeWarning):
|
|
||||||
"""
|
|
||||||
Raised when a the user has a setting enabled that can cause detection.
|
|
||||||
"""
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
import os.path
|
|
||||||
import re
|
import re
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from browserforge.fingerprints import Fingerprint, FingerprintGenerator
|
from browserforge.fingerprints import Fingerprint, FingerprintGenerator
|
||||||
from yaml import CLoader, load
|
|
||||||
|
from camoufox.pkgman import load_yaml
|
||||||
|
|
||||||
# Load the browserforge.yaml file
|
# Load the browserforge.yaml file
|
||||||
with open(os.path.join(os.path.dirname(__file__), 'browserforge.yml'), 'r') as f:
|
BROWSERFORGE_DATA = load_yaml('browserforge.yml')
|
||||||
BROWSERFORGE_DATA = load(f, Loader=CLoader)
|
|
||||||
|
|
||||||
FP_GENERATOR = FingerprintGenerator(browser='firefox', os=('linux', 'macos', 'windows'))
|
FP_GENERATOR = FingerprintGenerator(browser='firefox', os=('linux', 'macos', 'windows'))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import requests
|
||||||
from platformdirs import user_cache_dir
|
from platformdirs import user_cache_dir
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from typing_extensions import TypeAlias
|
from typing_extensions import TypeAlias
|
||||||
|
from yaml import CLoader, load
|
||||||
|
|
||||||
from .exceptions import UnsupportedArchitecture, UnsupportedOS
|
from .exceptions import UnsupportedArchitecture, UnsupportedOS
|
||||||
|
|
||||||
|
|
@ -337,3 +338,11 @@ def unzip(
|
||||||
with ZipFile(zip_file) as zf:
|
with ZipFile(zip_file) as zf:
|
||||||
for member in tqdm(zf.infolist(), desc=desc):
|
for member in tqdm(zf.infolist(), desc=desc):
|
||||||
zf.extract(member, extract_path)
|
zf.extract(member, extract_path)
|
||||||
|
|
||||||
|
|
||||||
|
def load_yaml(file: str) -> dict:
|
||||||
|
"""
|
||||||
|
Loads a local YAML file and returns it as a dictionary.
|
||||||
|
"""
|
||||||
|
with open(Path(__file__).parent / file, 'r') as f:
|
||||||
|
return load(f, Loader=CLoader)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
|
||||||
from os import environ
|
from os import environ
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from random import randrange
|
from random import randrange
|
||||||
|
|
@ -20,7 +19,6 @@ from .addons import (
|
||||||
threaded_try_load_addons,
|
threaded_try_load_addons,
|
||||||
)
|
)
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
DetectionWarning,
|
|
||||||
InvalidOS,
|
InvalidOS,
|
||||||
InvalidPropertyType,
|
InvalidPropertyType,
|
||||||
NonFirefoxFingerprint,
|
NonFirefoxFingerprint,
|
||||||
|
|
@ -30,6 +28,7 @@ from .fingerprints import from_browserforge, generate_fingerprint
|
||||||
from .ip import Proxy, public_ip, valid_ipv4, valid_ipv6
|
from .ip import Proxy, public_ip, valid_ipv4, valid_ipv6
|
||||||
from .locale import geoip_allowed, get_geolocation, normalize_locale
|
from .locale import geoip_allowed, get_geolocation, normalize_locale
|
||||||
from .pkgman import OS_NAME, get_path, installed_verstr
|
from .pkgman import OS_NAME, get_path, installed_verstr
|
||||||
|
from .warnings import LeakWarning
|
||||||
from .xpi_dl import add_default_addons
|
from .xpi_dl import add_default_addons
|
||||||
|
|
||||||
LAUNCH_FILE = {
|
LAUNCH_FILE = {
|
||||||
|
|
@ -197,12 +196,7 @@ def check_custom_fingerprint(fingerprint: Fingerprint) -> None:
|
||||||
'If this is intentional, pass `i_know_what_im_doing=True`.'
|
'If this is intentional, pass `i_know_what_im_doing=True`.'
|
||||||
)
|
)
|
||||||
|
|
||||||
warnings.warn(
|
LeakWarning.warn('custom_fingerprint', False)
|
||||||
'Passing your own fingerprint is not recommended. '
|
|
||||||
'BrowserForge fingerprints are automatically generated within Camoufox '
|
|
||||||
'based on the provided `os` and `screen` constraints.',
|
|
||||||
category=DetectionWarning,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def check_valid_os(os: ListOrString) -> None:
|
def check_valid_os(os: ListOrString) -> None:
|
||||||
|
|
@ -249,6 +243,45 @@ def set_into(target: Dict[str, Any], key: str, value: Any) -> None:
|
||||||
target[key] = value
|
target[key] = value
|
||||||
|
|
||||||
|
|
||||||
|
def is_domain_set(
|
||||||
|
config: Dict[str, Any],
|
||||||
|
*properties: str,
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if a domain is set in the config.
|
||||||
|
"""
|
||||||
|
for prop in properties:
|
||||||
|
# If the . prefix exists, check if the domain is a prefix of any key in the config
|
||||||
|
if prop.endswith('.'):
|
||||||
|
if any(key.startswith(prop) for key in config):
|
||||||
|
return True
|
||||||
|
# Otherwise, check if the domain is a direct key in the config
|
||||||
|
else:
|
||||||
|
if prop in config:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def warn_manual_config(config: Dict[str, Any]) -> None:
|
||||||
|
"""
|
||||||
|
Warns the user if they are manually setting properties that Camoufox already sets internally.
|
||||||
|
"""
|
||||||
|
# Manual locale setting
|
||||||
|
if is_domain_set(
|
||||||
|
config, 'navigator.language', 'navigator.languages', 'headers.Accept-Language'
|
||||||
|
):
|
||||||
|
LeakWarning.warn('locale', False)
|
||||||
|
# Manual User-Agent setting
|
||||||
|
if is_domain_set(config, 'headers.User-Agent'):
|
||||||
|
LeakWarning.warn('header-ua', False)
|
||||||
|
# Manual navigator setting
|
||||||
|
if is_domain_set(config, 'navigator.'):
|
||||||
|
LeakWarning.warn('navigator', False)
|
||||||
|
# Manual screen/window setting
|
||||||
|
if is_domain_set(config, 'screen.', 'window.', 'document.body.'):
|
||||||
|
LeakWarning.warn('viewport', False)
|
||||||
|
|
||||||
|
|
||||||
def get_launch_options(
|
def get_launch_options(
|
||||||
*,
|
*,
|
||||||
config: Optional[Dict[str, Any]] = None,
|
config: Optional[Dict[str, Any]] = None,
|
||||||
|
|
@ -282,24 +315,27 @@ def get_launch_options(
|
||||||
if config is None:
|
if config is None:
|
||||||
config = {}
|
config = {}
|
||||||
|
|
||||||
|
# Set default values for optional arguments
|
||||||
if addons is None:
|
if addons is None:
|
||||||
addons = []
|
addons = []
|
||||||
if args is None:
|
if args is None:
|
||||||
args = []
|
args = []
|
||||||
if firefox_user_prefs is None:
|
if firefox_user_prefs is None:
|
||||||
firefox_user_prefs = {}
|
firefox_user_prefs = {}
|
||||||
|
if i_know_what_im_doing is None:
|
||||||
|
i_know_what_im_doing = False
|
||||||
|
|
||||||
# Warn the user if headless is being used
|
# Warn the user if headless is being used
|
||||||
# https://github.com/daijro/camoufox/issues/26
|
# https://github.com/daijro/camoufox/issues/26
|
||||||
if headless:
|
if headless:
|
||||||
warnings.warn(
|
LeakWarning.warn('headless', i_know_what_im_doing)
|
||||||
'It is currently not recommended to use headless mode in Camoufox. '
|
|
||||||
'Some WAFs are able to detect headless browsers. The issue is currently being investigated.',
|
|
||||||
category=DetectionWarning,
|
|
||||||
)
|
|
||||||
elif headless is None:
|
elif headless is None:
|
||||||
headless = False
|
headless = False
|
||||||
|
|
||||||
|
# Warn the user for manual config settings
|
||||||
|
if not i_know_what_im_doing:
|
||||||
|
warn_manual_config(config)
|
||||||
|
|
||||||
# Assert the target OS is valid
|
# Assert the target OS is valid
|
||||||
if os:
|
if os:
|
||||||
check_valid_os(os)
|
check_valid_os(os)
|
||||||
|
|
@ -366,6 +402,14 @@ def get_launch_options(
|
||||||
geolocation = get_geolocation(geoip)
|
geolocation = get_geolocation(geoip)
|
||||||
config.update(geolocation.as_config())
|
config.update(geolocation.as_config())
|
||||||
|
|
||||||
|
# Raise a warning when a proxy is being used without spoofing geolocation
|
||||||
|
elif (
|
||||||
|
proxy
|
||||||
|
and 'localhost' not in proxy.get('server', '')
|
||||||
|
and not is_domain_set('geolocation', config)
|
||||||
|
):
|
||||||
|
LeakWarning.warn('proxy_without_geoip')
|
||||||
|
|
||||||
# Set locale
|
# Set locale
|
||||||
if locale:
|
if locale:
|
||||||
parsed_locale = normalize_locale(locale)
|
parsed_locale = normalize_locale(locale)
|
||||||
|
|
@ -391,10 +435,13 @@ def get_launch_options(
|
||||||
if block_webrtc:
|
if block_webrtc:
|
||||||
firefox_user_prefs['media.peerconnection.enabled'] = False
|
firefox_user_prefs['media.peerconnection.enabled'] = False
|
||||||
if allow_webgl:
|
if allow_webgl:
|
||||||
|
LeakWarning.warn('allow_webgl', i_know_what_im_doing)
|
||||||
firefox_user_prefs['webgl.disabled'] = False
|
firefox_user_prefs['webgl.disabled'] = False
|
||||||
|
|
||||||
# Launch
|
# Load the addons
|
||||||
threaded_try_load_addons(get_debug_port(args), addons)
|
threaded_try_load_addons(get_debug_port(args), addons)
|
||||||
|
|
||||||
|
# Prepare environment variables to pass to Camoufox
|
||||||
env_vars = {
|
env_vars = {
|
||||||
**get_env_vars(config, target_os),
|
**get_env_vars(config, target_os),
|
||||||
**(cast(Dict[str, Union[str, float, bool]], environ) if env is None else env),
|
**(cast(Dict[str, Union[str, float, bool]], environ) if env is None else env),
|
||||||
|
|
|
||||||
44
pythonlib/camoufox/warnings.py
Normal file
44
pythonlib/camoufox/warnings.py
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import inspect
|
||||||
|
import warnings
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from camoufox.pkgman import load_yaml
|
||||||
|
|
||||||
|
WARNINGS_DATA = load_yaml('warnings.yml')
|
||||||
|
|
||||||
|
|
||||||
|
class LeakWarning(RuntimeWarning):
|
||||||
|
"""
|
||||||
|
Raised when a the user has a setting enabled that can cause detection.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def warn(warning_key: str, i_know_what_im_doing: Optional[bool] = None) -> None:
|
||||||
|
"""
|
||||||
|
Warns the user if a passed parameter can cause leaks.
|
||||||
|
"""
|
||||||
|
warning = WARNINGS_DATA[warning_key]
|
||||||
|
if i_know_what_im_doing:
|
||||||
|
return
|
||||||
|
if i_know_what_im_doing is not None:
|
||||||
|
warning += '\nIf this is intentional, pass `i_know_what_im_doing=True`.'
|
||||||
|
|
||||||
|
# Get caller information
|
||||||
|
current_module = Path(__file__).parent
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
while frame:
|
||||||
|
if not Path(frame.f_code.co_filename).is_relative_to(current_module):
|
||||||
|
break
|
||||||
|
frame = frame.f_back
|
||||||
|
|
||||||
|
if frame:
|
||||||
|
warnings.warn_explicit(
|
||||||
|
warning,
|
||||||
|
category=LeakWarning,
|
||||||
|
filename=frame.f_code.co_filename,
|
||||||
|
lineno=frame.f_lineno,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
warnings.warn(warning, category=LeakWarning)
|
||||||
32
pythonlib/camoufox/warnings.yml
Normal file
32
pythonlib/camoufox/warnings.yml
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
headless: >-
|
||||||
|
Headless mode in Camoufox is not recommended at this time.
|
||||||
|
Some WAFs are able to detect headless browsers. The issue is currently being investigated.
|
||||||
|
|
||||||
|
navigator: >-
|
||||||
|
Manually setting navigator properties is not recommended.
|
||||||
|
Device information is automatically generated within Camoufox
|
||||||
|
based on the provided `os`.
|
||||||
|
|
||||||
|
locale: >-
|
||||||
|
Use the `locale` parameter in Camoufox instead of setting the config manually.
|
||||||
|
|
||||||
|
header-ua: >-
|
||||||
|
Do not set the header.User-Agent manually. Camoufox will generate a User-Agent for you.
|
||||||
|
|
||||||
|
viewport: >-
|
||||||
|
Manually setting screen & window properties is not recommended.
|
||||||
|
Screen dimensions are randomly generated within Camoufox
|
||||||
|
based on the provided screen constraints. See here:
|
||||||
|
https://github.com/daijro/camoufox/tree/main/pythonlib#browserforge-integration.
|
||||||
|
|
||||||
|
custom_fingerprint: >-
|
||||||
|
Passing your own fingerprint is not recommended.
|
||||||
|
BrowserForge fingerprints are automatically generated within Camoufox
|
||||||
|
based on the provided `os` and `screen` constraints.
|
||||||
|
|
||||||
|
proxy_without_geoip: >-
|
||||||
|
When using a proxy, it is heavily recommended that you pass `geoip=True`.
|
||||||
|
|
||||||
|
allow_webgl: >-
|
||||||
|
Enabling WebGL can lead to Canvas fingerprinting and detection.
|
||||||
|
Camoufox will automatically spoof your vendor and renderer, but it cannot spoof your WebGL fingerprint.
|
||||||
|
|
@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "camoufox"
|
name = "camoufox"
|
||||||
version = "0.2.7"
|
version = "0.2.8"
|
||||||
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