fix: Phase 1 - security & stability patches
- AuthMiddleware now requires auth on /v1/* routes (returns 401) - WebSocket origin check configurable via WSAllowedOrigin - Removed debug fmt.Printf leaks (config, ollama, server) - Registry access protected by sync.RWMutex (race condition fix) - Session cleanup goroutine runs every 15 min - RevokeSession returns error instead of silent no-op
This commit is contained in:
@@ -8,17 +8,17 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gophergate/internal/db"
|
||||
"gophergate/internal/models"
|
||||
"gophergate/internal/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gophergate/internal/db"
|
||||
"gophergate/internal/models"
|
||||
"gophergate/internal/utils"
|
||||
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/shirou/gopsutil/v3/load"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
"github.com/shirou/gopsutil/v3/process"
|
||||
)
|
||||
|
||||
@@ -168,7 +168,9 @@ func (s *Server) handleChangePassword(c *gin.Context) {
|
||||
|
||||
func (s *Server) handleLogout(c *gin.Context) {
|
||||
token := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")
|
||||
s.sessions.RevokeSession(token)
|
||||
if err := s.sessions.RevokeSession(token); err != nil {
|
||||
fmt.Printf("Error revoking session: %v\n", err)
|
||||
}
|
||||
c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "Logged out"}))
|
||||
}
|
||||
|
||||
@@ -226,7 +228,7 @@ func (s *Server) handleUsageSummary(c *gin.Context) {
|
||||
}
|
||||
|
||||
clause, binds := filter.ToSQL()
|
||||
|
||||
|
||||
// Total stats
|
||||
var totalStats struct {
|
||||
TotalRequests int `db:"total_requests"`
|
||||
@@ -307,7 +309,7 @@ func (s *Server) handleTimeSeries(c *gin.Context) {
|
||||
}
|
||||
|
||||
clause, binds := filter.ToSQL()
|
||||
|
||||
|
||||
if clause == "" {
|
||||
cutoff := time.Now().UTC().Add(-30 * 24 * time.Hour)
|
||||
clause = " AND timestamp >= ?"
|
||||
@@ -444,7 +446,10 @@ func (s *Server) handleAnalyticsBreakdown(c *gin.Context) {
|
||||
var label string
|
||||
var value int
|
||||
if err := mRows.Scan(&label, &value); err == nil {
|
||||
models = append(models, struct{Label string `json:"label"`; Value int `json:"value"`}{label, value})
|
||||
models = append(models, struct {
|
||||
Label string `json:"label"`
|
||||
Value int `json:"value"`
|
||||
}{label, value})
|
||||
}
|
||||
}
|
||||
mRows.Close()
|
||||
@@ -461,7 +466,10 @@ func (s *Server) handleAnalyticsBreakdown(c *gin.Context) {
|
||||
var label string
|
||||
var value int
|
||||
if err := cRows.Scan(&label, &value); err == nil {
|
||||
clients = append(clients, struct{Label string `json:"label"`; Value int `json:"value"`}{label, value})
|
||||
clients = append(clients, struct {
|
||||
Label string `json:"label"`
|
||||
Value int `json:"value"`
|
||||
}{label, value})
|
||||
}
|
||||
}
|
||||
cRows.Close()
|
||||
@@ -537,15 +545,15 @@ func (s *Server) handleGetClients(c *gin.Context) {
|
||||
}
|
||||
|
||||
type UIClient struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
LastUsed *time.Time `json:"last_used"`
|
||||
RequestsCount int `json:"requests_count"`
|
||||
TokensCount int `json:"tokens_count"`
|
||||
Status string `json:"status"`
|
||||
RateLimitPerMinute int `json:"rate_limit_per_minute"`
|
||||
RequestsCount int `json:"requests_count"`
|
||||
TokensCount int `json:"tokens_count"`
|
||||
Status string `json:"status"`
|
||||
RateLimitPerMinute int `json:"rate_limit_per_minute"`
|
||||
}
|
||||
|
||||
uiClients := make([]UIClient, len(clients))
|
||||
@@ -608,12 +616,12 @@ func (s *Server) handleGetClient(c *gin.Context) {
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, SuccessResponse(gin.H{
|
||||
"id": cl.ClientID,
|
||||
"name": name,
|
||||
"description": desc,
|
||||
"is_active": cl.IsActive,
|
||||
"rate_limit_per_minute": cl.RateLimitPerMinute,
|
||||
"created_at": cl.CreatedAt,
|
||||
"id": cl.ClientID,
|
||||
"name": name,
|
||||
"description": desc,
|
||||
"is_active": cl.IsActive,
|
||||
"rate_limit_per_minute": cl.RateLimitPerMinute,
|
||||
"created_at": cl.CreatedAt,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -873,10 +881,16 @@ func (s *Server) handleGetProviders(c *gin.Context) {
|
||||
var models []string
|
||||
if s.registry != nil {
|
||||
registryID := id
|
||||
if id == "gemini" { registryID = "google" }
|
||||
if id == "moonshot" { registryID = "moonshot" }
|
||||
if id == "grok" { registryID = "xai" }
|
||||
|
||||
if id == "gemini" {
|
||||
registryID = "google"
|
||||
}
|
||||
if id == "moonshot" {
|
||||
registryID = "moonshot"
|
||||
}
|
||||
if id == "grok" {
|
||||
registryID = "xai"
|
||||
}
|
||||
|
||||
if pInfo, ok := s.registry.Providers[registryID]; ok {
|
||||
for mID := range pInfo.Models {
|
||||
models = append(models, mID)
|
||||
@@ -969,7 +983,7 @@ func (s *Server) handleTestProvider(c *gin.Context) {
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
|
||||
// Prepare a simple test request
|
||||
testReq := &models.UnifiedRequest{
|
||||
Model: "gpt-4o-mini", // Default cheap test model
|
||||
@@ -1023,7 +1037,7 @@ func (s *Server) handleGetModels(c *gin.Context) {
|
||||
// Merge registry models with DB overrides
|
||||
var dbModels []db.ModelConfig
|
||||
_ = s.database.Select(&dbModels, "SELECT * FROM model_configs")
|
||||
|
||||
|
||||
dbMap := make(map[string]db.ModelConfig)
|
||||
for _, m := range dbModels {
|
||||
dbMap[m.ID] = m
|
||||
@@ -1305,7 +1319,7 @@ func (s *Server) handleUpdateUser(c *gin.Context) {
|
||||
|
||||
func (s *Server) handleDeleteUser(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
|
||||
session, _ := c.Get("session")
|
||||
if sess, ok := session.(*Session); ok {
|
||||
var username string
|
||||
|
||||
Reference in New Issue
Block a user