From f3005572b415b343efe97ac0c0df4f2b0695d871 Mon Sep 17 00:00:00 2001 From: J3vb <192430104+J3vb@users.noreply.github.com> Date: Sun, 19 Jul 2026 08:50:34 +0200 Subject: [PATCH] test(api): lock client-update bucket isolation (W2-1) Co-Authored-By: Claude Fable 5 --- Server/api/livekit_ratelimit_test.go | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Server/api/livekit_ratelimit_test.go b/Server/api/livekit_ratelimit_test.go index 710d900d..074ff3c4 100644 --- a/Server/api/livekit_ratelimit_test.go +++ b/Server/api/livekit_ratelimit_test.go @@ -13,6 +13,44 @@ func okHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } +// TestRateLimitMiddlewareWithPrefix_SeparatesClientUpdateBucket locks the +// W2-1 fix: exhausting the client-update budget must not 429 the sensitive +// endpoints (verify-totp, password change) that ride the empty-prefix +// bucket for the same IP. +func TestRateLimitMiddlewareWithPrefix_SeparatesClientUpdateBucket(t *testing.T) { + limiter := auth.NewRateLimiter() + trustedProxies := []string{"127.0.0.0/8"} + + clientUpdate := rateLimitMiddlewareWithPrefix(limiter, "client_update:", 1, time.Minute, trustedProxies)(http.HandlerFunc(okHandler)) + sensitive := RateLimitMiddleware(limiter, 1, time.Minute, trustedProxies)(http.HandlerFunc(okHandler)) + + newReq := func(path string) *http.Request { + r := httptest.NewRequest(http.MethodGet, path, nil) + r.RemoteAddr = "127.0.0.1:9999" + r.Header.Set("X-Forwarded-For", "203.0.113.7") + return r + } + + // Exhaust the client-update bucket for this IP. + rec := httptest.NewRecorder() + clientUpdate.ServeHTTP(rec, newReq("/client-update")) + if rec.Code != http.StatusOK { + t.Fatalf("first client-update status = %d, want 200", rec.Code) + } + rec = httptest.NewRecorder() + clientUpdate.ServeHTTP(rec, newReq("/client-update")) + if rec.Code != http.StatusTooManyRequests { + t.Fatalf("second client-update status = %d, want 429", rec.Code) + } + + // The same IP's sensitive-endpoint budget must be untouched. + rec = httptest.NewRecorder() + sensitive.ServeHTTP(rec, newReq("/api/v1/auth/verify-totp")) + if rec.Code != http.StatusOK { + t.Fatalf("sensitive endpoint shares the client-update bucket: status = %d, want 200", rec.Code) + } +} + func TestRateLimitMiddlewareWithPrefix_SeparatesLiveKitBucket(t *testing.T) { limiter := auth.NewRateLimiter() trustedProxies := []string{"127.0.0.0/8"}