Skip to content

Commit

Permalink
Version range control, multi locale usage, etc
Browse files Browse the repository at this point in the history
- Python library now constrains the supported Camoufox version, and will force an update if you are out of date.
- Added support patch for multiple accepted languages #37
- Added pysocks #43
- Added README deprecation notices
- Added public launch_options command
- Bumped python library to 0.3.0
- Full support for beta.12
  • Loading branch information
daijro committed Oct 20, 2024
1 parent 2167188 commit 0ff90fc
Show file tree
Hide file tree
Showing 15 changed files with 369 additions and 554 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ workspace:
else \
echo "Patch is not applied. Proceeding with application..."; \
fi
make checkpoint || trueZ
make checkpoint || true
make patch $(_ARGS)

vcredist_arch := $(shell echo $(arch) | sed 's/x86_64/x64/' | sed 's/i686/x86/')
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ Camoufox aims to be a minimalistic browser for robust fingerprint injection & an

---

> [!NOTE]
> All of the latest documentation is avaliable at [camoufox.com](https://camoufox.com).
> [!WARNING]
> Camoufox is in active development! Releases are avaliable [here](https://github.com/daijro/camoufox/releases), but are not recommended for production use.
> Camoufox is in active development! Releases are avaliable, but are not recommended for production use.
## Features

Expand Down
23 changes: 14 additions & 9 deletions patches/locale-spoofing.patch
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
diff --git a/browser/base/content/browser-init.js b/browser/base/content/browser-init.js
index 16f4dd7d42..63c9c39741 100644
index 2456c5b4c6..826404b1b7 100644
--- a/browser/base/content/browser-init.js
+++ b/browser/base/content/browser-init.js
@@ -109,6 +109,17 @@ var gBrowserInit = {
@@ -109,6 +109,22 @@ var gBrowserInit = {
window.TabBarVisibility.update();
TabsInTitlebar.init();

+ let camouLocale;
+ let language = ChromeUtils.camouGetString("locale:language");
+ let region = ChromeUtils.camouGetString("locale:region");
+ if (language && region) {
+ camouLocale = language + "-" + region + ", " + language;
+ } else {
+ camouLocale = ChromeUtils.camouGetString("navigator.language");
+ // If a list of languages were passed, use them.
+ let camouLocale = ChromeUtils.camouGetString("locale:all")
+ || ChromeUtils.camouGetString("navigator.language");
+ // If locale:all was NOT passed, but locale:language and locale:region was,
+ // fall back to it instead.
+ if (!camouLocale) {
+ let language = ChromeUtils.camouGetString("locale:language");
+ let region = ChromeUtils.camouGetString("locale:region");
+ if (language && region) {
+ camouLocale = language + "-" + region + ", " + language;
+ }
+ }
+ // Set the locale if it was found.
+ if (camouLocale)
+ Services.prefs.setCharPref("intl.accept_languages", camouLocale);
+
Expand Down
287 changes: 4 additions & 283 deletions pythonlib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

</div>

> [!NOTE]
> All the the latest documentation is avaliable [here](https://camoufox.com/python).
---

## What is this?
Expand Down Expand Up @@ -68,286 +71,4 @@ Commands:

## Usage

Camoufox is fully compatible with your existing Playwright code. You only have to change your browser initialization:

#### Sync API

```python
from camoufox.sync_api import Camoufox

with Camoufox(headless=False) as browser:
page = browser.new_page()
page.goto("https://example.com/")
```

#### Async API

```python
from camoufox.async_api import AsyncCamoufox

async with AsyncCamoufox(headless=False) as browser:
page = await browser.new_page()
await page.goto("https://example.com")
```

### Parameters List

<details>

<summary><strong>See parameters list...</strong></summary>

```
Launches a new browser instance for Camoufox.
Accepts all Playwright Firefox launch options, along with the following:
Parameters:
os (Optional[ListOrString]):
Operating system to use for the fingerprint generation.
Can be "windows", "macos", "linux", or a list to randomly choose from.
Default: ["windows", "macos", "linux"]
block_images (Optional[bool]):
Whether to block all images.
block_webrtc (Optional[bool]):
Whether to block WebRTC entirely.
allow_webgl (Optional[bool]):
Whether to allow WebGL. To prevent leaks, only use this for special cases.
geoip (Optional[Union[str, bool]]):
Calculate longitude, latitude, timezone, country, & locale based on the IP address.
Pass the target IP address to use, or `True` to find the IP address automatically.
humanize (Optional[Union[bool, float]]):
Humanize the cursor movement.
Takes either `True`, or the MAX duration in seconds of the cursor movement.
The cursor typically takes up to 1.5 seconds to move across the window.
locale (Optional[str]):
Locale to use in Camoufox.
addons (Optional[List[str]]):
List of Firefox addons to use.
fonts (Optional[List[str]]):
Fonts to load into Camoufox (in addition to the default fonts for the target `os`).
Takes a list of font family names that are installed on the system.
exclude_addons (Optional[List[DefaultAddons]]):
Default addons to exclude. Passed as a list of camoufox.DefaultAddons enums.
screen (Optional[Screen]):
Constrains the screen dimensions of the generated fingerprint.
Takes a browserforge.fingerprints.Screen instance.
fingerprint (Optional[Fingerprint]):
*WILL BE DEPRECATED SOON*
Pass a custom BrowserForge fingerprint. Note: Not all values will be implemented.
If not provided, a random fingerprint will be generated based on the provided
`os` & `screen` constraints.
ff_version (Optional[int]):
Firefox version to use. Defaults to the current Camoufox version.
To prevent leaks, only use this for special cases.
config (Optional[Dict[str, Any]]):
Camoufox properties to use. Camoufox will warn you if you are manually setting
properties that it handles internally.
headless (Union[bool, Literal['virtual']]):
Whether to run the browser in headless mode. Defaults to False.
If you are running linux, passing 'virtual' will use Xvfb.
executable_path (Optional[str]):
Custom Camoufox browser executable path.
firefox_user_prefs (Optional[Dict[str, Any]]):
Firefox user preferences to set.
proxy (Optional[Dict[str, str]]):
Proxy to use for the browser.
Note: If geoip is True, a request will be sent through this proxy to find the target IP.
args (Optional[List[str]]):
Arguments to pass to the browser.
env (Optional[Dict[str, Union[str, float, bool]]]):
Environment variables to set.
persistent_context (Optional[bool]):
Whether to use a persistent context.
debug (Optional[bool]):
Prints the config being sent to Camoufox.
**launch_options (Dict[str, Any]):
Additional Firefox launch options.
```

</details>

Camoufox will warn you if your passed configuration might cause leaks.

---

### GeoIP & Proxy Support

By passing `geoip=True`, or passing in a target IP address, Camoufox will automatically use the target IP's longitude, latitude, timezone, country, locale, & spoof the WebRTC IP address.

It will also calculate and spoof the browser's language based on the distribution of language speakers in the target region.

[See demo](https://i.imgur.com/UhSHfaV.png).

#### Installation

Install Camoufox with the `geoip` extra:

```bash
pip install -U camoufox[geoip]
```

#### Usage

Pass in the proxy dictionary as you would with Playwright's `proxy` parameter:

```python
with Camoufox(
geoip=True,
proxy={
'server': 'http://example.com:8080',
'username': 'username',
'password': 'password'
}
) as browser:
page = browser.new_page()
page.goto("https://www.browserscan.net")
```

<hr width=50>

### Remote Server (experimental)

**Warning! This feature is experimental. It uses a hacky workaround to gain access to undocumented Playwright methods.**

Camoufox can be ran as a remote websocket server. It can be accessed from other devices, and languages other than Python supporting the Playwright API.

#### Launching

To launch a remote server, run the following CLI command:

```bash
python -m camoufox server
```

Or, configure the server with a launch script:

```python
from camoufox.server import launch_server

launch_server(
headless=True,
geoip=True,
proxy={
'server': 'http://example.com:8080',
'username': 'username',
'password': 'password'
}
)
```

#### Connecting

To connect to the remote server, use Playwright's `connect` method:

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
# Example endpoint
browser = p.firefox.connect('ws://localhost:34091/8c7c6cdea3368d937ef7db2277d6647b')
page = browser.new_page()
...
```

**Note:** Because servers only use **one browser instance**, fingerprints will not rotate between sessions. If you plan on using Camoufox at scale, consider rotating the server between sessions.

<hr width=50>

### Virtual Display

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`:

#### Debian-based distros

```bash
sudo apt-get install xvfb
```

#### Arch-based distros

```bash
sudo pacman -S xorg-server-xvfb
```

#### Confirm `Xvfb` is installed:

```bash
$ which Xvfb
/usr/bin/Xvfb
```

Now, passing `headless='virtual'` will spawn a new lightweight virtual display in the background for Camoufox to run in.

<hr width=50>

### BrowserForge Integration

Camoufox is compatible with [BrowserForge](https://github.com/daijro/browserforge) fingerprints.

By default, Camoufox will generate an use a random BrowserForge fingerprint based on the target `os` & `screen` constraints.

```python
from camoufox.sync_api import Camoufox
from browserforge.fingerprints import Screen

with Camoufox(
os=('windows', 'macos', 'linux'),
screen=Screen(max_width=1920, max_height=1080),
) as browser:
page = browser.new_page()
page.goto("https://example.com/")
```

If Camoufox is being ran in headful mode, the max screen size will be generated based on your monitor's dimensions unless otherwise specified.

**Note:** To prevent UA mismatch detection, Camoufox only generates fingerprints with the same browser version as the current Camoufox version by default. If rotating the Firefox version is absolutely necessary, it would be more advisable to rotate between older versions of Camoufox instead.

<details>
<summary>Injecting custom Fingerprint objects...</summary>

> [!WARNING]
> It is recommended to pass `os` & `screen` constraints into Camoufox instead. Camoufox will handle fingerprint generation for you. This will be deprecated in the future.
You can also inject your own Firefox BrowserForge fingerprint into Camoufox.

```python
from camoufox.sync_api import Camoufox
from browserforge.fingerprints import FingerprintGenerator

fg = FingerprintGenerator(browser='firefox')

# Launch Camoufox with a random Firefox fingerprint
with Camoufox(fingerprint=fg.generate()) as browser:
page = browser.new_page()
page.goto("https://example.com/")
```

**Note:** As of now, some properties from BrowserForge fingerprints will not be passed to Camoufox. This is due to the outdated fingerprint dataset from Apify's fingerprint-suite (see [here](https://github.com/apify/fingerprint-suite/discussions/308)). Properties will be re-enabled as soon as an updated dataset is available.

</details>

<hr width=50>

### Config

If needed, Camoufox [config data](https://github.com/daijro/camoufox?tab=readme-ov-file#fingerprint-injection) can be overridden/passed as a dictionary to the `config` parameter. This can be used to enable features that have not yet been implemented into the Python library.

Although, this isn't recommended, as Camoufox will populate this data for you automatically. See the parameters list above for more proper usage.

```python
from camoufox.sync_api import Camoufox

with Camoufox(
config={
'webrtc:ipv4': '123.45.67.89',
'webrtc:ipv6': 'e791:d37a:88f6:48d1:2cad:2667:4582:1d6d',
}
) as browser:
page = browser.new_page()
page.goto("https://www.browserscan.net/webrtc")
```

Camoufox will warn you if you are manually setting properties that the Python library handles internally.

---
All of the latest documentation is avaliable at [camoufox.com/python](https://camoufox.com/python).
10 changes: 9 additions & 1 deletion pythonlib/camoufox/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
from .addons import DefaultAddons
from .async_api import AsyncCamoufox, AsyncNewBrowser
from .sync_api import Camoufox, NewBrowser
from .utils import launch_options

__all__ = ["Camoufox", "NewBrowser", "AsyncCamoufox", "AsyncNewBrowser", "DefaultAddons"]
__all__ = [
"Camoufox",
"NewBrowser",
"AsyncCamoufox",
"AsyncNewBrowser",
"DefaultAddons",
"launch_options",
]
3 changes: 2 additions & 1 deletion pythonlib/camoufox/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def __init__(self) -> None:
self.current_verstr = None

def is_updated_needed(self) -> bool:
# Camoufox is not installed
if self.current_verstr is None:
return True
# If the installed version is not the latest version
Expand Down Expand Up @@ -145,7 +146,7 @@ def version() -> None:

# Check for Camoufox updates
if updater.is_updated_needed():
rprint(f"(Latest: v{updater.verstr})", fg="red")
rprint(f"(Latest supported: v{updater.verstr})", fg="red")
else:
rprint("(Up to date!)", fg="yellow")

Expand Down
Loading

0 comments on commit 0ff90fc

Please sign in to comment.