mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-06-07 22:48:33 +08:00
feat(auth): enhance auth index generation with improved file path handling
- Updated `EnsureIndex` logic to incorporate absolute and cleaned file paths when generating auth indexes. - Refined metadata handling to include OAuth type in auth index seed. - Improved compatibility for `json` file paths as sources in auth attributes. - Added unit tests to validate correct auth index behavior for various path and type scenarios.
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -256,45 +257,65 @@ func (a *Auth) indexSeed() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
if fileName := strings.TrimSpace(a.FileName); fileName != "" {
|
||||
return "file:" + fileName
|
||||
}
|
||||
|
||||
providerKey := strings.ToLower(strings.TrimSpace(a.Provider))
|
||||
provider := strings.ToLower(strings.TrimSpace(a.Provider))
|
||||
compatName := ""
|
||||
baseURL := ""
|
||||
apiKey := ""
|
||||
source := ""
|
||||
filePath := ""
|
||||
if a.Attributes != nil {
|
||||
if value := strings.TrimSpace(a.Attributes["provider_key"]); value != "" {
|
||||
providerKey = strings.ToLower(value)
|
||||
}
|
||||
compatName = strings.ToLower(strings.TrimSpace(a.Attributes["compat_name"]))
|
||||
compatName = strings.TrimSpace(a.Attributes["compat_name"])
|
||||
baseURL = strings.TrimSpace(a.Attributes["base_url"])
|
||||
apiKey = strings.TrimSpace(a.Attributes["api_key"])
|
||||
source = strings.TrimSpace(a.Attributes["source"])
|
||||
filePath = strings.TrimSpace(a.Attributes["path"])
|
||||
if filePath == "" {
|
||||
filePath = strings.TrimSpace(a.Attributes["source"])
|
||||
}
|
||||
}
|
||||
|
||||
proxyURL := strings.TrimSpace(a.ProxyURL)
|
||||
hasCredentialIdentity := compatName != "" || baseURL != "" || proxyURL != "" || apiKey != "" || source != ""
|
||||
if providerKey != "" && hasCredentialIdentity {
|
||||
parts := []string{"provider=" + providerKey}
|
||||
if compatName != "" {
|
||||
parts = append(parts, "compat="+compatName)
|
||||
if filePath == "" {
|
||||
filePath = strings.TrimSpace(a.FileName)
|
||||
}
|
||||
if filePath == "" {
|
||||
filePath = strings.TrimSpace(a.ID)
|
||||
}
|
||||
|
||||
if filePath != "" && strings.HasSuffix(strings.ToLower(filePath), ".json") {
|
||||
abs, errAbs := filepath.Abs(filePath)
|
||||
if errAbs == nil && strings.TrimSpace(abs) != "" {
|
||||
filePath = abs
|
||||
}
|
||||
if baseURL != "" {
|
||||
parts = append(parts, "base="+baseURL)
|
||||
filePath = filepath.Clean(filePath)
|
||||
|
||||
authType := ""
|
||||
if a.Metadata != nil {
|
||||
if rawType, ok := a.Metadata["type"].(string); ok {
|
||||
authType = strings.TrimSpace(rawType)
|
||||
}
|
||||
}
|
||||
if proxyURL != "" {
|
||||
parts = append(parts, "proxy="+proxyURL)
|
||||
if authType == "" {
|
||||
authType = strings.TrimSpace(provider)
|
||||
}
|
||||
if apiKey != "" {
|
||||
parts = append(parts, "api_key="+apiKey)
|
||||
authType = strings.ToLower(strings.TrimSpace(authType))
|
||||
if authType != "" {
|
||||
return authType + ":" + filePath
|
||||
}
|
||||
if source != "" {
|
||||
parts = append(parts, "source="+source)
|
||||
}
|
||||
|
||||
apiPrefix := ""
|
||||
if apiKey != "" {
|
||||
switch {
|
||||
case compatName != "" || strings.EqualFold(provider, "openai-compatibility"):
|
||||
apiPrefix = "openai-compatibility"
|
||||
case strings.EqualFold(provider, "gemini"):
|
||||
apiPrefix = "gemini-api-key"
|
||||
case strings.EqualFold(provider, "codex"):
|
||||
apiPrefix = "codex-api-key"
|
||||
case strings.EqualFold(provider, "claude"):
|
||||
apiPrefix = "claude-api-key"
|
||||
}
|
||||
return "config:" + strings.Join(parts, "\x00")
|
||||
}
|
||||
if apiPrefix != "" {
|
||||
return apiPrefix + ":" + strings.TrimSpace(baseURL) + "+" + strings.TrimSpace(apiKey)
|
||||
}
|
||||
|
||||
if id := strings.TrimSpace(a.ID); id != "" {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -96,8 +98,40 @@ func TestEnsureIndexUsesCredentialIdentity(t *testing.T) {
|
||||
if geminiIndex == altBaseIndex {
|
||||
t.Fatalf("same provider/key with different base_url produced duplicate auth_index %q", geminiIndex)
|
||||
}
|
||||
if geminiIndex == duplicateIndex {
|
||||
t.Fatalf("duplicate config entries should be separated by source-derived seed, got %q", geminiIndex)
|
||||
if geminiIndex != duplicateIndex {
|
||||
t.Fatalf("same provider/key with different source should share auth_index, got %q vs %q", geminiIndex, duplicateIndex)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureIndexUsesOAuthTypeAndAbsolutePath(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
wd, errWd := os.Getwd()
|
||||
if errWd != nil {
|
||||
t.Fatalf("os.Getwd returned error: %v", errWd)
|
||||
}
|
||||
|
||||
relPath := "test-oauth.json"
|
||||
absPath := filepath.Join(wd, relPath)
|
||||
expectedSeed := "gemini:" + filepath.Clean(absPath)
|
||||
expectedIndex := stableAuthIndex(expectedSeed)
|
||||
|
||||
a := &Auth{
|
||||
Provider: "gemini-cli",
|
||||
Attributes: map[string]string{
|
||||
"path": relPath,
|
||||
},
|
||||
Metadata: map[string]any{
|
||||
"type": "gemini",
|
||||
},
|
||||
}
|
||||
|
||||
got := a.EnsureIndex()
|
||||
if got == "" {
|
||||
t.Fatal("auth index should not be empty")
|
||||
}
|
||||
if got != expectedIndex {
|
||||
t.Fatalf("auth index = %q, want %q", got, expectedIndex)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user