refactor(diff): improve security and stability of config change detection

Introduce formatProxyURL helper to sanitize proxy addresses before
logging, stripping credentials and path components while preserving
host information. Rework model hash computation to sort and deduplicate
name/alias pairs with case normalization, ensuring consistent output
regardless of input ordering. Add signature-based identification for
anonymous OpenAI-compatible provider entries to maintain stable keys
across configuration reloads. Replace direct stdout prints with
structured logger calls for file change notifications.
This commit is contained in:
hkfires
2025-12-16 22:39:19 +08:00
parent ef8e94e992
commit b0c5d9640a
8 changed files with 310 additions and 29 deletions

View File

@@ -13,32 +13,47 @@ import (
// ComputeOpenAICompatModelsHash returns a stable hash for OpenAI-compat models.
// Used to detect model list changes during hot reload.
func ComputeOpenAICompatModelsHash(models []config.OpenAICompatibilityModel) string {
if len(models) == 0 {
return ""
}
data, _ := json.Marshal(models)
sum := sha256.Sum256(data)
return hex.EncodeToString(sum[:])
keys := normalizeModelPairs(func(out func(key string)) {
for _, model := range models {
name := strings.TrimSpace(model.Name)
alias := strings.TrimSpace(model.Alias)
if name == "" && alias == "" {
continue
}
out(strings.ToLower(name) + "|" + strings.ToLower(alias))
}
})
return hashJoined(keys)
}
// ComputeVertexCompatModelsHash returns a stable hash for Vertex-compatible models.
func ComputeVertexCompatModelsHash(models []config.VertexCompatModel) string {
if len(models) == 0 {
return ""
}
data, _ := json.Marshal(models)
sum := sha256.Sum256(data)
return hex.EncodeToString(sum[:])
keys := normalizeModelPairs(func(out func(key string)) {
for _, model := range models {
name := strings.TrimSpace(model.Name)
alias := strings.TrimSpace(model.Alias)
if name == "" && alias == "" {
continue
}
out(strings.ToLower(name) + "|" + strings.ToLower(alias))
}
})
return hashJoined(keys)
}
// ComputeClaudeModelsHash returns a stable hash for Claude model aliases.
func ComputeClaudeModelsHash(models []config.ClaudeModel) string {
if len(models) == 0 {
return ""
}
data, _ := json.Marshal(models)
sum := sha256.Sum256(data)
return hex.EncodeToString(sum[:])
keys := normalizeModelPairs(func(out func(key string)) {
for _, model := range models {
name := strings.TrimSpace(model.Name)
alias := strings.TrimSpace(model.Alias)
if name == "" && alias == "" {
continue
}
out(strings.ToLower(name) + "|" + strings.ToLower(alias))
}
})
return hashJoined(keys)
}
// ComputeExcludedModelsHash returns a normalized hash for excluded model lists.
@@ -60,3 +75,28 @@ func ComputeExcludedModelsHash(excluded []string) string {
sum := sha256.Sum256(data)
return hex.EncodeToString(sum[:])
}
func normalizeModelPairs(collect func(out func(key string))) []string {
seen := make(map[string]struct{})
keys := make([]string, 0)
collect(func(key string) {
if _, exists := seen[key]; exists {
return
}
seen[key] = struct{}{}
keys = append(keys, key)
})
if len(keys) == 0 {
return nil
}
sort.Strings(keys)
return keys
}
func hashJoined(keys []string) string {
if len(keys) == 0 {
return ""
}
sum := sha256.Sum256([]byte(strings.Join(keys, "\n")))
return hex.EncodeToString(sum[:])
}