新增 codex_cli_only 开关并默认关闭,关闭时完全绕过限制逻辑。 在 OpenAI 网关引入统一检测入口,集中判定账号类型、开关与客户端族。 开启后仅放行 codex_cli_rs、codex_vscode、codex_app 客户端家族。 补充后端判定与网关分支测试,并在前端创建/编辑页增加开关配置与回显。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
76 lines
2.4 KiB
Go
76 lines
2.4 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"
|
|
// 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,
|
|
}
|
|
}
|