- H1: log legacy test-principal fallback (path/method/remote_addr) via slog.Warn so silent unauthenticated access is observable - H2: AddComment/Claim now derive actor ID/Name/Role from the auth principal and server-side doc duty resolution (resolveDocGovRole), never from request body; GetDocument/ListComments/ListAuditLogs now require project membership via requireDocGovDocAccess - H3: handleGetChatTurn asserts session ownership; handleListChatSessions and handleGetUserContext reject cross-user user_id (403) and stop defaulting to user id=1 Co-authored-by: Cursor <cursoragent@cursor.com>
70 lines
1.7 KiB
Go
70 lines
1.7 KiB
Go
package server
|
|
|
|
import (
|
|
"log/slog"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
func (s *Server) allowLegacyTestPrincipal() bool {
|
|
if s.cfg == nil {
|
|
return false
|
|
}
|
|
env := s.cfg.Env
|
|
if env != "dev" && env != "test" && env != "" {
|
|
return false
|
|
}
|
|
return s.cfg.AllowInMemory && s.cfg.ContextDbHost == ""
|
|
}
|
|
|
|
func isPublicRoute(method, path string) bool {
|
|
if path == "/" || path == "/health" || path == "/api/v1/health" ||
|
|
path == "/ready" || path == "/api/v1/ready" ||
|
|
path == "/api/v1/vault/status" {
|
|
return true
|
|
}
|
|
if method == http.MethodPost && path == "/api/v1/auth/login" {
|
|
return true
|
|
}
|
|
if method == http.MethodPost && path == "/api/v1/auth/register" {
|
|
return true
|
|
}
|
|
if method == http.MethodGet && path == "/api/v1/auth/public-config" {
|
|
return true
|
|
}
|
|
if !strings.HasPrefix(path, "/api/") {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (s *Server) authMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
path := r.URL.Path
|
|
if isPublicRoute(r.Method, path) {
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
user, err := s.authenticateUser(r)
|
|
if (err != nil || user == nil) && s.allowLegacyTestPrincipal() {
|
|
if fallback, fbErr := s.authSvc.GetUserByID(r.Context(), 1); fbErr == nil && fallback != nil {
|
|
slog.Warn("legacy_test_principal_fallback",
|
|
"path", r.URL.Path, "method", r.Method,
|
|
"remote_addr", r.RemoteAddr, "fallback_user_id", fallback.ID)
|
|
user = fallback
|
|
}
|
|
}
|
|
if user == nil {
|
|
writeJSONResponse(w, http.StatusUnauthorized, map[string]string{
|
|
"error_code": "ERR_UNAUTHENTICATED",
|
|
"message": "请先登录",
|
|
})
|
|
return
|
|
}
|
|
|
|
ctx := withPrincipal(r.Context(), user)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|