grok_upstream_headers.go 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. package service
  2. import (
  3. "net/http"
  4. "strings"
  5. "github.com/gin-gonic/gin"
  6. "github.com/Wei-Shaw/sub2api/internal/pkg/tlsfingerprint"
  7. "github.com/Wei-Shaw/sub2api/internal/pkg/xai"
  8. )
  9. // Fixed CLI identity aliases — single source of truth is internal/pkg/xai.
  10. const (
  11. grokClientVersionHeader = xai.CLIStableVersion
  12. grokClientIdentifierHeader = xai.CLIClientIdentifier
  13. grokClientModeHeader = xai.CLIClientMode
  14. )
  15. // defaultGrokUpstreamUserAgent is the pinned Grok CLI / workspace UA.
  16. // Grok upstream must not forward Claude Code / Codex / browser client UAs.
  17. func defaultGrokUpstreamUserAgent() string {
  18. return xai.CLIUserAgent(xai.ResolveCLIVersion())
  19. }
  20. func applyDefaultGrokUpstreamHeaders(req *http.Request) {
  21. if req == nil {
  22. return
  23. }
  24. // Always stamp CLI identity. Do not preserve inbound client UA (Claude Code,
  25. // Codex, curl, etc.) — xAI chat/CLI surfaces fingerprint the client string.
  26. req.Header.Set("User-Agent", defaultGrokUpstreamUserAgent())
  27. req.Header.Set("x-grok-client-version", xai.ResolveCLIVersion())
  28. req.Header.Set("x-grok-client-identifier", grokClientIdentifierHeader)
  29. }
  30. func applyGrokTLSProfileHeaders(req *http.Request, profile *tlsfingerprint.Profile) {
  31. // HEAD Profile is TLS-only (no HTTP UserAgent/Originator fields). Always stamp CLI identity.
  32. applyDefaultGrokUpstreamHeaders(req)
  33. _ = profile
  34. }
  35. // openAITLSFingerprintRuntime is the resolved TLS fingerprint routing result
  36. // used by OpenAI/Grok outbound header application. Defined here so Grok header
  37. // helpers compile even when the full OpenAI TLS router is not present on HEAD.
  38. type openAITLSFingerprintRuntime struct {
  39. Profile *tlsfingerprint.Profile
  40. UpstreamUserAgent string
  41. UpstreamOriginator string
  42. Matched bool
  43. }
  44. func applyGrokRuntimeHeaders(req *http.Request, runtime openAITLSFingerprintRuntime) {
  45. applyDefaultGrokUpstreamHeaders(req)
  46. if req == nil {
  47. return
  48. }
  49. // Apply Originator only; force CLI UA after so router overrides cannot
  50. // leak Codex/Claude Code identity onto Grok upstream.
  51. if originator := strings.TrimSpace(runtime.UpstreamOriginator); originator != "" {
  52. req.Header.Set("Originator", originator)
  53. }
  54. req.Header.Set("User-Agent", defaultGrokUpstreamUserAgent())
  55. }
  56. // resolveGrokUpstreamUserAgent always returns the pinned Grok CLI User-Agent.
  57. // Inbound client UAs (Claude Code, Codex, browsers, libraries) are never forwarded.
  58. func resolveGrokUpstreamUserAgent(_ *gin.Context) string {
  59. return defaultGrokUpstreamUserAgent()
  60. }