mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-23 19:57:09 +00:00
fix: prevent rate limiting on essential real-time endpoints (addresses #419)
The /api/state and /api/guests/metadata endpoints are now excluded from rate limiting as they are polled frequently by the UI for real-time updates. This prevents the "Loading..." issue when users with multiple nodes access the application. - Added skip list in UniversalRateLimitMiddleware for real-time endpoints - Removed duplicate rate limiting logic from router's ServeHTTP - Consolidated all rate limiting into the universal middleware
This commit is contained in:
@@ -127,6 +127,19 @@ func UniversalRateLimitMiddleware(next http.Handler) http.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
// Skip rate limiting for real-time data endpoints that are polled frequently
|
||||
// These endpoints are essential for UI functionality and should not be rate limited
|
||||
skipPaths := []string{
|
||||
"/api/state", // Real-time state updates
|
||||
"/api/guests/metadata", // Guest metadata (polled frequently)
|
||||
}
|
||||
for _, path := range skipPaths {
|
||||
if strings.Contains(r.URL.Path, path) {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Extract client IP
|
||||
ip := GetClientIP(r)
|
||||
|
||||
|
||||
+2
-34
@@ -906,40 +906,8 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Apply rate limiting for API endpoints
|
||||
if strings.HasPrefix(req.URL.Path, "/api/") {
|
||||
// Skip rate limiting ONLY for real-time data endpoints
|
||||
skipRateLimit := false
|
||||
for _, path := range []string{
|
||||
"/api/state", // WebSocket updates
|
||||
"/api/guests/metadata", // Guest metadata (polled frequently)
|
||||
"/api/health", // Health checks
|
||||
"/ws", // WebSocket
|
||||
} {
|
||||
if strings.Contains(req.URL.Path, path) {
|
||||
skipRateLimit = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Apply stricter rate limiting for auth endpoints (but not status checks)
|
||||
if (strings.Contains(req.URL.Path, "/api/security/") && req.URL.Path != "/api/security/status") || req.URL.Path == "/api/login" {
|
||||
clientIP := GetClientIP(req)
|
||||
// Use auth limiter for security endpoints (10 per minute)
|
||||
if !authLimiter.Allow(clientIP) {
|
||||
http.Error(w, "Too many requests. Please wait before trying again.", http.StatusTooManyRequests)
|
||||
LogAuditEvent("rate_limit", "", clientIP, req.URL.Path, false, "Auth rate limit exceeded")
|
||||
return
|
||||
}
|
||||
} else if !skipRateLimit {
|
||||
// Use general API limiter for other endpoints (500 per minute)
|
||||
clientIP := GetClientIP(req)
|
||||
if !apiLimiter.Allow(clientIP) {
|
||||
http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// Rate limiting is now handled by UniversalRateLimitMiddleware
|
||||
// No need for duplicate rate limiting logic here
|
||||
|
||||
// Log request
|
||||
start := time.Now()
|
||||
|
||||
Reference in New Issue
Block a user