Metadata-Version: 2.4
Name: final_tls
Version: 0.4.2
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Intended Audience :: Developers
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Security
Summary: 从0自建的 Firefox 151 网络指纹模拟客户端(TLS 1.2/1.3 + HTTP/1.1/2 + ECH;HTTP/3 可选),Rust + PyO3
Keywords: tls,tls-fingerprint,ja3,ja4,http2,http3,fingerprint,firefox,ech,pyo3,http-client,scraping
Author-email: Bin <lulufubin@163.com>
License: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/lulufubin/final-tls
Project-URL: Issues, https://github.com/lulufubin/final-tls/issues
Project-URL: Repository, https://github.com/lulufubin/final-tls

# final-tls

**Firefox 151** 网络指纹模拟 HTTP 客户端(Python),JA3 / JA4 / Akamai 指纹与真实浏览器逐项一致,用法接近 `requests`。
A **Firefox 151** TLS/HTTP fingerprint HTTP client for Python — JA3 / JA4 / Akamai match the real browser, `requests`-like API.

**[中文](#中文) · [English](#english)**

```python
import json
from final_tls import Session

s = Session()
print(json.loads(s.get("https://tls.peet.ws/api/all").text())["tls"]["ja4"])
# t13d1717h2_5b57614c22b0_3cbfd9057e0d
```

---

<a name="中文"></a>

## 中文

### ✨ 功能

- **真·Firefox 151 指纹** —— JA3 / JA4 / Akamai HTTP2 指纹与真实浏览器逐项一致,非简单改 UA。
- **像 requests 一样用** —— `Session` 跨请求自动复用连接池 / Cookie / TLS 会话票据。
- **同步 + 异步 + 并发批量** —— `get`/`post`、`get_async`/`post_async`、`request_many`/`request_many_async`。
- **释放 GIL** —— 每个请求在网络期间释放 GIL,多线程真正并行。
- **完整 Cookie jar** —— 解析 `Set-Cookie`,按 domain/path/secure 自动回带(跨重定向有效),可读可写。
- **持久化请求头** —— 会话级默认头(优先级:Firefox 默认 < 会话头 < 单次请求头)。
- **自动重定向** —— 301/302/303/307/308,按浏览器规则调整方法/请求体,跨 origin 自动剥离敏感头。
- **代理** —— HTTP CONNECT / SOCKS5。
- **自动解压** —— gzip / deflate / brotli / zstd。
- **重试 / 超时** —— 网络错误重试、坏连接自动重连、可配超时。

### 🔧 核心

- 自研 TLS / HTTP 协议栈,指纹与真实 **Firefox 151** 逐项一致。
- **TLS**:TLS 1.3(X25519MLKEM768 后量子混合密钥交换)、TLS 1.2 回退(ECDHE / RSA、GCM / CBC)、会话复用 + 0-RTT、真实 ECH(经 DoH 取 ECHConfig + HPKE)。
- **HTTP**:HTTP/2(HPACK + Firefox SETTINGS / 窗口 / 伪头顺序)、HTTP/1.1(keep-alive)。
- **平台**:Windows / CPython 3.11+(abi3,一个 wheel 通吃 3.11+)。

### 💡 示例

完整示例见 [`examples/`](https://github.com/lulufubin/final-env-public/tree/main/examples):

| 文件 | 内容 |
|---|---|
| [`01_basic.py`](https://github.com/lulufubin/final-env-public/blob/main/examples/01_basic.py) | 基础 get / post |
| [`02_session_cookies.py`](https://github.com/lulufubin/final-env-public/blob/main/examples/02_session_cookies.py) | Session 复用、Cookie、持久化头 |
| [`03_concurrent.py`](https://github.com/lulufubin/final-env-public/blob/main/examples/03_concurrent.py) | 并发批量 + 多线程 |
| [`04_async.py`](https://github.com/lulufubin/final-env-public/blob/main/examples/04_async.py) | 异步(asyncio) |

### 📖 使用

```python
from final_tls import Session

s = Session(timeout=30)                 # 复用同一实例:连接池 / Cookie / TLS 票据全共享

# 同步
r = s.get("https://example.com/")
print(r.status, r.text()[:80], len(r.content()))
s.post("https://httpbin.org/post", data=b'{"x":1}', headers={"Content-Type": "application/json"})

# 会话级头 + Cookie
s.headers = {"Authorization": "Bearer xxx"}
s.set_cookie("sid", "abc", domain="example.com")
print(s.cookies)

# 并发批量(内置,多线程,GIL 释放)
rs = s.request_many(["https://example.com/"] * 100, concurrency=32)

# 异步
import asyncio
async def main():
    rs = await s.request_many_async(["https://example.com/"] * 100, concurrency=32)
asyncio.run(main())

# 代理
s = Session(proxy="127.0.0.1:7890")     # 或 {"https": "...", "socks5": "..."}
```

**API 速览**:`Session(proxy, timeout, max_redirects, retries, pool_per_host, ech)` ·
`get/post` · `get_async/post_async` · `request_many/request_many_async` ·
`headers`(读/写)/`set_header` · `cookies`/`set_cookie`/`clear_cookies` · `ech` · `close()` · `with` / `async with`。
`Response`:`status` / `headers` / `text()` / `content()`。请求失败抛 `RuntimeError`。

### 📦 安装

```bash
pip install final_tls
# 或用 uv / or with uv
uv add final_tls
```

> Windows / CPython 3.11+。

### 🔗 与 RuyiTrace 配合

[RuyiTrace(Firefox-FingerPrint-Analyzer)](https://github.com/LoseNine/Firefox-FingerPrint-Analyzer) 是一款桌面研究工具:用**定制 Firefox 内核**(C++ 级探针,页面脚本无法察觉)采集目标站在**浏览器 / JS 层**的指纹采集与风控逻辑(Canvas / WebGL / WebRTC / Audio / Navigator / Screen / Crypto 等 API 调用 + 调用栈),导出 NDJSON 日志供分析。

二者**互补,覆盖两个层面**:

| 层面 | 工具 | 负责 |
|---|---|---|
| 网络 / 传输层 | **final-tls** | TLS / HTTP 指纹(JA3 / JA4 / Akamai)与真实 Firefox 一致 |
| 浏览器 / JS 层 | **RuyiTrace** | 分析目标站的 JS 指纹采集与风控策略(查了什么、怎么查) |

**典型配合工作流**:

1. 用 **RuyiTrace** 采集分析目标站,搞清它在 JS 层检测哪些指纹、期望什么浏览器环境。
2. 用 **final-tls** 发请求,让**网络层 TLS / HTTP 指纹**与该浏览器(Firefox 151)逐项一致。
3. 两层对齐——网络指纹 + 浏览器指纹一致——更贴近真实浏览器。

### ⚠️ 免责声明

本项目仅供技术研究与学习交流,请勿用于任何违法用途。使用者须自行遵守目标网站服务条款及所在地法律法规。
本软件按 "AS IS" 提供,不提供任何担保;因使用产生的一切风险、损失与法律责任均由使用者自行承担,作者不承担任何责任。

---

<a name="english"></a>

## English

### ✨ Features

- **Real Firefox 151 fingerprint** — JA3 / JA4 / Akamai HTTP2 match a real browser, not just a spoofed UA.
- **`requests`-like API** — `Session` reuses connection pool / cookies / TLS session tickets across requests.
- **Sync + async + concurrent batch** — `get`/`post`, `get_async`/`post_async`, `request_many`/`request_many_async`.
- **GIL released** — every request releases the GIL during I/O, so threads run truly in parallel.
- **Full cookie jar** — parses `Set-Cookie`, auto-sends by domain/path/secure (across redirects), readable & writable.
- **Persistent headers** — session-level default headers (priority: Firefox defaults < session headers < per-call headers).
- **Auto redirects** — 301/302/303/307/308, browser-style method/body handling, strips sensitive headers cross-origin.
- **Proxy** — HTTP CONNECT / SOCKS5.
- **Auto decompression** — gzip / deflate / brotli / zstd.
- **Retry / timeout** — retries on network errors, auto-reconnect of stale connections, configurable timeout.

### 🔧 Core

- Hand-rolled TLS / HTTP stack whose fingerprint matches real **Firefox 151** field-by-field.
- **TLS**: TLS 1.3 (X25519MLKEM768 post-quantum hybrid KEX), TLS 1.2 fallback (ECDHE / RSA, GCM / CBC), session resumption + 0-RTT, real ECH (ECHConfig via DoH + HPKE).
- **HTTP**: HTTP/2 (HPACK + Firefox SETTINGS / window / pseudo-header order), HTTP/1.1 (keep-alive).
- **Platform**: Windows / CPython 3.11+ (abi3 — one wheel for 3.11+).

### 💡 Examples

See [`examples/`](https://github.com/lulufubin/final-env-public/tree/main/examples):

| File | What |
|---|---|
| [`01_basic.py`](https://github.com/lulufubin/final-env-public/blob/main/examples/01_basic.py) | Basic get / post |
| [`02_session_cookies.py`](https://github.com/lulufubin/final-env-public/blob/main/examples/02_session_cookies.py) | Session reuse, cookies, persistent headers |
| [`03_concurrent.py`](https://github.com/lulufubin/final-env-public/blob/main/examples/03_concurrent.py) | Concurrent batch + threading |
| [`04_async.py`](https://github.com/lulufubin/final-env-public/blob/main/examples/04_async.py) | Async (asyncio) |

### 📖 Usage

```python
from final_tls import Session

s = Session(timeout=30)                 # reuse one instance: pool / cookies / TLS tickets shared

# sync
r = s.get("https://example.com/")
print(r.status, r.text()[:80], len(r.content()))
s.post("https://httpbin.org/post", data=b'{"x":1}', headers={"Content-Type": "application/json"})

# session headers + cookies
s.headers = {"Authorization": "Bearer xxx"}
s.set_cookie("sid", "abc", domain="example.com")
print(s.cookies)

# concurrent batch (built-in, threaded, GIL released)
rs = s.request_many(["https://example.com/"] * 100, concurrency=32)

# async
import asyncio
async def main():
    rs = await s.request_many_async(["https://example.com/"] * 100, concurrency=32)
asyncio.run(main())

# proxy
s = Session(proxy="127.0.0.1:7890")     # or {"https": "...", "socks5": "..."}
```

**API at a glance**: `Session(proxy, timeout, max_redirects, retries, pool_per_host, ech)` ·
`get/post` · `get_async/post_async` · `request_many/request_many_async` ·
`headers` (get/set) / `set_header` · `cookies`/`set_cookie`/`clear_cookies` · `ech` · `close()` · `with` / `async with`.
`Response`: `status` / `headers` / `text()` / `content()`. Failures raise `RuntimeError`.

### 📦 Installation

```bash
pip install final_tls
# or with uv
uv add final_tls
```

> Windows / CPython 3.11+.

### 🔗 Integration with RuyiTrace

[RuyiTrace (Firefox-FingerPrint-Analyzer)](https://github.com/LoseNine/Firefox-FingerPrint-Analyzer) is a desktop research tool: it uses a **customized Firefox kernel** (C++-level probes, invisible to page scripts) to capture a target site's **browser / JS-layer** fingerprinting and risk-control logic (Canvas / WebGL / WebRTC / Audio / Navigator / Screen / Crypto API calls + stacks), exporting NDJSON logs for analysis.

The two are **complementary, covering two layers**:

| Layer | Tool | Role |
|---|---|---|
| Network / transport | **final-tls** | TLS / HTTP fingerprint (JA3 / JA4 / Akamai) matching real Firefox |
| Browser / JS | **RuyiTrace** | Analyze the site's JS-level fingerprinting & risk-control strategy (what is checked, and how) |

**Typical workflow**:

1. Use **RuyiTrace** to analyze the target site — learn which fingerprints it checks at the JS layer and which browser environment it expects.
2. Use **final-tls** to send requests so the **network-layer TLS / HTTP fingerprint** matches that browser (Firefox 151) field-by-field.
3. With both layers aligned — network fingerprint + browser fingerprint consistent — you stay closer to a real browser.

### ⚠️ Disclaimer

This project is for technical research and learning only; do not use it for any unlawful purpose. Users must comply with the
target sites' Terms of Service and the laws of their jurisdiction. The software is provided "AS IS" without any warranty; all
risks, losses and legal liability arising from its use are borne solely by the user, and the author assumes no responsibility.

