Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
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
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
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewMetadataFormatMinVersion is the minimum Claude Code version that uses
|
||||
// JSON-formatted metadata.user_id instead of the legacy concatenated string.
|
||||
const NewMetadataFormatMinVersion = "2.1.78"
|
||||
|
||||
// ParsedUserID represents the components extracted from a metadata.user_id value.
|
||||
type ParsedUserID struct {
|
||||
DeviceID string // 64-char hex (or arbitrary client id)
|
||||
AccountUUID string // may be empty
|
||||
SessionID string // UUID
|
||||
IsNewFormat bool // true if the original was JSON format
|
||||
}
|
||||
|
||||
// legacyUserIDRegex matches the legacy user_id format:
|
||||
//
|
||||
// user_{64hex}_account_{optional_uuid}_session_{uuid}
|
||||
var legacyUserIDRegex = regexp.MustCompile(`^user_([a-fA-F0-9]{64})_account_([a-fA-F0-9-]*)_session_([a-fA-F0-9-]{36})$`)
|
||||
|
||||
// jsonUserID is the JSON structure for the new metadata.user_id format.
|
||||
type jsonUserID struct {
|
||||
DeviceID string `json:"device_id"`
|
||||
AccountUUID string `json:"account_uuid"`
|
||||
SessionID string `json:"session_id"`
|
||||
}
|
||||
|
||||
// ParseMetadataUserID parses a metadata.user_id string in either format.
|
||||
// Returns nil if the input cannot be parsed.
|
||||
func ParseMetadataUserID(raw string) *ParsedUserID {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Try JSON format first (starts with '{')
|
||||
if raw[0] == '{' {
|
||||
var j jsonUserID
|
||||
if err := json.Unmarshal([]byte(raw), &j); err != nil {
|
||||
return nil
|
||||
}
|
||||
if j.DeviceID == "" || j.SessionID == "" {
|
||||
return nil
|
||||
}
|
||||
return &ParsedUserID{
|
||||
DeviceID: j.DeviceID,
|
||||
AccountUUID: j.AccountUUID,
|
||||
SessionID: j.SessionID,
|
||||
IsNewFormat: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Try legacy format
|
||||
matches := legacyUserIDRegex.FindStringSubmatch(raw)
|
||||
if matches == nil {
|
||||
return nil
|
||||
}
|
||||
return &ParsedUserID{
|
||||
DeviceID: matches[1],
|
||||
AccountUUID: matches[2],
|
||||
SessionID: matches[3],
|
||||
IsNewFormat: false,
|
||||
}
|
||||
}
|
||||
|
||||
// FormatMetadataUserID builds a metadata.user_id string in the format
|
||||
// appropriate for the given CLI version. Components are the rewritten values
|
||||
// (not necessarily the originals).
|
||||
func FormatMetadataUserID(deviceID, accountUUID, sessionID, uaVersion string) string {
|
||||
if IsNewMetadataFormatVersion(uaVersion) {
|
||||
b, _ := json.Marshal(jsonUserID{
|
||||
DeviceID: deviceID,
|
||||
AccountUUID: accountUUID,
|
||||
SessionID: sessionID,
|
||||
})
|
||||
return string(b)
|
||||
}
|
||||
// Legacy format
|
||||
return "user_" + deviceID + "_account_" + accountUUID + "_session_" + sessionID
|
||||
}
|
||||
|
||||
// IsNewMetadataFormatVersion returns true if the given CLI version uses the
|
||||
// new JSON metadata.user_id format (>= 2.1.78).
|
||||
func IsNewMetadataFormatVersion(version string) bool {
|
||||
if version == "" {
|
||||
return false
|
||||
}
|
||||
return CompareVersions(version, NewMetadataFormatMinVersion) >= 0
|
||||
}
|
||||
|
||||
// ExtractCLIVersion extracts the Claude Code version from a User-Agent string.
|
||||
// Returns "" if the UA doesn't match the expected pattern.
|
||||
func ExtractCLIVersion(ua string) string {
|
||||
matches := claudeCodeUAVersionPattern.FindStringSubmatch(ua)
|
||||
if len(matches) >= 2 {
|
||||
return matches[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user