From a187d8e20e9e3d8051e0223c761d8ebdcb15ed57 Mon Sep 17 00:00:00 2001 From: newkirk Date: Tue, 21 Jul 2026 13:23:02 -0400 Subject: [PATCH] fix(phase-4): add DB error checking, mask sensitive auth tokens in API and middleware logs --- internal/middleware/auth.go | 6 +++++- internal/providers/deepseek.go | 7 ++----- internal/server/system.go | 13 +++++++++++-- internal/server/users.go | 26 +++++++++++++++++++++----- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go index 3e9934bc..e370e94d 100644 --- a/internal/middleware/auth.go +++ b/internal/middleware/auth.go @@ -72,7 +72,11 @@ func AuthMiddleware(database *db.DB, requireAuth bool) gin.HandlerFunc { c.Next() } else { - log.Printf("Token not found, inactive or error in DB: %s (err: %v)", token, err) + maskedToken := "••••" + if len(token) > 8 { + maskedToken = token[:3] + "••••" + token[len(token)-4:] + } + log.Printf("Token not found, inactive or error in DB: %s (err: %v)", maskedToken, err) c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ "error": gin.H{ "message": "Invalid or inactive client token.", diff --git a/internal/providers/deepseek.go b/internal/providers/deepseek.go index 9cbb86e8..9240baba 100644 --- a/internal/providers/deepseek.go +++ b/internal/providers/deepseek.go @@ -113,14 +113,11 @@ func (p *DeepSeekProvider) ChatCompletion(ctx context.Context, req *models.Unifi } if !resp.IsSuccess() { - var msg string - if resp.RawBody() != nil { + msg := resp.String() + if msg == "" && resp.RawBody() != nil { bodyBytes, _ := io.ReadAll(resp.RawBody()) msg = string(bodyBytes) } - if msg == "" { - msg = resp.String() - } return nil, fmt.Errorf("DeepSeek API error (%d): %s", resp.StatusCode(), msg) } diff --git a/internal/server/system.go b/internal/server/system.go index 2d19ab69..c33d6c60 100644 --- a/internal/server/system.go +++ b/internal/server/system.go @@ -67,18 +67,27 @@ func (s *Server) handleGetSettings(c *gin.Context) { providerCount := 0 modelCount := 0 s.registryMu.RLock() - defer s.registryMu.RUnlock() if s.registry != nil { providerCount = len(s.registry.Providers) for _, p := range s.registry.Providers { modelCount += len(p.Models) } } + s.registryMu.RUnlock() + + maskedTokens := make([]string, len(s.cfg.Server.AuthTokens)) + for i, token := range s.cfg.Server.AuthTokens { + if len(token) > 8 { + maskedTokens[i] = token[:3] + "••••" + token[len(token)-4:] + } else { + maskedTokens[i] = "••••" + } + } c.JSON(http.StatusOK, SuccessResponse(gin.H{ "server": gin.H{ "version": "1.0.0-go", - "auth_tokens": s.cfg.Server.AuthTokens, + "auth_tokens": maskedTokens, }, "database": gin.H{ "type": "sqlite", diff --git a/internal/server/users.go b/internal/server/users.go index 1c17e9a6..7e973cec 100644 --- a/internal/server/users.go +++ b/internal/server/users.go @@ -70,17 +70,33 @@ func (s *Server) handleUpdateUser(c *gin.Context) { } if req.DisplayName != nil { - s.database.Exec("UPDATE users SET display_name = ? WHERE id = ?", req.DisplayName, id) + if _, err := s.database.Exec("UPDATE users SET display_name = ? WHERE id = ?", req.DisplayName, id); err != nil { + c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to update display name")) + return + } } if req.Role != nil { - s.database.Exec("UPDATE users SET role = ? WHERE id = ?", req.Role, id) + if _, err := s.database.Exec("UPDATE users SET role = ? WHERE id = ?", req.Role, id); err != nil { + c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to update role")) + return + } } if req.MustChangePassword != nil { - s.database.Exec("UPDATE users SET must_change_password = ? WHERE id = ?", req.MustChangePassword, id) + if _, err := s.database.Exec("UPDATE users SET must_change_password = ? WHERE id = ?", req.MustChangePassword, id); err != nil { + c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to update password flag")) + return + } } if req.Password != nil { - hash, _ := bcrypt.GenerateFromPassword([]byte(*req.Password), 12) - s.database.Exec("UPDATE users SET password_hash = ? WHERE id = ?", string(hash), id) + hash, err := bcrypt.GenerateFromPassword([]byte(*req.Password), 12) + if err != nil { + c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to hash password")) + return + } + if _, err := s.database.Exec("UPDATE users SET password_hash = ? WHERE id = ?", string(hash), id); err != nil { + c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to update password")) + return + } } c.JSON(http.StatusOK, SuccessResponse(gin.H{"message": "User updated"}))