| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- package openai
- import (
- "encoding/json"
- "fmt"
- "net/http"
- "strings"
- "github.com/tidwall/gjson"
- )
- // EngineFingerprintSignal 描述引擎指纹统一列表的一条信号。
- // Required=true(勾选)= 该信号必须命中;多条 Required 之间 AND。
- // Match 为同一信号的等价写法/变体,行内 OR(命中任一即算该条满足)。
- type EngineFingerprintSignal struct {
- Type string `json:"type"` // header_exact | header_prefix | body_path
- Match []string `json:"match"` // 行内 OR 变体
- Required bool `json:"required"` // 勾选=true
- }
- const (
- FingerprintSignalHeaderExact = "header_exact"
- FingerprintSignalHeaderPrefix = "header_prefix"
- FingerprintSignalBodyPath = "body_path"
- )
- // DefaultEngineFingerprintSignals 默认种子:只勾 x-codex- 前缀,其余预填不勾。
- // 依据:实测真 codex(含旧版)约 98.8% 必带 x-codex-window-id 头。
- var DefaultEngineFingerprintSignals = []EngineFingerprintSignal{
- {Type: FingerprintSignalHeaderPrefix, Match: []string{"x-codex-"}, Required: true},
- {Type: FingerprintSignalHeaderExact, Match: []string{"session-id", "session_id"}, Required: false},
- {Type: FingerprintSignalHeaderExact, Match: []string{"thread-id", "thread_id"}, Required: false},
- {Type: FingerprintSignalBodyPath, Match: []string{"client_metadata.x-codex-window-id", "client_metadata.x-codex-installation-id"}, Required: false},
- }
- // EvaluateEngineFingerprint 应用「勾选 AND / 行内变体 OR」规则。
- // 只有 Required=true 的条目参与;全部命中→true;任一缺失→false;无任何 Required→true。
- func EvaluateEngineFingerprint(h http.Header, body []byte, signals []EngineFingerprintSignal) bool {
- for _, s := range signals {
- if !s.Required {
- continue
- }
- if !engineSignalMatches(h, body, s) {
- return false
- }
- }
- return true
- }
- func engineSignalMatches(h http.Header, body []byte, s EngineFingerprintSignal) bool {
- switch s.Type {
- case FingerprintSignalHeaderExact:
- for _, name := range s.Match {
- if n := strings.TrimSpace(name); n != "" && h != nil && strings.TrimSpace(h.Get(n)) != "" {
- return true
- }
- }
- case FingerprintSignalHeaderPrefix:
- if h == nil {
- return false
- }
- for k := range h {
- lk := strings.ToLower(k)
- for _, p := range s.Match {
- if np := strings.ToLower(strings.TrimSpace(p)); np != "" && strings.HasPrefix(lk, np) {
- return true
- }
- }
- }
- case FingerprintSignalBodyPath:
- if len(body) == 0 {
- return false
- }
- for _, path := range s.Match {
- if p := strings.TrimSpace(path); p != "" && gjson.GetBytes(body, p).Exists() {
- return true
- }
- }
- }
- return false
- }
- // ParseEngineFingerprintSignals 解析 JSON;空串→(nil,true);非法→(nil,false)。
- func ParseEngineFingerprintSignals(raw string) ([]EngineFingerprintSignal, bool) {
- if strings.TrimSpace(raw) == "" {
- return nil, true
- }
- var sigs []EngineFingerprintSignal
- if json.Unmarshal([]byte(raw), &sigs) != nil {
- return nil, false
- }
- return sigs, true
- }
- // ValidateEngineFingerprintSignalsJSON 校验:空=合法;非空须为合法数组,
- // 每条 type 合法且 match 至少一个非空项。供管理端写入校验复用。
- func ValidateEngineFingerprintSignalsJSON(raw string) error {
- trimmed := strings.TrimSpace(raw)
- if trimmed == "" {
- return nil
- }
- var sigs []EngineFingerprintSignal
- if err := json.Unmarshal([]byte(trimmed), &sigs); err != nil {
- return fmt.Errorf("must be empty or a valid JSON array of {type, match[], required}")
- }
- for i, s := range sigs {
- switch s.Type {
- case FingerprintSignalHeaderExact, FingerprintSignalHeaderPrefix, FingerprintSignalBodyPath:
- default:
- return fmt.Errorf("entry %d: type must be one of header_exact/header_prefix/body_path", i)
- }
- hasMatch := false
- for _, m := range s.Match {
- if strings.TrimSpace(m) != "" {
- hasMatch = true
- break
- }
- }
- if !hasMatch {
- return fmt.Errorf("entry %d: match must contain at least one non-empty value", i)
- }
- }
- return nil
- }
- // DefaultEngineFingerprintSignalsJSON 默认种子的 JSON 字符串。
- func DefaultEngineFingerprintSignalsJSON() string {
- b, _ := json.Marshal(DefaultEngineFingerprintSignals)
- return string(b)
- }
|