impersonate-proxy 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- impersonate_proxy-0.2.1/LICENSE +21 -0
- impersonate_proxy-0.2.1/PKG-INFO +15 -0
- impersonate_proxy-0.2.1/README.md +143 -0
- impersonate_proxy-0.2.1/pyproject.toml +90 -0
- impersonate_proxy-0.2.1/setup.cfg +4 -0
- impersonate_proxy-0.2.1/src/impersonate_proxy/__init__.py +1 -0
- impersonate_proxy-0.2.1/src/impersonate_proxy/main.py +735 -0
- impersonate_proxy-0.2.1/src/impersonate_proxy.egg-info/PKG-INFO +15 -0
- impersonate_proxy-0.2.1/src/impersonate_proxy.egg-info/SOURCES.txt +16 -0
- impersonate_proxy-0.2.1/src/impersonate_proxy.egg-info/dependency_links.txt +1 -0
- impersonate_proxy-0.2.1/src/impersonate_proxy.egg-info/entry_points.txt +2 -0
- impersonate_proxy-0.2.1/src/impersonate_proxy.egg-info/requires.txt +8 -0
- impersonate_proxy-0.2.1/src/impersonate_proxy.egg-info/top_level.txt +1 -0
- impersonate_proxy-0.2.1/tests/test_cert_cache.py +67 -0
- impersonate_proxy-0.2.1/tests/test_helpers.py +76 -0
- impersonate_proxy-0.2.1/tests/test_proxy_http.py +200 -0
- impersonate_proxy-0.2.1/tests/test_proxy_live.py +63 -0
- impersonate_proxy-0.2.1/tests/test_proxy_live_extended.py +281 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nicholas de Jong
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: impersonate-proxy
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: HTTP/HTTPS proxy that impersonates browser TLS fingerprints using curl_cffi
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: curl_cffi>=0.7.0
|
|
9
|
+
Requires-Dist: cryptography>=42.0.0
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: basedpyright>=1.20.0; extra == "dev"
|
|
12
|
+
Requires-Dist: ruff>=0.8.0; extra == "dev"
|
|
13
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
14
|
+
Requires-Dist: requests>=2.28.0; extra == "dev"
|
|
15
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# impersonate-proxy
|
|
2
|
+
|
|
3
|
+
> [!NOTE]
|
|
4
|
+
> This project is a fork of the original source project [hauxir/tls-impersonate-proxy](https://github.com/hauxir/tls-impersonate-proxy) maintained at [psaintelligence/impersonate-proxy](https://github.com/psaintelligence/impersonate-proxy).
|
|
5
|
+
|
|
6
|
+
HTTP/HTTPS proxy that impersonates browser TLS fingerprints using [curl_cffi](https://github.com/lexiforest/curl_cffi). Defeats JA3/JA4 TLS fingerprinting used by CDNs to block non-browser clients.
|
|
7
|
+
|
|
8
|
+
## How it works
|
|
9
|
+
|
|
10
|
+
Many CDNs use TLS fingerprinting (JA3/JA4) to distinguish real browsers from tools like ffmpeg, curl, wget, etc. This proxy sits between your client and the internet, re-issuing every request with a browser TLS fingerprint via curl_cffi.
|
|
11
|
+
|
|
12
|
+
- **HTTP requests**: Proxied directly with browser TLS fingerprint
|
|
13
|
+
- **HTTPS requests**: MITM (Man-in-the-Middle) with certificates signed by a local CA, then re-issued with browser TLS fingerprint
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install git+https://github.com/psaintelligence/impersonate-proxy.git
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or with [uv](https://github.com/astral-sh/uv):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv pip install git+https://github.com/psaintelligence/impersonate-proxy.git
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Start the proxy (default: 127.0.0.1:8899)
|
|
35
|
+
impersonate-proxy
|
|
36
|
+
|
|
37
|
+
# Custom port and host
|
|
38
|
+
impersonate-proxy --port 9000 --host 0.0.0.0
|
|
39
|
+
|
|
40
|
+
# Different browser fingerprint
|
|
41
|
+
impersonate-proxy --impersonate edge101
|
|
42
|
+
|
|
43
|
+
# Custom CA certificate storage directory
|
|
44
|
+
impersonate-proxy --ca-dir ~/.my-certs
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### With ffmpeg
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
ffmpeg -http_proxy http://127.0.0.1:8899 -i https://stream.example.com/live.m3u8 output.mp4
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### With curl
|
|
54
|
+
|
|
55
|
+
To use the proxy with HTTPS requests, you must pass the generated CA certificate to curl or install it in your system trust store:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
curl --cacert ~/.config/impersonate-proxy/ca.crt -x http://127.0.0.1:8899 https://example.com
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### With any HTTP client
|
|
62
|
+
|
|
63
|
+
Set the `http_proxy` / `https_proxy` environment variables:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
export http_proxy=http://127.0.0.1:8899
|
|
67
|
+
export https_proxy=http://127.0.0.1:8899
|
|
68
|
+
|
|
69
|
+
# For Python HTTP clients (requests, httpx)
|
|
70
|
+
export REQUESTS_CA_BUNDLE=~/.config/impersonate-proxy/ca.crt
|
|
71
|
+
export SSL_CERT_FILE=~/.config/impersonate-proxy/ca.crt
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Configuration Options
|
|
77
|
+
|
|
78
|
+
| Command Line Option | Environment Variable | Default | Description |
|
|
79
|
+
|---|---|---|---|
|
|
80
|
+
| `--port` / `-p` | `IMPERSONATE_PROXY_PORT` | `8899` | Port to listen on |
|
|
81
|
+
| `--host` / `-H` | `IMPERSONATE_PROXY_HOST` | `127.0.0.1` | Host to bind to |
|
|
82
|
+
| `--impersonate` / `-i` | `IMPERSONATE_PROXY_IMPERSONATE` | `chrome` | Browser to impersonate |
|
|
83
|
+
| `--ca-dir` / `-c` | `IMPERSONATE_PROXY_CA_DIR` | `~/.config/impersonate-proxy` | Directory to load/store the CA files |
|
|
84
|
+
| `--no-enrich-headers` | `IMPERSONATE_PROXY_ENRICH_HEADERS=false` | *(enrichment on)* | Disable automatic browser header injection (User-Agent, Sec-Fetch-*, etc.) |
|
|
85
|
+
| `--debug` / `-d` | `IMPERSONATE_PROXY_DEBUG` | `false` | Enable verbose debug logging and show identifying details in logs |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## How HTTPS works
|
|
90
|
+
|
|
91
|
+
For HTTPS, the proxy uses MITM (Man-in-the-Middle):
|
|
92
|
+
|
|
93
|
+
1. On startup, the proxy loads or generates the CA private key (`ca.key`) and self-signed certificate (`ca.crt`) in the specified `--ca-dir`. Existing keys/certs in the directory are reused.
|
|
94
|
+
2. When a client sends a CONNECT request, the proxy wraps the connection with a dynamically generated site-specific certificate signed by the CA (generated quickly using ECDSA P-256 keys).
|
|
95
|
+
3. The proxy reads the decrypted HTTP requests inside the secure tunnel and forwards them using `curl_cffi` with browser TLS signatures.
|
|
96
|
+
4. If the CA files cannot be loaded or generated, the proxy falls back to a raw TCP tunnel (no TLS impersonation for HTTPS).
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Docker
|
|
101
|
+
|
|
102
|
+
You can run the proxy inside Docker using the provided `Dockerfile` and `docker-compose.yml`.
|
|
103
|
+
|
|
104
|
+
### Docker Compose
|
|
105
|
+
|
|
106
|
+
1. Start the container:
|
|
107
|
+
```bash
|
|
108
|
+
docker compose up -d
|
|
109
|
+
```
|
|
110
|
+
2. Retrieve the generated CA certificate from the volume (to use in client requests):
|
|
111
|
+
```bash
|
|
112
|
+
docker cp impersonate-proxy:/certs/ca.crt ./ca.crt
|
|
113
|
+
```
|
|
114
|
+
3. Test the proxy connection:
|
|
115
|
+
```bash
|
|
116
|
+
curl --cacert ./ca.crt -x http://127.0.0.1:8899 https://example.com
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Development
|
|
122
|
+
|
|
123
|
+
Make targets are available for development tasks (utilizing an isolated `uv` virtual environment):
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
make setup # Setup environment and dependencies
|
|
127
|
+
make sync # Synchronize python dependencies
|
|
128
|
+
make lint # Check code format and style
|
|
129
|
+
make lint-fix # Automatically format and fix issues
|
|
130
|
+
make typecheck # Run basedpyright static type checker
|
|
131
|
+
make test # Run offline unit and integration tests
|
|
132
|
+
make test-verbose # Run tests with verbose output
|
|
133
|
+
make test-live # Run basic live tests (hit real URLs)
|
|
134
|
+
make test-extended # Run extended bot-detection fingerprint tests
|
|
135
|
+
make benchmark # Run concurrency performance benchmark
|
|
136
|
+
make docs-sync # Sync documentation dependencies
|
|
137
|
+
make docs-build # Build documentation site
|
|
138
|
+
make docs-serve # Serve documentation locally
|
|
139
|
+
make build # Build wheel and source distributions
|
|
140
|
+
make bump-patch # Bump version patch number
|
|
141
|
+
make bump-minor # Bump version minor number
|
|
142
|
+
make clean # Remove build and cache directories
|
|
143
|
+
```
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.setuptools]
|
|
6
|
+
package-dir = {"" = "src"}
|
|
7
|
+
packages = ["impersonate_proxy"]
|
|
8
|
+
|
|
9
|
+
[tool.setuptools.dynamic]
|
|
10
|
+
version = {attr = "impersonate_proxy.__version__"}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
[project]
|
|
14
|
+
name = "impersonate-proxy"
|
|
15
|
+
dynamic = ["version"]
|
|
16
|
+
description = "HTTP/HTTPS proxy that impersonates browser TLS fingerprints using curl_cffi"
|
|
17
|
+
requires-python = ">=3.12"
|
|
18
|
+
license = "MIT"
|
|
19
|
+
dependencies = [
|
|
20
|
+
"curl_cffi>=0.7.0",
|
|
21
|
+
"cryptography>=42.0.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.scripts]
|
|
25
|
+
impersonate-proxy = "impersonate_proxy.main:main"
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
dev = [
|
|
29
|
+
"basedpyright>=1.20.0",
|
|
30
|
+
"ruff>=0.8.0",
|
|
31
|
+
"pytest>=7.0.0",
|
|
32
|
+
"requests>=2.28.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[tool.ruff]
|
|
36
|
+
target-version = "py312"
|
|
37
|
+
line-length = 120
|
|
38
|
+
indent-width = 4
|
|
39
|
+
|
|
40
|
+
[tool.ruff.lint]
|
|
41
|
+
select = [
|
|
42
|
+
"E",
|
|
43
|
+
"W",
|
|
44
|
+
"F",
|
|
45
|
+
"I",
|
|
46
|
+
"B",
|
|
47
|
+
"C4",
|
|
48
|
+
"UP",
|
|
49
|
+
"SIM",
|
|
50
|
+
]
|
|
51
|
+
ignore = [
|
|
52
|
+
"E501",
|
|
53
|
+
"SIM108",
|
|
54
|
+
]
|
|
55
|
+
fixable = ["ALL"]
|
|
56
|
+
|
|
57
|
+
[tool.ruff.format]
|
|
58
|
+
quote-style = "double"
|
|
59
|
+
indent-style = "space"
|
|
60
|
+
skip-magic-trailing-comma = false
|
|
61
|
+
line-ending = "auto"
|
|
62
|
+
|
|
63
|
+
[tool.ruff.lint.isort]
|
|
64
|
+
known-first-party = ["impersonate_proxy"]
|
|
65
|
+
|
|
66
|
+
[tool.basedpyright]
|
|
67
|
+
pythonVersion = "3.12"
|
|
68
|
+
typeCheckingMode = "standard"
|
|
69
|
+
reportMissingImports = "none"
|
|
70
|
+
reportMissingTypeStubs = "none"
|
|
71
|
+
reportUnknownMemberType = "none"
|
|
72
|
+
reportUnknownArgumentType = "none"
|
|
73
|
+
reportUnknownVariableType = "none"
|
|
74
|
+
reportUnknownLambdaType = "none"
|
|
75
|
+
reportUnknownParameterType = "none"
|
|
76
|
+
reportGeneralTypeIssues = "none"
|
|
77
|
+
reportArgumentType = "none"
|
|
78
|
+
reportAttributeAccessIssue = "none"
|
|
79
|
+
reportOptionalMemberAccess = "none"
|
|
80
|
+
reportPossiblyUnboundVariable = "none"
|
|
81
|
+
include = ["src/impersonate_proxy"]
|
|
82
|
+
exclude = ["**/node_modules", "**/__pycache__", "venv", ".venv"]
|
|
83
|
+
|
|
84
|
+
[tool.pytest.ini_options]
|
|
85
|
+
addopts = "-m \"not live and not live_extended\""
|
|
86
|
+
markers = [
|
|
87
|
+
"live: tests that hit real URLs (deselect with '-m \"not live\"')",
|
|
88
|
+
"live_extended: extended fingerprint/bot-detection tests against known protected sites (run with 'pytest -m live_extended')",
|
|
89
|
+
]
|
|
90
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.1"
|