Big update

This commit is contained in:
Alois 2026-08-27 15:02:32 +02:00
commit 2e6afc460b
Signed by: alois
SSH key fingerprint: SHA256:GBzT2DXvAuGV9XIV5W3WrzVpjU54FThmxHXdbz95J24
474 changed files with 934 additions and 86159 deletions

View file

@ -1,7 +1,6 @@
package api
import (
"context"
"errors"
"io/fs"
"net/http"
@ -26,165 +25,16 @@ func (s *Server) registerManagementRoutes() {
log.Info("management routes registered after secret key configuration")
s.engine.POST("/v0/management/oauth-callback", s.managementAvailabilityMiddleware(), s.mgmt.PostOAuthCallback)
s.engine.GET("/v0/management/oauth-callback", s.managementAvailabilityMiddleware(), s.mgmt.GetOAuthCallback)
mgmt := s.engine.Group("/v0/management")
mgmt.Use(s.managementAvailabilityMiddleware(), s.mgmt.Middleware())
{
mgmt.GET("/config", s.mgmt.GetConfig)
mgmt.GET("/config.yaml", s.mgmt.GetConfigYAML)
mgmt.PUT("/config.yaml", s.mgmt.PutConfigYAML)
mgmt.GET("/latest-version", s.mgmt.GetLatestVersion)
mgmt.GET("/plugins", s.mgmt.ListPlugins)
mgmt.GET("/plugin-store", s.mgmt.ListPluginStore)
mgmt.POST("/plugin-store/:id/install", s.mgmt.InstallPluginFromStore)
mgmt.DELETE("/plugins/:id", s.mgmt.DeletePlugin)
mgmt.PATCH("/plugins/:id/enabled", s.mgmt.PatchPluginEnabled)
mgmt.GET("/plugins/:id/config", s.mgmt.GetPluginConfig)
mgmt.PUT("/plugins/:id/config", s.mgmt.PutPluginConfig)
mgmt.PATCH("/plugins/:id/config", s.mgmt.PatchPluginConfig)
mgmt.GET("/debug", s.mgmt.GetDebug)
mgmt.PUT("/debug", s.mgmt.PutDebug)
mgmt.PATCH("/debug", s.mgmt.PutDebug)
mgmt.GET("/logging-to-file", s.mgmt.GetLoggingToFile)
mgmt.PUT("/logging-to-file", s.mgmt.PutLoggingToFile)
mgmt.PATCH("/logging-to-file", s.mgmt.PutLoggingToFile)
mgmt.GET("/logs-max-total-size-mb", s.mgmt.GetLogsMaxTotalSizeMB)
mgmt.PUT("/logs-max-total-size-mb", s.mgmt.PutLogsMaxTotalSizeMB)
mgmt.PATCH("/logs-max-total-size-mb", s.mgmt.PutLogsMaxTotalSizeMB)
mgmt.GET("/error-logs-max-files", s.mgmt.GetErrorLogsMaxFiles)
mgmt.PUT("/error-logs-max-files", s.mgmt.PutErrorLogsMaxFiles)
mgmt.PATCH("/error-logs-max-files", s.mgmt.PutErrorLogsMaxFiles)
mgmt.GET("/usage-statistics-enabled", s.mgmt.GetUsageStatisticsEnabled)
mgmt.PUT("/usage-statistics-enabled", s.mgmt.PutUsageStatisticsEnabled)
mgmt.PATCH("/usage-statistics-enabled", s.mgmt.PutUsageStatisticsEnabled)
mgmt.GET("/proxy-url", s.mgmt.GetProxyURL)
mgmt.PUT("/proxy-url", s.mgmt.PutProxyURL)
mgmt.PATCH("/proxy-url", s.mgmt.PutProxyURL)
mgmt.DELETE("/proxy-url", s.mgmt.DeleteProxyURL)
mgmt.POST("/api-call", s.mgmt.APICall)
mgmt.GET("/quota-exceeded/switch-project", s.mgmt.GetSwitchProject)
mgmt.PUT("/quota-exceeded/switch-project", s.mgmt.PutSwitchProject)
mgmt.PATCH("/quota-exceeded/switch-project", s.mgmt.PutSwitchProject)
mgmt.GET("/quota-exceeded/switch-preview-model", s.mgmt.GetSwitchPreviewModel)
mgmt.PUT("/quota-exceeded/switch-preview-model", s.mgmt.PutSwitchPreviewModel)
mgmt.PATCH("/quota-exceeded/switch-preview-model", s.mgmt.PutSwitchPreviewModel)
mgmt.POST("/reset-quota", s.mgmt.ResetQuota)
mgmt.GET("/api-keys", s.mgmt.GetAPIKeys)
mgmt.PUT("/api-keys", s.mgmt.PutAPIKeys)
mgmt.PATCH("/api-keys", s.mgmt.PatchAPIKeys)
mgmt.DELETE("/api-keys", s.mgmt.DeleteAPIKeys)
mgmt.GET("/api-key-usage", s.mgmt.GetAPIKeyUsage)
mgmt.GET("/usage-queue", s.mgmt.GetUsageQueue)
mgmt.GET("/gemini-api-key", s.mgmt.GetGeminiKeys)
mgmt.PUT("/gemini-api-key", s.mgmt.PutGeminiKeys)
mgmt.PATCH("/gemini-api-key", s.mgmt.PatchGeminiKey)
mgmt.DELETE("/gemini-api-key", s.mgmt.DeleteGeminiKey)
mgmt.GET("/interactions-api-key", s.mgmt.GetInteractionsKeys)
mgmt.PUT("/interactions-api-key", s.mgmt.PutInteractionsKeys)
mgmt.PATCH("/interactions-api-key", s.mgmt.PatchInteractionsKey)
mgmt.DELETE("/interactions-api-key", s.mgmt.DeleteInteractionsKey)
mgmt.GET("/logs", s.mgmt.GetLogs)
mgmt.DELETE("/logs", s.mgmt.DeleteLogs)
mgmt.GET("/request-error-logs", s.mgmt.GetRequestErrorLogs)
mgmt.GET("/request-error-logs/:name", s.mgmt.DownloadRequestErrorLog)
mgmt.GET("/request-log-by-id/:id", s.mgmt.GetRequestLogByID)
mgmt.GET("/request-log", s.mgmt.GetRequestLog)
mgmt.PUT("/request-log", s.mgmt.PutRequestLog)
mgmt.PATCH("/request-log", s.mgmt.PutRequestLog)
mgmt.GET("/ws-auth", s.mgmt.GetWebsocketAuth)
mgmt.PUT("/ws-auth", s.mgmt.PutWebsocketAuth)
mgmt.PATCH("/ws-auth", s.mgmt.PutWebsocketAuth)
mgmt.GET("/request-retry", s.mgmt.GetRequestRetry)
mgmt.PUT("/request-retry", s.mgmt.PutRequestRetry)
mgmt.PATCH("/request-retry", s.mgmt.PutRequestRetry)
mgmt.GET("/max-retry-credentials", s.mgmt.GetMaxRetryCredentials)
mgmt.PUT("/max-retry-credentials", s.mgmt.PutMaxRetryCredentials)
mgmt.PATCH("/max-retry-credentials", s.mgmt.PutMaxRetryCredentials)
mgmt.GET("/max-retry-interval", s.mgmt.GetMaxRetryInterval)
mgmt.PUT("/max-retry-interval", s.mgmt.PutMaxRetryInterval)
mgmt.PATCH("/max-retry-interval", s.mgmt.PutMaxRetryInterval)
mgmt.GET("/force-model-prefix", s.mgmt.GetForceModelPrefix)
mgmt.PUT("/force-model-prefix", s.mgmt.PutForceModelPrefix)
mgmt.PATCH("/force-model-prefix", s.mgmt.PutForceModelPrefix)
mgmt.GET("/routing/strategy", s.mgmt.GetRoutingStrategy)
mgmt.PUT("/routing/strategy", s.mgmt.PutRoutingStrategy)
mgmt.PATCH("/routing/strategy", s.mgmt.PutRoutingStrategy)
mgmt.GET("/claude-api-key", s.mgmt.GetClaudeKeys)
mgmt.PUT("/claude-api-key", s.mgmt.PutClaudeKeys)
mgmt.PATCH("/claude-api-key", s.mgmt.PatchClaudeKey)
mgmt.DELETE("/claude-api-key", s.mgmt.DeleteClaudeKey)
mgmt.GET("/codex-api-key", s.mgmt.GetCodexKeys)
mgmt.PUT("/codex-api-key", s.mgmt.PutCodexKeys)
mgmt.PATCH("/codex-api-key", s.mgmt.PatchCodexKey)
mgmt.DELETE("/codex-api-key", s.mgmt.DeleteCodexKey)
mgmt.GET("/xai-api-key", s.mgmt.GetXAIKeys)
mgmt.PUT("/xai-api-key", s.mgmt.PutXAIKeys)
mgmt.PATCH("/xai-api-key", s.mgmt.PatchXAIKey)
mgmt.DELETE("/xai-api-key", s.mgmt.DeleteXAIKey)
mgmt.GET("/openai-compatibility", s.mgmt.GetOpenAICompat)
mgmt.PUT("/openai-compatibility", s.mgmt.PutOpenAICompat)
mgmt.PATCH("/openai-compatibility", s.mgmt.PatchOpenAICompat)
mgmt.DELETE("/openai-compatibility", s.mgmt.DeleteOpenAICompat)
mgmt.GET("/vertex-api-key", s.mgmt.GetVertexCompatKeys)
mgmt.PUT("/vertex-api-key", s.mgmt.PutVertexCompatKeys)
mgmt.PATCH("/vertex-api-key", s.mgmt.PatchVertexCompatKey)
mgmt.DELETE("/vertex-api-key", s.mgmt.DeleteVertexCompatKey)
mgmt.GET("/oauth-excluded-models", s.mgmt.GetOAuthExcludedModels)
mgmt.PUT("/oauth-excluded-models", s.mgmt.PutOAuthExcludedModels)
mgmt.PATCH("/oauth-excluded-models", s.mgmt.PatchOAuthExcludedModels)
mgmt.DELETE("/oauth-excluded-models", s.mgmt.DeleteOAuthExcludedModels)
mgmt.GET("/oauth-model-alias", s.mgmt.GetOAuthModelAlias)
mgmt.PUT("/oauth-model-alias", s.mgmt.PutOAuthModelAlias)
mgmt.PATCH("/oauth-model-alias", s.mgmt.PatchOAuthModelAlias)
mgmt.DELETE("/oauth-model-alias", s.mgmt.DeleteOAuthModelAlias)
mgmt.GET("/oauth-request-scoped-errors", s.mgmt.GetOAuthRequestScopedErrors)
mgmt.PUT("/oauth-request-scoped-errors", s.mgmt.PutOAuthRequestScopedErrors)
mgmt.PATCH("/oauth-request-scoped-errors", s.mgmt.PatchOAuthRequestScopedErrors)
mgmt.DELETE("/oauth-request-scoped-errors", s.mgmt.DeleteOAuthRequestScopedErrors)
mgmt.GET("/auth-files", s.mgmt.ListAuthFiles)
mgmt.GET("/auth-files/models", s.mgmt.GetAuthFileModels)
mgmt.GET("/model-definitions/:channel", s.mgmt.GetStaticModelDefinitions)
mgmt.GET("/auth-files/download", s.mgmt.DownloadAuthFile)
mgmt.POST("/auth-files", s.mgmt.UploadAuthFile)
mgmt.DELETE("/auth-files", s.mgmt.DeleteAuthFile)
mgmt.PATCH("/auth-files/status", s.mgmt.PatchAuthFileStatus)
mgmt.PATCH("/auth-files/fields", s.mgmt.PatchAuthFileFields)
mgmt.POST("/vertex/import", s.mgmt.ImportVertexCredential)
mgmt.GET("/anthropic-auth-url", s.mgmt.RequestAnthropicToken)
mgmt.POST("/codex-quota", s.mgmt.CodexQuota)
mgmt.GET("/codex-auth-url", s.mgmt.RequestCodexToken)
mgmt.GET("/antigravity-auth-url", s.mgmt.RequestAntigravityToken)
mgmt.GET("/kimi-auth-url", s.mgmt.RequestKimiToken)
mgmt.GET("/xai-auth-url", s.mgmt.RequestXAIToken)
mgmt.GET("/get-auth-status", s.mgmt.GetAuthStatus)
mgmt.DELETE("/oauth-session", s.mgmt.CancelAuthSession)
mgmt.POST("/oauth-callback", s.mgmt.PostOAuthCallback)
}
}
@ -202,10 +52,6 @@ func (s *Server) managementAvailable(c *gin.Context) bool {
c.AbortWithStatus(http.StatusNotFound)
return false
}
if s.cfg.Home.Enabled {
c.AbortWithStatus(http.StatusNotFound)
return false
}
if !s.managementRoutesEnabled.Load() {
c.AbortWithStatus(http.StatusNotFound)
return false
@ -213,90 +59,15 @@ func (s *Server) managementAvailable(c *gin.Context) bool {
return true
}
func (s *Server) refreshPluginManagementRoutes() {
if s == nil || s.pluginHost == nil || s.engine == nil {
return
}
s.pluginHost.RegisterManagementRoutes(context.Background(), s.registeredManagementRouteKeys())
}
// RefreshPluginManagementRoutes rebuilds plugin-owned Management API routes.
func (s *Server) RefreshPluginManagementRoutes() {
s.refreshPluginManagementRoutes()
}
func (s *Server) registeredManagementRouteKeys() map[string]struct{} {
out := make(map[string]struct{})
if s == nil || s.engine == nil {
return out
}
for _, route := range s.engine.Routes() {
if strings.HasPrefix(route.Path, "/v0/management/") || route.Path == "/v0/management" {
out[strings.ToUpper(strings.TrimSpace(route.Method))+" "+route.Path] = struct{}{}
}
}
return out
}
func (s *Server) RefreshPluginManagementRoutes() {}
func (s *Server) pluginManagementNoRoute(c *gin.Context) {
if s == nil || c == nil || c.Request == nil || c.Request.URL == nil {
if c != nil {
c.AbortWithStatus(http.StatusNotFound)
}
return
}
path := c.Request.URL.Path
if strings.HasPrefix(path, "/v0/resource/plugins/") {
s.pluginResourceNoRoute(c)
return
}
if path != "/v0/management" && !strings.HasPrefix(path, "/v0/management/") {
c.AbortWithStatus(http.StatusNotFound)
return
}
if s.pluginHost == nil || s.mgmt == nil {
c.AbortWithStatus(http.StatusNotFound)
return
}
if !s.managementAvailable(c) {
return
}
s.mgmt.Middleware()(c)
if c.IsAborted() {
return
}
if s.mgmt.ServePluginAuthURL(c) {
c.Abort()
return
}
if s.pluginHost.ServeManagementHTTP(c.Writer, c.Request) {
c.Abort()
return
}
c.AbortWithStatus(http.StatusNotFound)
}
func (s *Server) pluginResourceNoRoute(c *gin.Context) {
if s == nil || c == nil || c.Request == nil || c.Request.URL == nil {
if c != nil {
c.AbortWithStatus(http.StatusNotFound)
}
return
}
if s.cfg == nil || s.cfg.Home.Enabled || s.pluginHost == nil {
c.AbortWithStatus(http.StatusNotFound)
return
}
if s.pluginHost.ServeResourceHTTP(c.Writer, c.Request) {
c.Abort()
return
}
c.AbortWithStatus(http.StatusNotFound)
}
func (s *Server) serveManagementControlPanel(c *gin.Context) {
cfg := s.cfg
if cfg == nil || cfg.Home.Enabled || cfg.RemoteManagement.DisableControlPanel {
if cfg == nil || cfg.RemoteManagement.DisableControlPanel {
c.AbortWithStatus(http.StatusNotFound)
return
}
@ -314,7 +85,7 @@ func (s *Server) serveManagementControlPanel(c *gin.Context) {
func (s *Server) serveManagementAsset(c *gin.Context) {
cfg := s.cfg
if cfg == nil || cfg.Home.Enabled || cfg.RemoteManagement.DisableControlPanel {
if cfg == nil || cfg.RemoteManagement.DisableControlPanel {
c.AbortWithStatus(http.StatusNotFound)
return
}