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
75 lines
2.6 KiB
Go
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()
|
|
}
|