Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
131 lines
4.1 KiB
Go
131 lines
4.1 KiB
Go
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)
|
|
}
|