package service import ( "github.com/Wei-Shaw/sub2api/internal/config" "github.com/Wei-Shaw/sub2api/internal/pkg/openai" "github.com/gin-gonic/gin" ) const ( // CodexClientRestrictionReasonDisabled 表示账号未开启 codex_cli_only。 CodexClientRestrictionReasonDisabled = "codex_cli_only_disabled" // CodexClientRestrictionReasonMatchedUA 表示请求命中官方客户端 UA 白名单。 CodexClientRestrictionReasonMatchedUA = "official_client_user_agent_matched" // CodexClientRestrictionReasonMatchedOriginator 表示请求命中官方客户端 originator 白名单。 CodexClientRestrictionReasonMatchedOriginator = "official_client_originator_matched" // CodexClientRestrictionReasonNotMatchedUA 表示请求未命中官方客户端 UA 白名单。 CodexClientRestrictionReasonNotMatchedUA = "official_client_user_agent_not_matched" // CodexClientRestrictionReasonForceCodexCLI 表示通过 ForceCodexCLI 配置兜底放行。 CodexClientRestrictionReasonForceCodexCLI = "force_codex_cli_enabled" ) // CodexClientRestrictionDetectionResult 是 codex_cli_only 统一检测入口结果。 type CodexClientRestrictionDetectionResult struct { Enabled bool Matched bool Reason string } // CodexClientRestrictionDetector 定义 codex_cli_only 统一检测入口。 type CodexClientRestrictionDetector interface { Detect(c *gin.Context, account *Account) CodexClientRestrictionDetectionResult } // OpenAICodexClientRestrictionDetector 为 OpenAI OAuth codex_cli_only 的默认实现。 type OpenAICodexClientRestrictionDetector struct { cfg *config.Config } func NewOpenAICodexClientRestrictionDetector(cfg *config.Config) *OpenAICodexClientRestrictionDetector { return &OpenAICodexClientRestrictionDetector{cfg: cfg} } func (d *OpenAICodexClientRestrictionDetector) Detect(c *gin.Context, account *Account) CodexClientRestrictionDetectionResult { if account == nil || !account.IsCodexCLIOnlyEnabled() { return CodexClientRestrictionDetectionResult{ Enabled: false, Matched: false, Reason: CodexClientRestrictionReasonDisabled, } } if d != nil && d.cfg != nil && d.cfg.Gateway.ForceCodexCLI { return CodexClientRestrictionDetectionResult{ Enabled: true, Matched: true, Reason: CodexClientRestrictionReasonForceCodexCLI, } } userAgent := "" originator := "" if c != nil { userAgent = c.GetHeader("User-Agent") originator = c.GetHeader("originator") } if openai.IsCodexOfficialClientRequest(userAgent) { return CodexClientRestrictionDetectionResult{ Enabled: true, Matched: true, Reason: CodexClientRestrictionReasonMatchedUA, } } if openai.IsCodexOfficialClientOriginator(originator) { return CodexClientRestrictionDetectionResult{ Enabled: true, Matched: true, Reason: CodexClientRestrictionReasonMatchedOriginator, } } return CodexClientRestrictionDetectionResult{ Enabled: true, Matched: false, Reason: CodexClientRestrictionReasonNotMatchedUA, } }