feat(openai): 增加 OAuth 账号 Codex 官方客户端限制开关
新增 codex_cli_only 开关并默认关闭,关闭时完全绕过限制逻辑。 在 OpenAI 网关引入统一检测入口,集中判定账号类型、开关与客户端族。 开启后仅放行 codex_cli_rs、codex_vscode、codex_app 客户端家族。 补充后端判定与网关分支测试,并在前端创建/编辑页增加开关配置与回显。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
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"
|
||||
// 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 := ""
|
||||
if c != nil {
|
||||
userAgent = c.GetHeader("User-Agent")
|
||||
}
|
||||
if openai.IsCodexOfficialClientRequest(userAgent) {
|
||||
return CodexClientRestrictionDetectionResult{
|
||||
Enabled: true,
|
||||
Matched: true,
|
||||
Reason: CodexClientRestrictionReasonMatchedUA,
|
||||
}
|
||||
}
|
||||
|
||||
return CodexClientRestrictionDetectionResult{
|
||||
Enabled: true,
|
||||
Matched: false,
|
||||
Reason: CodexClientRestrictionReasonNotMatchedUA,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user