- 为 codex_cli_only 增加 originator 判定通道,避免仅依赖 User-Agent 误拦截 - 扩展官方客户端家族标识,补充 codex_chatgpt_desktop 等常见前缀 - 新增并更新单元测试与网关透传回归测试,覆盖 UA 与 originator 组合场景 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
87 lines
2.9 KiB
Go
87 lines
2.9 KiB
Go
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,
|
|
}
|
|
}
|