feat: enhance configuration and rate limiting
- Added new configuration options: trustProxy, uploadConcurrency, batchMaxItems, batchMaxSizeBytes, and maxRequestBodyBytes to AppConfig. - Implemented utility functions for parsing environment variables and masking sensitive data. - Updated rate limiting logic to use configurable window size and maximum requests per window. - Introduced a middleware for rate limiting on specific routes. - Refactored file handling routes to support streaming downloads instead of redirects. - Improved error handling and response formatting in file routes. - Added support for oversized request rejection based on Content-Length header. - Updated Swagger documentation to reflect changes in API behavior and responses. - Enhanced tests to cover new features and ensure proper functionality.
This commit is contained in:
+34
-14
@@ -1,25 +1,45 @@
|
||||
import { beforeEach, describe, expect, it, spyOn } from 'bun:test';
|
||||
import logger from '../src/utils/logger';
|
||||
import { checkRateLimit, cleanupRateLimitCache } from '../src/utils/rateLimit';
|
||||
|
||||
// Spy on logger.warn
|
||||
const warnSpy = spyOn(logger, 'warn');
|
||||
import { beforeEach, describe, expect, it } from 'bun:test';
|
||||
import { checkRateLimit, cleanupRateLimitCache, clearRateLimitCache } from '../src/utils/rateLimit';
|
||||
|
||||
describe('Rate Limiter', () => {
|
||||
beforeEach(() => {
|
||||
warnSpy.mockClear();
|
||||
clearRateLimitCache();
|
||||
});
|
||||
|
||||
it('should always allow requests as rate limiter is disabled', () => {
|
||||
it('should allow requests up to the configured limit then block', () => {
|
||||
const key = 'user-1';
|
||||
expect(checkRateLimit(key)).toBe(true);
|
||||
expect(checkRateLimit(key)).toBe(true);
|
||||
expect(checkRateLimit(key)).toBe(true);
|
||||
expect(checkRateLimit(key)).toBe(true);
|
||||
expect(warnSpy).not.toHaveBeenCalled();
|
||||
|
||||
// Default config maxRequests is 30; all 20 should pass
|
||||
for (let i = 0; i < 20; i++) {
|
||||
expect(checkRateLimit(key)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('should no-op on cleanup', () => {
|
||||
it('should block requests when limit exceeded', () => {
|
||||
const key = 'user-2';
|
||||
|
||||
// Exhaust the limit (30 by default)
|
||||
for (let i = 0; i < 30; i++) {
|
||||
checkRateLimit(key);
|
||||
}
|
||||
|
||||
expect(checkRateLimit(key)).toBe(false);
|
||||
});
|
||||
|
||||
it('should reset window after cleanup on expired entries', async () => {
|
||||
const key = 'user-3';
|
||||
|
||||
// Use one request then wait past the window
|
||||
expect(checkRateLimit(key)).toBe(true);
|
||||
|
||||
// Simulate expiry by advancing past the window
|
||||
// We can only test cleanup of non-expired entries (no-op)
|
||||
expect(() => cleanupRateLimitCache()).not.toThrow();
|
||||
});
|
||||
|
||||
it('should track different IPs independently', () => {
|
||||
expect(checkRateLimit('10.0.0.1')).toBe(true);
|
||||
expect(checkRateLimit('10.0.0.1')).toBe(true);
|
||||
expect(checkRateLimit('10.0.0.2')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user