mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
feat(fingerprint): 引入 per-key 请求指纹系统,替代全局 TLS 指纹开关
为每个 ProviderAPIKey 生成并持久化独立的请求指纹配置,涵盖 TLS impersonate profile、浏览器 UA、Stainless SDK 头部、Node/Chrome/Electron 版本等维度。 指纹基于 key ID 确定性生成,支持手动编辑和批量重新生成。 - 新增 fingerprint 模块:生成、加载、校验、懒持久化 - 数据库迁移:provider_api_keys 新增 fingerprint JSON 列 - 请求链路注入:handler 基类设置上下文指纹,request_builder 和 envelope 消费 - HTTP Client 支持动态 impersonate profile 选择 - Antigravity 适配器使用指纹覆盖 UA/session/Node 版本 - 前端移除手动 TLS 指纹开关,新增批量 regenerate_fingerprint 操作 - 号池管理 UI 优化:token 缩写格式、blocked 行样式、时间显示改为日期格式
This commit is contained in:
@@ -32,6 +32,8 @@ from src.core.api_format.headers import (
|
||||
HeaderBuilder,
|
||||
build_adapter_base_headers_for_endpoint,
|
||||
build_adapter_headers_for_endpoint,
|
||||
build_anthropic_extra_headers,
|
||||
build_browser_fingerprint_headers,
|
||||
build_upstream_headers_for_endpoint,
|
||||
detect_capabilities_for_endpoint,
|
||||
extract_client_api_key_for_endpoint,
|
||||
@@ -119,6 +121,8 @@ __all__ = [
|
||||
"detect_capabilities_for_endpoint",
|
||||
"HeaderBuilder",
|
||||
"build_upstream_headers_for_endpoint",
|
||||
"build_browser_fingerprint_headers",
|
||||
"build_anthropic_extra_headers",
|
||||
"merge_headers_with_protection",
|
||||
"filter_response_headers",
|
||||
"redact_headers_for_log",
|
||||
|
||||
@@ -14,7 +14,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
from collections.abc import Set as AbstractSet
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from src.core.api_format.enums import ApiFamily
|
||||
from src.core.api_format.metadata import (
|
||||
@@ -26,6 +26,9 @@ from src.core.api_format.metadata import (
|
||||
from src.core.api_format.signature import EndpointSignature, parse_signature_key
|
||||
from src.core.logger import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.services.provider.fingerprint import FingerprintProfile
|
||||
|
||||
# =============================================================================
|
||||
# 头部常量定义
|
||||
# =============================================================================
|
||||
@@ -125,6 +128,59 @@ RESPONSE_DROP_HEADERS: frozenset[str] = (
|
||||
)
|
||||
|
||||
|
||||
_DEFAULT_CHROME_MAJOR = "140"
|
||||
|
||||
|
||||
def _extract_chrome_major(version: str) -> str:
|
||||
value = str(version or "").strip()
|
||||
if not value:
|
||||
return _DEFAULT_CHROME_MAJOR
|
||||
return value.split(".", 1)[0] or _DEFAULT_CHROME_MAJOR
|
||||
|
||||
|
||||
def _resolve_sec_ch_platform(fp: FingerprintProfile) -> str:
|
||||
os_name = (fp.stainless_os or "").strip().lower()
|
||||
platform_info = (fp.platform_info or "").strip().lower()
|
||||
|
||||
if os_name.startswith("win") or "windows" in platform_info:
|
||||
return '"Windows"'
|
||||
if os_name in {"mac", "macos", "darwin"} or "darwin" in platform_info:
|
||||
return '"macOS"'
|
||||
return '"Linux"'
|
||||
|
||||
|
||||
def build_browser_fingerprint_headers(fp: FingerprintProfile | None = None) -> dict[str, str]:
|
||||
"""Build browser fingerprint headers, optionally overridden by per-key fingerprint."""
|
||||
headers = {**BROWSER_FINGERPRINT_HEADERS}
|
||||
if fp is None:
|
||||
return headers
|
||||
|
||||
chrome_major = _extract_chrome_major(fp.chrome_version)
|
||||
headers["User-Agent"] = fp.user_agent or headers["User-Agent"]
|
||||
headers["sec-ch-ua"] = f'"Not=A?Brand";v="24", "Chromium";v="{chrome_major}"'
|
||||
headers["sec-ch-ua-platform"] = _resolve_sec_ch_platform(fp)
|
||||
return headers
|
||||
|
||||
|
||||
def build_anthropic_extra_headers(fp: FingerprintProfile | None = None) -> dict[str, str]:
|
||||
"""Build Anthropic extra headers, optionally overridden by per-key fingerprint."""
|
||||
headers = {**_ANTHROPIC_EXTRA_HEADERS}
|
||||
if fp is None:
|
||||
return headers
|
||||
|
||||
headers["x-stainless-os"] = fp.stainless_os or headers["x-stainless-os"]
|
||||
headers["x-stainless-arch"] = fp.stainless_arch or headers["x-stainless-arch"]
|
||||
headers["x-stainless-package-version"] = (
|
||||
fp.stainless_package_version or headers["x-stainless-package-version"]
|
||||
)
|
||||
# browser:chrome runtime-version = Chrome 版本;
|
||||
# CLI 路径(ClaudeCodeEnvelope)使用 Node.js,其 extra_headers 会以 fp.stainless_runtime_version 覆盖。
|
||||
headers["x-stainless-runtime-version"] = (
|
||||
fp.chrome_version or headers["x-stainless-runtime-version"]
|
||||
)
|
||||
return headers
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 请求头规范化
|
||||
# =============================================================================
|
||||
@@ -568,12 +624,12 @@ def build_adapter_base_headers_for_endpoint(
|
||||
auth_value = f"Bearer {api_key}" if auth_type == "bearer" else api_key
|
||||
|
||||
# 以浏览器指纹为底层默认值,绕过 Cloudflare 等反爬防护
|
||||
headers: dict[str, str] = {**BROWSER_FINGERPRINT_HEADERS}
|
||||
headers: dict[str, str] = build_browser_fingerprint_headers()
|
||||
|
||||
# Claude API family 额外注入 Anthropic 专属 header
|
||||
definition = resolve_endpoint_definition(endpoint)
|
||||
if definition and definition.api_family == ApiFamily.CLAUDE:
|
||||
headers.update(_ANTHROPIC_EXTRA_HEADERS)
|
||||
headers.update(build_anthropic_extra_headers())
|
||||
|
||||
headers[auth_header] = auth_value
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
Reference in New Issue
Block a user