吸收上游 26 个新 commit: - feat: Airwallex 支付 + 多币种支持 (b23055af) - feat: Antigravity user agent 版本可配置 (a07a0dac) - fix(mimic): 同步 messages 里 tool_use 名称 (f97b8534) - fix: cache_control 改写默认关闭 (9377c967) - fix(openai): 多 tool_use 上下文延续 (87d73236) - fix(openai): 未定价模型零成本记录 (6d69ae87) - fix(openai): WS replay tool 输出延续 (16a31557) - fix(openai): 429 plan type 同步 (c3a14717) - fix(gemini): Vertex token 走 account proxy (2a17c0b2) - fix(ccswitch): codex 模型 import deeplink (65493df9) - fix: 订单详情/支付页 NaN 修复 (ba1c6fa5, 6884b03e) - 系统设置标签导航优化 (18cc4691) 本地解决: - config.go CSP: 合并 Firebase Auth (Windsurf) + Airwallex 域名 - KeysView.vue: 删除死代码(已被 buildCcSwitchImportDeeplink 取代) - ccswitchImport.ts: 补充 windsurf 平台 case - 修复 NewOpsHandler/RegisterGatewayRoutes/SelectAccountWithScheduler 测试签名 保留: - Antigravity newapi 兼容 (ForwardUpstream /v1/messages 透传) - Antigravity 核心(gateway_service, oauth, client, credits_overages 等) - Windsurf 全套 - Claude 网关 + TLS 指纹路由 - 其他本地 feat: P2C 调度 / viewer / context 压缩 / RPM / fallback / health
92 lines
3.2 KiB
Go
92 lines
3.2 KiB
Go
package repository
|
||
|
||
// ==============================================================
|
||
// antigravity — Go 原生 TLS 指纹扩展
|
||
//
|
||
// 此文件包含 Antigravity fork 新增的 TLS 指纹代理功能,
|
||
// 与 upstream 代码完全隔离,便于 upstream 更新时的合并维护。
|
||
//
|
||
// 上游文件 http_upstream.go 中的钩子调用点:
|
||
// Do() — 匹配主机时路由到 doWithTLSFingerprint
|
||
// DoWithTLS() — profile==nil 时回退到 Do(),触发同样的路由
|
||
//
|
||
// 替代原先的 Node.js TLS 代理(node-tls-proxy),
|
||
// 直接使用 Go utls 库模拟 Claude CLI 的 TLS 指纹。
|
||
// ==============================================================
|
||
|
||
import (
|
||
"log/slog"
|
||
"net/http"
|
||
|
||
"github.com/Wei-Shaw/sub2api/internal/pkg/tlsfingerprint"
|
||
"github.com/Wei-Shaw/sub2api/internal/util/logredact"
|
||
)
|
||
|
||
// isTLSFingerprintRoutingEnabled 检查 TLS 指纹路由是否启用
|
||
// 使用 TLSFingerprint.Enabled 配置项(而不是旧的 NodeTLSProxy.Enabled)
|
||
func (s *httpUpstreamService) isTLSFingerprintRoutingEnabled() bool {
|
||
if s.cfg == nil {
|
||
return false
|
||
}
|
||
return s.cfg.Gateway.TLSFingerprint.Enabled
|
||
}
|
||
|
||
// shouldRouteWithTLSFingerprint 判断请求是否应该使用 TLS 指纹
|
||
// 拦截目标主机在 proxy_hosts 白名单中的 HTTPS 请求
|
||
// 白名单为空时默认代理 api.anthropic.com 和 Antigravity API 主机
|
||
func (s *httpUpstreamService) shouldRouteWithTLSFingerprint(req *http.Request) bool {
|
||
if req == nil || req.URL == nil || req.URL.Scheme != "https" {
|
||
return false
|
||
}
|
||
reqHost := req.URL.Hostname()
|
||
if reqHost == "" {
|
||
return false
|
||
}
|
||
|
||
hosts := s.cfg.Gateway.NodeTLSProxy.ProxyHosts
|
||
if len(hosts) == 0 {
|
||
// 默认白名单:api.anthropic.com 和 Antigravity API 主机
|
||
defaultHosts := map[string]bool{
|
||
"api.anthropic.com": true,
|
||
"cloudcode-pa.googleapis.com": true,
|
||
"daily-cloudcode-pa.googleapis.com": true,
|
||
}
|
||
return defaultHosts[reqHost]
|
||
}
|
||
for _, h := range hosts {
|
||
if reqHost == h {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// defaultTLSProfile 返回模拟 Claude CLI (Node.js 24.x) 的默认 TLS 指纹配置
|
||
// 所有 slice 字段留空 → dialer.go 自动使用内置的 Node.js 24.x 默认值
|
||
// ALPN 仅声明 http/1.1,与真实 CLI 行为一致(undici allowH2=false)
|
||
func defaultTLSProfile() *tlsfingerprint.Profile {
|
||
return &tlsfingerprint.Profile{
|
||
Name: "claude_cli_builtin",
|
||
EnableGREASE: true,
|
||
}
|
||
}
|
||
|
||
// doWithTLSFingerprint 使用 Go 原生 utls TLS 指纹发送请求
|
||
// 直接通过 DoWithTLS 路径,利用已有的 utls dialer 基础设施:
|
||
// - 直连:Dialer (TCP → utls handshake)
|
||
// - HTTP 代理:HTTPProxyDialer (CONNECT 隧道 → utls handshake)
|
||
// - SOCKS5 代理:SOCKS5ProxyDialer (SOCKS5 隧道 → utls handshake)
|
||
func (s *httpUpstreamService) doWithTLSFingerprint(req *http.Request, proxyURL string, accountID int64, accountConcurrency int) (*http.Response, error) {
|
||
proxyInfo := "direct"
|
||
if proxyURL != "" {
|
||
proxyInfo = logredact.RedactProxyURL(proxyURL)
|
||
}
|
||
slog.Debug("tls_fingerprint_routing",
|
||
"account_id", accountID,
|
||
"target", req.URL.Host,
|
||
"proxy", proxyInfo,
|
||
)
|
||
|
||
return s.DoWithTLS(req, proxyURL, accountID, accountConcurrency, defaultTLSProfile())
|
||
}
|