feat: Add request rate limiter based on IP address (#8174)

This commit is contained in:
Daniel
2023-01-06 23:39:02 +11:00
committed by GitHub
parent 0eac5dc6d4
commit 6c79f6a69e
13 changed files with 713 additions and 50 deletions

View File

@@ -85,6 +85,7 @@ export class Config {
requestKeywordDenylist,
allowExpiredAuthDataToken,
logLevels,
rateLimit,
}) {
if (masterKey === readOnlyMasterKey) {
throw new Error('masterKey and readOnlyMasterKey should be different');
@@ -126,6 +127,7 @@ export class Config {
this.validateEnforcePrivateUsers(enforcePrivateUsers);
this.validateAllowExpiredAuthDataToken(allowExpiredAuthDataToken);
this.validateRequestKeywordDenylist(requestKeywordDenylist);
this.validateRateLimit(rateLimit);
this.validateLogLevels(logLevels);
}
@@ -517,6 +519,48 @@ export class Config {
}
}
static validateRateLimit(rateLimit) {
if (!rateLimit) {
return;
}
if (
Object.prototype.toString.call(rateLimit) !== '[object Object]' &&
!Array.isArray(rateLimit)
) {
throw `rateLimit must be an array or object`;
}
const options = Array.isArray(rateLimit) ? rateLimit : [rateLimit];
for (const option of options) {
if (Object.prototype.toString.call(option) !== '[object Object]') {
throw `rateLimit must be an array of objects`;
}
if (option.requestPath == null) {
throw `rateLimit.requestPath must be defined`;
}
if (typeof option.requestPath !== 'string') {
throw `rateLimit.requestPath must be a string`;
}
if (option.requestTimeWindow == null) {
throw `rateLimit.requestTimeWindow must be defined`;
}
if (typeof option.requestTimeWindow !== 'number') {
throw `rateLimit.requestTimeWindow must be a number`;
}
if (option.includeInternalRequests && typeof option.includeInternalRequests !== 'boolean') {
throw `rateLimit.includeInternalRequests must be a boolean`;
}
if (option.requestCount == null) {
throw `rateLimit.requestCount must be defined`;
}
if (typeof option.requestCount !== 'number') {
throw `rateLimit.requestCount must be a number`;
}
if (option.errorResponseMessage && typeof option.errorResponseMessage !== 'string') {
throw `rateLimit.errorResponseMessage must be a string`;
}
}
}
generateEmailVerifyTokenExpiresAt() {
if (!this.verifyUserEmails || !this.emailVerifyTokenValidityDuration) {
return undefined;