mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
fix(config): dedupe and normalize Gemini keys and headers
This commit is contained in:
@@ -12,7 +12,13 @@ import (
|
||||
)
|
||||
|
||||
func (h *Handler) GetConfig(c *gin.Context) {
|
||||
c.JSON(200, h.cfg)
|
||||
if h == nil || h.cfg == nil {
|
||||
c.JSON(200, gin.H{})
|
||||
return
|
||||
}
|
||||
cfgCopy := *h.cfg
|
||||
cfgCopy.GlAPIKey = geminiKeyStringsFromConfig(h.cfg)
|
||||
c.JSON(200, &cfgCopy)
|
||||
}
|
||||
|
||||
func (h *Handler) GetConfigYAML(c *gin.Context) {
|
||||
|
||||
@@ -87,10 +87,10 @@ func (h *Handler) deleteFromStringList(c *gin.Context, target *[]string, after f
|
||||
return
|
||||
}
|
||||
}
|
||||
if val := c.Query("value"); val != "" {
|
||||
if val := strings.TrimSpace(c.Query("value")); val != "" {
|
||||
out := make([]string, 0, len(*target))
|
||||
for _, v := range *target {
|
||||
if v != val {
|
||||
if strings.TrimSpace(v) != val {
|
||||
out = append(out, v)
|
||||
}
|
||||
}
|
||||
@@ -104,6 +104,53 @@ func (h *Handler) deleteFromStringList(c *gin.Context, target *[]string, after f
|
||||
c.JSON(400, gin.H{"error": "missing index or value"})
|
||||
}
|
||||
|
||||
func sanitizeStringSlice(in []string) []string {
|
||||
out := make([]string, 0, len(in))
|
||||
for i := range in {
|
||||
if trimmed := strings.TrimSpace(in[i]); trimmed != "" {
|
||||
out = append(out, trimmed)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func geminiKeyStringsFromConfig(cfg *config.Config) []string {
|
||||
if cfg == nil || len(cfg.GeminiKey) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]string, 0, len(cfg.GeminiKey))
|
||||
for i := range cfg.GeminiKey {
|
||||
if key := strings.TrimSpace(cfg.GeminiKey[i].APIKey); key != "" {
|
||||
out = append(out, key)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (h *Handler) applyLegacyKeys(keys []string) {
|
||||
if h == nil || h.cfg == nil {
|
||||
return
|
||||
}
|
||||
sanitized := sanitizeStringSlice(keys)
|
||||
existing := make(map[string]config.GeminiKey, len(h.cfg.GeminiKey))
|
||||
for _, entry := range h.cfg.GeminiKey {
|
||||
if key := strings.TrimSpace(entry.APIKey); key != "" {
|
||||
existing[key] = entry
|
||||
}
|
||||
}
|
||||
newList := make([]config.GeminiKey, 0, len(sanitized))
|
||||
for _, key := range sanitized {
|
||||
if entry, ok := existing[key]; ok {
|
||||
newList = append(newList, entry)
|
||||
} else {
|
||||
newList = append(newList, config.GeminiKey{APIKey: key})
|
||||
}
|
||||
}
|
||||
h.cfg.GeminiKey = newList
|
||||
h.cfg.GlAPIKey = sanitized
|
||||
h.cfg.SyncGeminiKeys()
|
||||
}
|
||||
|
||||
// api-keys
|
||||
func (h *Handler) GetAPIKeys(c *gin.Context) { c.JSON(200, gin.H{"api-keys": h.cfg.APIKeys}) }
|
||||
func (h *Handler) PutAPIKeys(c *gin.Context) {
|
||||
@@ -121,20 +168,20 @@ func (h *Handler) DeleteAPIKeys(c *gin.Context) {
|
||||
|
||||
// generative-language-api-key
|
||||
func (h *Handler) GetGlKeys(c *gin.Context) {
|
||||
c.JSON(200, gin.H{"generative-language-api-key": h.cfg.GlAPIKey})
|
||||
c.JSON(200, gin.H{"generative-language-api-key": geminiKeyStringsFromConfig(h.cfg)})
|
||||
}
|
||||
func (h *Handler) PutGlKeys(c *gin.Context) {
|
||||
h.putStringList(c, func(v []string) {
|
||||
h.cfg.GlAPIKey = append([]string(nil), v...)
|
||||
}, func() {
|
||||
h.cfg.SyncGeminiKeys()
|
||||
})
|
||||
h.applyLegacyKeys(v)
|
||||
}, nil)
|
||||
}
|
||||
func (h *Handler) PatchGlKeys(c *gin.Context) {
|
||||
h.patchStringList(c, &h.cfg.GlAPIKey, func() { h.cfg.SyncGeminiKeys() })
|
||||
target := append([]string(nil), geminiKeyStringsFromConfig(h.cfg)...)
|
||||
h.patchStringList(c, &target, func() { h.applyLegacyKeys(target) })
|
||||
}
|
||||
func (h *Handler) DeleteGlKeys(c *gin.Context) {
|
||||
h.deleteFromStringList(c, &h.cfg.GlAPIKey, func() { h.cfg.SyncGeminiKeys() })
|
||||
target := append([]string(nil), geminiKeyStringsFromConfig(h.cfg)...)
|
||||
h.deleteFromStringList(c, &target, func() { h.applyLegacyKeys(target) })
|
||||
}
|
||||
|
||||
// gemini-api-key: []GeminiKey
|
||||
|
||||
@@ -303,56 +303,40 @@ func (cfg *Config) SyncGeminiKeys() {
|
||||
return
|
||||
}
|
||||
|
||||
if len(cfg.GeminiKey) > 0 {
|
||||
out := make([]GeminiKey, 0, len(cfg.GeminiKey))
|
||||
for i := range cfg.GeminiKey {
|
||||
entry := cfg.GeminiKey[i]
|
||||
entry.APIKey = strings.TrimSpace(entry.APIKey)
|
||||
entry.BaseURL = strings.TrimSpace(entry.BaseURL)
|
||||
entry.ProxyURL = strings.TrimSpace(entry.ProxyURL)
|
||||
if entry.APIKey == "" {
|
||||
continue
|
||||
}
|
||||
if len(entry.Headers) > 0 {
|
||||
clean := make(map[string]string, len(entry.Headers))
|
||||
for hk, hv := range entry.Headers {
|
||||
key := strings.TrimSpace(hk)
|
||||
val := strings.TrimSpace(hv)
|
||||
if key == "" || val == "" {
|
||||
continue
|
||||
}
|
||||
clean[key] = val
|
||||
}
|
||||
if len(clean) == 0 {
|
||||
entry.Headers = nil
|
||||
} else {
|
||||
entry.Headers = clean
|
||||
}
|
||||
}
|
||||
out = append(out, entry)
|
||||
seen := make(map[string]struct{}, len(cfg.GeminiKey))
|
||||
out := cfg.GeminiKey[:0]
|
||||
for i := range cfg.GeminiKey {
|
||||
entry := cfg.GeminiKey[i]
|
||||
entry.APIKey = strings.TrimSpace(entry.APIKey)
|
||||
if entry.APIKey == "" {
|
||||
continue
|
||||
}
|
||||
cfg.GeminiKey = out
|
||||
entry.BaseURL = strings.TrimSpace(entry.BaseURL)
|
||||
entry.ProxyURL = strings.TrimSpace(entry.ProxyURL)
|
||||
entry.Headers = normalizeGeminiHeaders(entry.Headers)
|
||||
if _, exists := seen[entry.APIKey]; exists {
|
||||
continue
|
||||
}
|
||||
seen[entry.APIKey] = struct{}{}
|
||||
out = append(out, entry)
|
||||
}
|
||||
cfg.GeminiKey = out
|
||||
|
||||
if len(cfg.GeminiKey) == 0 && len(cfg.GlAPIKey) > 0 {
|
||||
out := make([]GeminiKey, 0, len(cfg.GlAPIKey))
|
||||
for i := range cfg.GlAPIKey {
|
||||
key := strings.TrimSpace(cfg.GlAPIKey[i])
|
||||
if len(cfg.GlAPIKey) > 0 {
|
||||
for _, raw := range cfg.GlAPIKey {
|
||||
key := strings.TrimSpace(raw)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
out = append(out, GeminiKey{APIKey: key})
|
||||
if _, exists := seen[key]; exists {
|
||||
continue
|
||||
}
|
||||
cfg.GeminiKey = append(cfg.GeminiKey, GeminiKey{APIKey: key})
|
||||
seen[key] = struct{}{}
|
||||
}
|
||||
cfg.GeminiKey = out
|
||||
}
|
||||
|
||||
cfg.GlAPIKey = cfg.GlAPIKey[:0]
|
||||
if len(cfg.GeminiKey) > 0 {
|
||||
cfg.GlAPIKey = make([]string, 0, len(cfg.GeminiKey))
|
||||
for i := range cfg.GeminiKey {
|
||||
cfg.GlAPIKey = append(cfg.GlAPIKey, cfg.GeminiKey[i].APIKey)
|
||||
}
|
||||
}
|
||||
cfg.GlAPIKey = nil
|
||||
}
|
||||
|
||||
func syncInlineAccessProvider(cfg *Config) {
|
||||
@@ -372,6 +356,25 @@ func looksLikeBcrypt(s string) bool {
|
||||
return len(s) > 4 && (s[:4] == "$2a$" || s[:4] == "$2b$" || s[:4] == "$2y$")
|
||||
}
|
||||
|
||||
func normalizeGeminiHeaders(headers map[string]string) map[string]string {
|
||||
if len(headers) == 0 {
|
||||
return nil
|
||||
}
|
||||
clean := make(map[string]string, len(headers))
|
||||
for k, v := range headers {
|
||||
key := strings.TrimSpace(k)
|
||||
val := strings.TrimSpace(v)
|
||||
if key == "" || val == "" {
|
||||
continue
|
||||
}
|
||||
clean[key] = val
|
||||
}
|
||||
if len(clean) == 0 {
|
||||
return nil
|
||||
}
|
||||
return clean
|
||||
}
|
||||
|
||||
// hashSecret hashes the given secret using bcrypt.
|
||||
func hashSecret(secret string) (string, error) {
|
||||
// Use default cost for simplicity.
|
||||
|
||||
Reference in New Issue
Block a user