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:
daijro 2024-10-06 21:53:54 -05:00
parent 4a1cd7ec64
commit 351e99ed18
8 changed files with 171 additions and 36 deletions

28
.gitignore vendored
View file

@ -1,20 +1,32 @@
# Local builds
/camoufox-*
/firefox-*
/mozilla-unified
/extra-docs
/.vscode
_old/
dist/
bin/
venv/
/bundle/fonts/extra
launch
launch.exe
# Internal testing
/extra-docs
/tests
/.vscode
/bundle/fonts/extra
pythonlib/*.png
scripts/*.png
test*
# Old data
_old/
*.old
__pycache__/
*.pyc
# Logs
wget-log
*.kate-swp
*.log
test.py
# Python interface
venv/
__pycache__/
*.pyc
*.mmdb

View file

@ -116,11 +116,3 @@ class InvalidOS(ValueError):
"""
...
class DetectionWarning(RuntimeWarning):
"""
Raised when a the user has a setting enabled that can cause detection.
"""
...

View file

@ -1,14 +1,13 @@
import os.path
import re
from dataclasses import asdict
from typing import Any, Dict, Optional
from browserforge.fingerprints import Fingerprint, FingerprintGenerator
from yaml import CLoader, load
from camoufox.pkgman import load_yaml
# Load the browserforge.yaml file
with open(os.path.join(os.path.dirname(__file__), 'browserforge.yml'), 'r') as f:
BROWSERFORGE_DATA = load(f, Loader=CLoader)
BROWSERFORGE_DATA = load_yaml('browserforge.yml')
FP_GENERATOR = FingerprintGenerator(browser='firefox', os=('linux', 'macos', 'windows'))

View file

@ -16,6 +16,7 @@ import requests
from platformdirs import user_cache_dir
from tqdm import tqdm
from typing_extensions import TypeAlias
from yaml import CLoader, load
from .exceptions import UnsupportedArchitecture, UnsupportedOS
@ -337,3 +338,11 @@ def unzip(
with ZipFile(zip_file) as zf:
for member in tqdm(zf.infolist(), desc=desc):
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)

View file

@ -1,6 +1,5 @@
import os
import sys
import warnings
from os import environ
from pprint import pprint
from random import randrange
@ -20,7 +19,6 @@ from .addons import (
threaded_try_load_addons,
)
from .exceptions import (
DetectionWarning,
InvalidOS,
InvalidPropertyType,
NonFirefoxFingerprint,
@ -30,6 +28,7 @@ from .fingerprints import from_browserforge, generate_fingerprint
from .ip import Proxy, public_ip, valid_ipv4, valid_ipv6
from .locale import geoip_allowed, get_geolocation, normalize_locale
from .pkgman import OS_NAME, get_path, installed_verstr
from .warnings import LeakWarning
from .xpi_dl import add_default_addons
LAUNCH_FILE = {
@ -197,12 +196,7 @@ def check_custom_fingerprint(fingerprint: Fingerprint) -> None:
'If this is intentional, pass `i_know_what_im_doing=True`.'
)
warnings.warn(
'Passing your own fingerprint is not recommended. '
'BrowserForge fingerprints are automatically generated within Camoufox '
'based on the provided `os` and `screen` constraints.',
category=DetectionWarning,
)
LeakWarning.warn('custom_fingerprint', False)
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
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(
*,
config: Optional[Dict[str, Any]] = None,
@ -282,24 +315,27 @@ def get_launch_options(
if config is None:
config = {}
# Set default values for optional arguments
if addons is None:
addons = []
if args is None:
args = []
if firefox_user_prefs is None:
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
# https://github.com/daijro/camoufox/issues/26
if headless:
warnings.warn(
'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,
)
LeakWarning.warn('headless', i_know_what_im_doing)
elif headless is None:
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
if os:
check_valid_os(os)
@ -366,6 +402,14 @@ def get_launch_options(
geolocation = get_geolocation(geoip)
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
if locale:
parsed_locale = normalize_locale(locale)
@ -391,10 +435,13 @@ def get_launch_options(
if block_webrtc:
firefox_user_prefs['media.peerconnection.enabled'] = False
if allow_webgl:
LeakWarning.warn('allow_webgl', i_know_what_im_doing)
firefox_user_prefs['webgl.disabled'] = False
# Launch
# Load the addons
threaded_try_load_addons(get_debug_port(args), addons)
# Prepare environment variables to pass to Camoufox
env_vars = {
**get_env_vars(config, target_os),
**(cast(Dict[str, Union[str, float, bool]], environ) if env is None else env),

View 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)

View 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.

View file

@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "camoufox"
version = "0.2.7"
version = "0.2.8"
description = "Wrapper around Playwright to help launch Camoufox"
authors = ["daijro <daijro.dev@gmail.com>"]
license = "MIT"