mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 04:10:51 +08:00
refactor(access): migrate to SDKConfig for authentication and provider management
- Replaced `config.Config` with `SDKConfig` in authentication and provider logic for consistency with SDK changes. - Updated provider registration, reconciliation, and build functions to align with the `SDKConfig` structure. - Refactored related imports and handlers to support the new configuration approach. - Improved clarity and reduced redundancy in API key synchronization and provider initialization.
This commit is contained in:
@@ -6,18 +6,20 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
||||||
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
|
||||||
|
sdkConfig "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReconcileProviders builds the desired provider list by reusing existing providers when possible
|
// ReconcileProviders builds the desired provider list by reusing existing providers when possible
|
||||||
// and creating or removing providers only when their configuration changed. It returns the final
|
// and creating or removing providers only when their configuration changed. It returns the final
|
||||||
// ordered provider slice along with the identifiers of providers that were added, updated, or
|
// ordered provider slice along with the identifiers of providers that were added, updated, or
|
||||||
// removed compared to the previous configuration.
|
// removed compared to the previous configuration.
|
||||||
func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (result []Provider, added, updated, removed []string, err error) {
|
func ReconcileProviders(oldCfg, newCfg *config.Config, existing []access.Provider) (result []access.Provider, added, updated, removed []string, err error) {
|
||||||
if newCfg == nil {
|
if newCfg == nil {
|
||||||
return nil, nil, nil, nil, nil
|
return nil, nil, nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
existingMap := make(map[string]Provider, len(existing))
|
existingMap := make(map[string]access.Provider, len(existing))
|
||||||
for _, provider := range existing {
|
for _, provider := range existing {
|
||||||
if provider == nil {
|
if provider == nil {
|
||||||
continue
|
continue
|
||||||
@@ -28,11 +30,11 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
|
|||||||
oldCfgMap := accessProviderMap(oldCfg)
|
oldCfgMap := accessProviderMap(oldCfg)
|
||||||
newEntries := collectProviderEntries(newCfg)
|
newEntries := collectProviderEntries(newCfg)
|
||||||
|
|
||||||
result = make([]Provider, 0, len(newEntries))
|
result = make([]access.Provider, 0, len(newEntries))
|
||||||
finalIDs := make(map[string]struct{}, len(newEntries))
|
finalIDs := make(map[string]struct{}, len(newEntries))
|
||||||
|
|
||||||
isInlineProvider := func(id string) bool {
|
isInlineProvider := func(id string) bool {
|
||||||
return strings.EqualFold(id, config.DefaultAccessProviderName)
|
return strings.EqualFold(id, sdkConfig.DefaultAccessProviderName)
|
||||||
}
|
}
|
||||||
appendChange := func(list *[]string, id string) {
|
appendChange := func(list *[]string, id string) {
|
||||||
if isInlineProvider(id) {
|
if isInlineProvider(id) {
|
||||||
@@ -58,7 +60,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider, buildErr := buildProvider(providerCfg, newCfg)
|
provider, buildErr := access.BuildProvider(providerCfg, &newCfg.SDKConfig)
|
||||||
if buildErr != nil {
|
if buildErr != nil {
|
||||||
return nil, nil, nil, nil, buildErr
|
return nil, nil, nil, nil, buildErr
|
||||||
}
|
}
|
||||||
@@ -76,7 +78,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(result) == 0 && len(newCfg.APIKeys) > 0 {
|
if len(result) == 0 && len(newCfg.APIKeys) > 0 {
|
||||||
config.SyncInlineAPIKeys(newCfg, newCfg.APIKeys)
|
sdkConfig.SyncInlineAPIKeys(&newCfg.SDKConfig, newCfg.APIKeys)
|
||||||
if providerCfg := newCfg.ConfigAPIKeyProvider(); providerCfg != nil {
|
if providerCfg := newCfg.ConfigAPIKeyProvider(); providerCfg != nil {
|
||||||
key := providerIdentifier(providerCfg)
|
key := providerIdentifier(providerCfg)
|
||||||
if key != "" {
|
if key != "" {
|
||||||
@@ -86,7 +88,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
|
|||||||
if existingProvider, okExisting := existingMap[key]; okExisting {
|
if existingProvider, okExisting := existingMap[key]; okExisting {
|
||||||
result = append(result, existingProvider)
|
result = append(result, existingProvider)
|
||||||
} else {
|
} else {
|
||||||
provider, buildErr := buildProvider(providerCfg, newCfg)
|
provider, buildErr := access.BuildProvider(providerCfg, &newCfg.SDKConfig)
|
||||||
if buildErr != nil {
|
if buildErr != nil {
|
||||||
return nil, nil, nil, nil, buildErr
|
return nil, nil, nil, nil, buildErr
|
||||||
}
|
}
|
||||||
@@ -98,7 +100,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
|
|||||||
result = append(result, provider)
|
result = append(result, provider)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
provider, buildErr := buildProvider(providerCfg, newCfg)
|
provider, buildErr := access.BuildProvider(providerCfg, &newCfg.SDKConfig)
|
||||||
if buildErr != nil {
|
if buildErr != nil {
|
||||||
return nil, nil, nil, nil, buildErr
|
return nil, nil, nil, nil, buildErr
|
||||||
}
|
}
|
||||||
@@ -110,7 +112,7 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
|
|||||||
result = append(result, provider)
|
result = append(result, provider)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
provider, buildErr := buildProvider(providerCfg, newCfg)
|
provider, buildErr := access.BuildProvider(providerCfg, &newCfg.SDKConfig)
|
||||||
if buildErr != nil {
|
if buildErr != nil {
|
||||||
return nil, nil, nil, nil, buildErr
|
return nil, nil, nil, nil, buildErr
|
||||||
}
|
}
|
||||||
@@ -144,8 +146,8 @@ func ReconcileProviders(oldCfg, newCfg *config.Config, existing []Provider) (res
|
|||||||
return result, added, updated, removed, nil
|
return result, added, updated, removed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func accessProviderMap(cfg *config.Config) map[string]*config.AccessProvider {
|
func accessProviderMap(cfg *config.Config) map[string]*sdkConfig.AccessProvider {
|
||||||
result := make(map[string]*config.AccessProvider)
|
result := make(map[string]*sdkConfig.AccessProvider)
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -170,8 +172,8 @@ func accessProviderMap(cfg *config.Config) map[string]*config.AccessProvider {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectProviderEntries(cfg *config.Config) []*config.AccessProvider {
|
func collectProviderEntries(cfg *config.Config) []*sdkConfig.AccessProvider {
|
||||||
entries := make([]*config.AccessProvider, 0, len(cfg.Access.Providers))
|
entries := make([]*sdkConfig.AccessProvider, 0, len(cfg.Access.Providers))
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
@@ -187,7 +189,7 @@ func collectProviderEntries(cfg *config.Config) []*config.AccessProvider {
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func providerIdentifier(provider *config.AccessProvider) string {
|
func providerIdentifier(provider *sdkConfig.AccessProvider) string {
|
||||||
if provider == nil {
|
if provider == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -198,13 +200,13 @@ func providerIdentifier(provider *config.AccessProvider) string {
|
|||||||
if typ == "" {
|
if typ == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if strings.EqualFold(typ, config.AccessProviderTypeConfigAPIKey) {
|
if strings.EqualFold(typ, sdkConfig.AccessProviderTypeConfigAPIKey) {
|
||||||
return config.DefaultAccessProviderName
|
return sdkConfig.DefaultAccessProviderName
|
||||||
}
|
}
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
func providerConfigEqual(a, b *config.AccessProvider) bool {
|
func providerConfigEqual(a, b *sdkConfig.AccessProvider) bool {
|
||||||
if a == nil || b == nil {
|
if a == nil || b == nil {
|
||||||
return a == nil && b == nil
|
return a == nil && b == nil
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
||||||
|
sdkConfig "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generic helpers for list[string]
|
// Generic helpers for list[string]
|
||||||
@@ -106,13 +107,13 @@ func (h *Handler) deleteFromStringList(c *gin.Context, target *[]string, after f
|
|||||||
// api-keys
|
// api-keys
|
||||||
func (h *Handler) GetAPIKeys(c *gin.Context) { c.JSON(200, gin.H{"api-keys": h.cfg.APIKeys}) }
|
func (h *Handler) GetAPIKeys(c *gin.Context) { c.JSON(200, gin.H{"api-keys": h.cfg.APIKeys}) }
|
||||||
func (h *Handler) PutAPIKeys(c *gin.Context) {
|
func (h *Handler) PutAPIKeys(c *gin.Context) {
|
||||||
h.putStringList(c, func(v []string) { config.SyncInlineAPIKeys(h.cfg, v) }, nil)
|
h.putStringList(c, func(v []string) { sdkConfig.SyncInlineAPIKeys(&h.cfg.SDKConfig, v) }, nil)
|
||||||
}
|
}
|
||||||
func (h *Handler) PatchAPIKeys(c *gin.Context) {
|
func (h *Handler) PatchAPIKeys(c *gin.Context) {
|
||||||
h.patchStringList(c, &h.cfg.APIKeys, func() { config.SyncInlineAPIKeys(h.cfg, h.cfg.APIKeys) })
|
h.patchStringList(c, &h.cfg.APIKeys, func() { sdkConfig.SyncInlineAPIKeys(&h.cfg.SDKConfig, h.cfg.APIKeys) })
|
||||||
}
|
}
|
||||||
func (h *Handler) DeleteAPIKeys(c *gin.Context) {
|
func (h *Handler) DeleteAPIKeys(c *gin.Context) {
|
||||||
h.deleteFromStringList(c, &h.cfg.APIKeys, func() { config.SyncInlineAPIKeys(h.cfg, h.cfg.APIKeys) })
|
h.deleteFromStringList(c, &h.cfg.APIKeys, func() { sdkConfig.SyncInlineAPIKeys(&h.cfg.SDKConfig, h.cfg.APIKeys) })
|
||||||
}
|
}
|
||||||
|
|
||||||
// generative-language-api-key
|
// generative-language-api-key
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/access"
|
||||||
managementHandlers "github.com/router-for-me/CLIProxyAPI/v6/internal/api/handlers/management"
|
managementHandlers "github.com/router-for-me/CLIProxyAPI/v6/internal/api/handlers/management"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/api/middleware"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/api/middleware"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
||||||
@@ -25,8 +26,8 @@ import (
|
|||||||
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
|
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers"
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/claude"
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/claude"
|
||||||
gemini2 "github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/gemini"
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/gemini"
|
||||||
openai2 "github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/openai"
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/openai"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@@ -224,11 +225,11 @@ func NewServer(cfg *config.Config, authManager *auth.Manager, accessManager *sdk
|
|||||||
// setupRoutes configures the API routes for the server.
|
// setupRoutes configures the API routes for the server.
|
||||||
// It defines the endpoints and associates them with their respective handlers.
|
// It defines the endpoints and associates them with their respective handlers.
|
||||||
func (s *Server) setupRoutes() {
|
func (s *Server) setupRoutes() {
|
||||||
openaiHandlers := openai2.NewOpenAIAPIHandler(s.handlers)
|
openaiHandlers := openai.NewOpenAIAPIHandler(s.handlers)
|
||||||
geminiHandlers := gemini2.NewGeminiAPIHandler(s.handlers)
|
geminiHandlers := gemini.NewGeminiAPIHandler(s.handlers)
|
||||||
geminiCLIHandlers := gemini2.NewGeminiCLIAPIHandler(s.handlers)
|
geminiCLIHandlers := gemini.NewGeminiCLIAPIHandler(s.handlers)
|
||||||
claudeCodeHandlers := claude.NewClaudeCodeAPIHandler(s.handlers)
|
claudeCodeHandlers := claude.NewClaudeCodeAPIHandler(s.handlers)
|
||||||
openaiResponsesHandlers := openai2.NewOpenAIResponsesAPIHandler(s.handlers)
|
openaiResponsesHandlers := openai.NewOpenAIResponsesAPIHandler(s.handlers)
|
||||||
|
|
||||||
// OpenAI compatible API routes
|
// OpenAI compatible API routes
|
||||||
v1 := s.engine.Group("/v1")
|
v1 := s.engine.Group("/v1")
|
||||||
@@ -469,7 +470,7 @@ func (s *Server) watchKeepAlive() {
|
|||||||
// that routes to different handlers based on the User-Agent header.
|
// that routes to different handlers based on the User-Agent header.
|
||||||
// If User-Agent starts with "claude-cli", it routes to Claude handler,
|
// If User-Agent starts with "claude-cli", it routes to Claude handler,
|
||||||
// otherwise it routes to OpenAI handler.
|
// otherwise it routes to OpenAI handler.
|
||||||
func (s *Server) unifiedModelsHandler(openaiHandler *openai2.OpenAIAPIHandler, claudeHandler *claude.ClaudeCodeAPIHandler) gin.HandlerFunc {
|
func (s *Server) unifiedModelsHandler(openaiHandler *openai.OpenAIAPIHandler, claudeHandler *claude.ClaudeCodeAPIHandler) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
userAgent := c.GetHeader("User-Agent")
|
userAgent := c.GetHeader("User-Agent")
|
||||||
|
|
||||||
@@ -552,7 +553,7 @@ func (s *Server) applyAccessConfig(oldCfg, newCfg *config.Config) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
existing := s.accessManager.Providers()
|
existing := s.accessManager.Providers()
|
||||||
providers, added, updated, removed, err := sdkaccess.ReconcileProviders(oldCfg, newCfg, existing)
|
providers, added, updated, removed, err := access.ReconcileProviders(oldCfg, newCfg, existing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to reconcile request auth providers: %v", err)
|
log.Errorf("failed to reconcile request auth providers: %v", err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -31,12 +31,6 @@ type Config struct {
|
|||||||
// UsageStatisticsEnabled toggles in-memory usage aggregation; when false, usage data is discarded.
|
// UsageStatisticsEnabled toggles in-memory usage aggregation; when false, usage data is discarded.
|
||||||
UsageStatisticsEnabled bool `yaml:"usage-statistics-enabled" json:"usage-statistics-enabled"`
|
UsageStatisticsEnabled bool `yaml:"usage-statistics-enabled" json:"usage-statistics-enabled"`
|
||||||
|
|
||||||
// APIKeys is a list of keys for authenticating clients to this proxy server.
|
|
||||||
APIKeys []string `yaml:"api-keys" json:"api-keys"`
|
|
||||||
|
|
||||||
// Access holds request authentication provider configuration.
|
|
||||||
Access AccessConfig `yaml:"auth" json:"auth"`
|
|
||||||
|
|
||||||
// QuotaExceeded defines the behavior when a quota is exceeded.
|
// QuotaExceeded defines the behavior when a quota is exceeded.
|
||||||
QuotaExceeded QuotaExceeded `yaml:"quota-exceeded" json:"quota-exceeded"`
|
QuotaExceeded QuotaExceeded `yaml:"quota-exceeded" json:"quota-exceeded"`
|
||||||
|
|
||||||
@@ -62,38 +56,6 @@ type Config struct {
|
|||||||
GeminiWeb GeminiWebConfig `yaml:"gemini-web" json:"gemini-web"`
|
GeminiWeb GeminiWebConfig `yaml:"gemini-web" json:"gemini-web"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessConfig groups request authentication providers.
|
|
||||||
type AccessConfig struct {
|
|
||||||
// Providers lists configured authentication providers.
|
|
||||||
Providers []AccessProvider `yaml:"providers" json:"providers"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccessProvider describes a request authentication provider entry.
|
|
||||||
type AccessProvider struct {
|
|
||||||
// Name is the instance identifier for the provider.
|
|
||||||
Name string `yaml:"name" json:"name"`
|
|
||||||
|
|
||||||
// Type selects the provider implementation registered via the SDK.
|
|
||||||
Type string `yaml:"type" json:"type"`
|
|
||||||
|
|
||||||
// SDK optionally names a third-party SDK module providing this provider.
|
|
||||||
SDK string `yaml:"sdk,omitempty" json:"sdk,omitempty"`
|
|
||||||
|
|
||||||
// APIKeys lists inline keys for providers that require them.
|
|
||||||
APIKeys []string `yaml:"api-keys,omitempty" json:"api-keys,omitempty"`
|
|
||||||
|
|
||||||
// Config passes provider-specific options to the implementation.
|
|
||||||
Config map[string]any `yaml:"config,omitempty" json:"config,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// AccessProviderTypeConfigAPIKey is the built-in provider validating inline API keys.
|
|
||||||
AccessProviderTypeConfigAPIKey = "config-api-key"
|
|
||||||
|
|
||||||
// DefaultAccessProviderName is applied when no provider name is supplied.
|
|
||||||
DefaultAccessProviderName = "config-inline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GeminiWebConfig nests Gemini Web related options under 'gemini-web'.
|
// GeminiWebConfig nests Gemini Web related options under 'gemini-web'.
|
||||||
type GeminiWebConfig struct {
|
type GeminiWebConfig struct {
|
||||||
// Context enables JSON-based conversation reuse.
|
// Context enables JSON-based conversation reuse.
|
||||||
@@ -232,43 +194,6 @@ func LoadConfig(configFile string) (*Config, error) {
|
|||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncInlineAPIKeys updates the inline API key provider and top-level APIKeys field.
|
|
||||||
func SyncInlineAPIKeys(cfg *Config, keys []string) {
|
|
||||||
if cfg == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cloned := append([]string(nil), keys...)
|
|
||||||
cfg.APIKeys = cloned
|
|
||||||
if provider := cfg.ConfigAPIKeyProvider(); provider != nil {
|
|
||||||
if provider.Name == "" {
|
|
||||||
provider.Name = DefaultAccessProviderName
|
|
||||||
}
|
|
||||||
provider.APIKeys = cloned
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cfg.Access.Providers = append(cfg.Access.Providers, AccessProvider{
|
|
||||||
Name: DefaultAccessProviderName,
|
|
||||||
Type: AccessProviderTypeConfigAPIKey,
|
|
||||||
APIKeys: cloned,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigAPIKeyProvider returns the first inline API key provider if present.
|
|
||||||
func (c *Config) ConfigAPIKeyProvider() *AccessProvider {
|
|
||||||
if c == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for i := range c.Access.Providers {
|
|
||||||
if c.Access.Providers[i].Type == AccessProviderTypeConfigAPIKey {
|
|
||||||
if c.Access.Providers[i].Name == "" {
|
|
||||||
c.Access.Providers[i].Name = DefaultAccessProviderName
|
|
||||||
}
|
|
||||||
return &c.Access.Providers[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func syncInlineAccessProvider(cfg *Config) {
|
func syncInlineAccessProvider(cfg *Config) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return
|
return
|
||||||
@@ -277,9 +202,9 @@ func syncInlineAccessProvider(cfg *Config) {
|
|||||||
if len(cfg.APIKeys) == 0 {
|
if len(cfg.APIKeys) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg.Access.Providers = append(cfg.Access.Providers, AccessProvider{
|
cfg.Access.Providers = append(cfg.Access.Providers, config.AccessProvider{
|
||||||
Name: DefaultAccessProviderName,
|
Name: config.DefaultAccessProviderName,
|
||||||
Type: AccessProviderTypeConfigAPIKey,
|
Type: config.AccessProviderTypeConfigAPIKey,
|
||||||
APIKeys: append([]string(nil), cfg.APIKeys...),
|
APIKeys: append([]string(nil), cfg.APIKeys...),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -289,9 +214,9 @@ func syncInlineAccessProvider(cfg *Config) {
|
|||||||
if len(cfg.APIKeys) == 0 {
|
if len(cfg.APIKeys) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg.Access.Providers = append(cfg.Access.Providers, AccessProvider{
|
cfg.Access.Providers = append(cfg.Access.Providers, config.AccessProvider{
|
||||||
Name: DefaultAccessProviderName,
|
Name: config.DefaultAccessProviderName,
|
||||||
Type: AccessProviderTypeConfigAPIKey,
|
Type: config.AccessProviderTypeConfigAPIKey,
|
||||||
APIKeys: append([]string(nil), cfg.APIKeys...),
|
APIKeys: append([]string(nil), cfg.APIKeys...),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
|
||||||
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
|
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
|
||||||
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type provider struct {
|
type provider struct {
|
||||||
@@ -18,7 +18,7 @@ func init() {
|
|||||||
sdkaccess.RegisterProvider(config.AccessProviderTypeConfigAPIKey, newProvider)
|
sdkaccess.RegisterProvider(config.AccessProviderTypeConfigAPIKey, newProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProvider(cfg *config.AccessProvider, _ *config.Config) (sdkaccess.Provider, error) {
|
func newProvider(cfg *config.AccessProvider, _ *config.SDKConfig) (sdkaccess.Provider, error) {
|
||||||
name := cfg.Name
|
name := cfg.Name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name = config.DefaultAccessProviderName
|
name = config.DefaultAccessProviderName
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provider validates credentials for incoming requests.
|
// Provider validates credentials for incoming requests.
|
||||||
@@ -23,7 +23,7 @@ type Result struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ProviderFactory builds a provider from configuration data.
|
// ProviderFactory builds a provider from configuration data.
|
||||||
type ProviderFactory func(cfg *config.AccessProvider, root *config.Config) (Provider, error)
|
type ProviderFactory func(cfg *config.AccessProvider, root *config.SDKConfig) (Provider, error)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
registryMu sync.RWMutex
|
registryMu sync.RWMutex
|
||||||
@@ -40,7 +40,7 @@ func RegisterProvider(typ string, factory ProviderFactory) {
|
|||||||
registryMu.Unlock()
|
registryMu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildProvider(cfg *config.AccessProvider, root *config.Config) (Provider, error) {
|
func BuildProvider(cfg *config.AccessProvider, root *config.SDKConfig) (Provider, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil, fmt.Errorf("access: nil provider config")
|
return nil, fmt.Errorf("access: nil provider config")
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ func buildProvider(cfg *config.AccessProvider, root *config.Config) (Provider, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildProviders constructs providers declared in configuration.
|
// BuildProviders constructs providers declared in configuration.
|
||||||
func BuildProviders(root *config.Config) ([]Provider, error) {
|
func BuildProviders(root *config.SDKConfig) ([]Provider, error) {
|
||||||
if root == nil {
|
if root == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ func BuildProviders(root *config.Config) ([]Provider, error) {
|
|||||||
if providerCfg.Type == "" {
|
if providerCfg.Type == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
provider, err := buildProvider(providerCfg, root)
|
provider, err := BuildProvider(providerCfg, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ func BuildProviders(root *config.Config) ([]Provider, error) {
|
|||||||
if len(providers) == 0 && len(root.APIKeys) > 0 {
|
if len(providers) == 0 && len(root.APIKeys) > 0 {
|
||||||
config.SyncInlineAPIKeys(root, root.APIKeys)
|
config.SyncInlineAPIKeys(root, root.APIKeys)
|
||||||
if providerCfg := root.ConfigAPIKeyProvider(); providerCfg != nil {
|
if providerCfg := root.ConfigAPIKeyProvider(); providerCfg != nil {
|
||||||
provider, err := buildProvider(providerCfg, root)
|
provider, err := BuildProvider(providerCfg, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ func (b *Builder) Build() (*Service, error) {
|
|||||||
if accessManager == nil {
|
if accessManager == nil {
|
||||||
accessManager = sdkaccess.NewManager()
|
accessManager = sdkaccess.NewManager()
|
||||||
}
|
}
|
||||||
providers, err := sdkaccess.BuildProviders(b.cfg)
|
providers, err := sdkaccess.BuildProviders(&b.cfg.SDKConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/access"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/api"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/api"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
||||||
geminiwebclient "github.com/router-for-me/CLIProxyAPI/v6/internal/provider/gemini-web"
|
geminiwebclient "github.com/router-for-me/CLIProxyAPI/v6/internal/provider/gemini-web"
|
||||||
@@ -115,7 +116,7 @@ func (s *Service) refreshAccessProviders(cfg *config.Config) {
|
|||||||
s.cfgMu.RUnlock()
|
s.cfgMu.RUnlock()
|
||||||
|
|
||||||
existing := s.accessManager.Providers()
|
existing := s.accessManager.Providers()
|
||||||
providers, added, updated, removed, err := sdkaccess.ReconcileProviders(oldCfg, cfg, existing)
|
providers, added, updated, removed, err := access.ReconcileProviders(oldCfg, cfg, existing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to reconcile request auth providers: %v", err)
|
log.Errorf("failed to reconcile request auth providers: %v", err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -11,4 +11,79 @@ type SDKConfig struct {
|
|||||||
|
|
||||||
// RequestLog enables or disables detailed request logging functionality.
|
// RequestLog enables or disables detailed request logging functionality.
|
||||||
RequestLog bool `yaml:"request-log" json:"request-log"`
|
RequestLog bool `yaml:"request-log" json:"request-log"`
|
||||||
|
|
||||||
|
// APIKeys is a list of keys for authenticating clients to this proxy server.
|
||||||
|
APIKeys []string `yaml:"api-keys" json:"api-keys"`
|
||||||
|
|
||||||
|
// Access holds request authentication provider configuration.
|
||||||
|
Access AccessConfig `yaml:"auth" json:"auth"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccessConfig groups request authentication providers.
|
||||||
|
type AccessConfig struct {
|
||||||
|
// Providers lists configured authentication providers.
|
||||||
|
Providers []AccessProvider `yaml:"providers" json:"providers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccessProvider describes a request authentication provider entry.
|
||||||
|
type AccessProvider struct {
|
||||||
|
// Name is the instance identifier for the provider.
|
||||||
|
Name string `yaml:"name" json:"name"`
|
||||||
|
|
||||||
|
// Type selects the provider implementation registered via the SDK.
|
||||||
|
Type string `yaml:"type" json:"type"`
|
||||||
|
|
||||||
|
// SDK optionally names a third-party SDK module providing this provider.
|
||||||
|
SDK string `yaml:"sdk,omitempty" json:"sdk,omitempty"`
|
||||||
|
|
||||||
|
// APIKeys lists inline keys for providers that require them.
|
||||||
|
APIKeys []string `yaml:"api-keys,omitempty" json:"api-keys,omitempty"`
|
||||||
|
|
||||||
|
// Config passes provider-specific options to the implementation.
|
||||||
|
Config map[string]any `yaml:"config,omitempty" json:"config,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AccessProviderTypeConfigAPIKey is the built-in provider validating inline API keys.
|
||||||
|
AccessProviderTypeConfigAPIKey = "config-api-key"
|
||||||
|
|
||||||
|
// DefaultAccessProviderName is applied when no provider name is supplied.
|
||||||
|
DefaultAccessProviderName = "config-inline"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SyncInlineAPIKeys updates the inline API key provider and top-level APIKeys field.
|
||||||
|
func SyncInlineAPIKeys(cfg *SDKConfig, keys []string) {
|
||||||
|
if cfg == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cloned := append([]string(nil), keys...)
|
||||||
|
cfg.APIKeys = cloned
|
||||||
|
if provider := cfg.ConfigAPIKeyProvider(); provider != nil {
|
||||||
|
if provider.Name == "" {
|
||||||
|
provider.Name = DefaultAccessProviderName
|
||||||
|
}
|
||||||
|
provider.APIKeys = cloned
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg.Access.Providers = append(cfg.Access.Providers, AccessProvider{
|
||||||
|
Name: DefaultAccessProviderName,
|
||||||
|
Type: AccessProviderTypeConfigAPIKey,
|
||||||
|
APIKeys: cloned,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigAPIKeyProvider returns the first inline API key provider if present.
|
||||||
|
func (c *SDKConfig) ConfigAPIKeyProvider() *AccessProvider {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := range c.Access.Providers {
|
||||||
|
if c.Access.Providers[i].Type == AccessProviderTypeConfigAPIKey {
|
||||||
|
if c.Access.Providers[i].Name == "" {
|
||||||
|
c.Access.Providers[i].Name = DefaultAccessProviderName
|
||||||
|
}
|
||||||
|
return &c.Access.Providers[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user