refactor: add optional disabled config
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Vendored
+14
-10
@@ -34,16 +34,20 @@ export interface Config {
|
||||
* unless you configure credentials for service calls.
|
||||
*/
|
||||
dangerouslyDisableDefaultAuthPolicy?: boolean;
|
||||
rateLimit?: {
|
||||
/**
|
||||
* Limit each IP to max requests per window
|
||||
*/
|
||||
max?: number;
|
||||
/**
|
||||
* The duration for which the rate limit is enforced
|
||||
*/
|
||||
window?: HumanDuration;
|
||||
};
|
||||
rateLimit?:
|
||||
| false
|
||||
| {
|
||||
/**
|
||||
* Limit each IP to max requests per window
|
||||
*/
|
||||
max?: number;
|
||||
/**
|
||||
* The duration for which the rate limit is enforced
|
||||
*/
|
||||
window?: HumanDuration;
|
||||
|
||||
disable?: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
+61
@@ -219,6 +219,8 @@ it('do not limit authenticated requests', async () => {
|
||||
.send()
|
||||
.expect(200);
|
||||
}
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('limit the number of unauthenticated requests', async () => {
|
||||
@@ -302,3 +304,62 @@ it('limit the number of unauthenticated requests', async () => {
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('skip limiting requests when the rate limit is disabled', async () => {
|
||||
const now = Date.now();
|
||||
jest.useFakeTimers({ now });
|
||||
const max = 2;
|
||||
const cacheMock = mockServices.cache.mock();
|
||||
const twoMinutesInMilliseconds = 2 * 60 * 1000;
|
||||
const resetTime = now + twoMinutesInMilliseconds;
|
||||
|
||||
// Simulate that the totalHits exceeds the configured max value
|
||||
cacheMock.get.mockResolvedValue({ totalHits: max + 1, resetTime });
|
||||
|
||||
const { app: app1, barrier: barrier1 } = setup({
|
||||
cache: cacheMock,
|
||||
config: {
|
||||
backend: {
|
||||
auth: {
|
||||
rateLimit: {
|
||||
max,
|
||||
window: { minutes: 2 },
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
barrier1.addAuthPolicy({ allow: 'unauthenticated', path: '/public' });
|
||||
|
||||
// exceed the rate limit for authenticated requests
|
||||
for (let i = 0; i < max + 1; i += 1) {
|
||||
await request(app1)
|
||||
.get('/public')
|
||||
.set('authorization', mockCredentials.user.header())
|
||||
.send()
|
||||
.expect(200);
|
||||
}
|
||||
|
||||
// Simulate that the totalHits exceeds the default max value
|
||||
cacheMock.get.mockResolvedValue({ totalHits: 61, resetTime });
|
||||
|
||||
const { app: app2, barrier: barrier2 } = setup({
|
||||
cache: cacheMock,
|
||||
config: {
|
||||
backend: {
|
||||
auth: {
|
||||
rateLimit: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
barrier2.addAuthPolicy({ allow: 'unauthenticated', path: '/public' });
|
||||
|
||||
// exceed the rate limit for authenticated requests
|
||||
await request(app2).get('/public').send().expect(200);
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
+24
-9
@@ -65,24 +65,39 @@ export function createCredentialsBarrier(options: {
|
||||
const unauthenticatedPredicates = new Array<(path: string) => boolean>();
|
||||
const cookiePredicates = new Array<(path: string) => boolean>();
|
||||
|
||||
// Default rate limit is 60 requests per 1 minute
|
||||
const max = config?.has('backend.auth.rateLimit.max')
|
||||
? config.getNumber('backend.auth.rateLimit.max')
|
||||
: 60;
|
||||
const rateLimitConfig = config.getOptional('backend.auth.rateLimit');
|
||||
|
||||
const duration = config?.has('backend.auth.rateLimit.window')
|
||||
? readDurationFromConfig(config.getConfig('backend.auth.rateLimit.window'))
|
||||
: undefined;
|
||||
const disabled =
|
||||
rateLimitConfig === false ||
|
||||
(typeof rateLimitConfig === 'object' &&
|
||||
config?.getOptionalBoolean('backend.auth.rateLimit.disabled') === true);
|
||||
|
||||
const duration =
|
||||
typeof rateLimitConfig === 'object' &&
|
||||
config?.has('backend.auth.rateLimit.window')
|
||||
? readDurationFromConfig(
|
||||
config.getConfig('backend.auth.rateLimit.window'),
|
||||
)
|
||||
: undefined;
|
||||
|
||||
// Default rate limit window is 1 minute
|
||||
const windowMs = duration ? durationToMilliseconds(duration) : 1 * 60 * 1000;
|
||||
|
||||
const max =
|
||||
typeof rateLimitConfig === 'object' &&
|
||||
config?.has('backend.auth.rateLimit.max')
|
||||
? config.getNumber('backend.auth.rateLimit.max')
|
||||
: 60;
|
||||
|
||||
// Default rate limit is 60 requests per 1 minute
|
||||
const limiter = rateLimit({
|
||||
windowMs,
|
||||
max,
|
||||
limit: max,
|
||||
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
|
||||
legacyHeaders: false, // Disable the `X-RateLimit-*` headers,
|
||||
store: RateLimitStore.fromOptions({ cache }),
|
||||
skip() {
|
||||
return disabled;
|
||||
},
|
||||
});
|
||||
|
||||
const middleware: RequestHandler = (req, res, next) => {
|
||||
|
||||
Reference in New Issue
Block a user