Files
sub2api/backend/internal/service/grok_upstream_headers.go
T
李建琦 6d655c9903
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
2026-08-21 18:30:13 +08:00

75 lines
2.6 KiB
Go

package service
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/Wei-Shaw/sub2api/internal/pkg/tlsfingerprint"
"github.com/Wei-Shaw/sub2api/internal/pkg/xai"
)
// grokUpstreamUserAgent is kept for compatibility with older Grok request
// tests. Current requests use the pinned default UA from this package.
const grokUpstreamUserAgent = "sub2api-grok/1.0"
// Fixed CLI identity aliases — single source of truth is internal/pkg/xai.
const (
grokClientVersionHeader = xai.CLIStableVersion
grokClientIdentifierHeader = xai.CLIClientIdentifier
grokClientModeHeader = xai.CLIClientMode
)
// defaultGrokUpstreamUserAgent is the pinned Grok CLI / workspace UA.
// Grok upstream must not forward Claude Code / Codex / browser client UAs.
func defaultGrokUpstreamUserAgent() string {
return xai.CLIUserAgent(xai.ResolveCLIVersion())
}
func applyDefaultGrokUpstreamHeaders(req *http.Request) {
if req == nil {
return
}
// Always stamp CLI identity. Do not preserve inbound client UA (Claude Code,
// Codex, curl, etc.) — xAI chat/CLI surfaces fingerprint the client string.
req.Header.Set("User-Agent", defaultGrokUpstreamUserAgent())
req.Header.Set("x-grok-client-version", xai.ResolveCLIVersion())
req.Header.Set("x-grok-client-identifier", grokClientIdentifierHeader)
}
func applyGrokTLSProfileHeaders(req *http.Request, profile *tlsfingerprint.Profile) {
// HEAD Profile is TLS-only (no HTTP UserAgent/Originator fields). Always stamp CLI identity.
applyDefaultGrokUpstreamHeaders(req)
_ = profile
}
// openAITLSFingerprintRuntime is the resolved TLS fingerprint routing result
// used by OpenAI/Grok outbound header application. Defined here so Grok header
// helpers compile even when the full OpenAI TLS router is not present on HEAD.
type openAITLSFingerprintRuntime struct {
Profile *tlsfingerprint.Profile
UpstreamUserAgent string
UpstreamOriginator string
Matched bool
}
func applyGrokRuntimeHeaders(req *http.Request, runtime openAITLSFingerprintRuntime) {
applyDefaultGrokUpstreamHeaders(req)
if req == nil {
return
}
// Apply Originator only; force CLI UA after so router overrides cannot
// leak Codex/Claude Code identity onto Grok upstream.
if originator := strings.TrimSpace(runtime.UpstreamOriginator); originator != "" {
req.Header.Set("Originator", originator)
}
req.Header.Set("User-Agent", defaultGrokUpstreamUserAgent())
}
// resolveGrokUpstreamUserAgent always returns the pinned Grok CLI User-Agent.
// Inbound client UAs (Claude Code, Codex, browsers, libraries) are never forwarded.
func resolveGrokUpstreamUserAgent(_ *gin.Context) string {
return defaultGrokUpstreamUserAgent()
}