- windsurf_gateway_service: 添加上游延迟/TTFT/错误上下文记录 - endpoint: DeriveUpstreamEndpoint 添加 PlatformWindsurf 分支 - ops_error_logger: guessPlatformFromPath 添加 /windsurf/ 识别
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())
|
||
}
|