yuken 3 лет назад
Родитель
Сommit
77967b0495

+ 9 - 5
packages/app/src/server/middlewares/api-rate-limiter.ts

@@ -26,7 +26,9 @@ const opts = {
 const rateLimiter = new RateLimiterMongo(opts);
 
 // generate ApiRateLimitConfig for api rate limiter
-const apiRateLimitConfig = generateApiRateLimitConfig();
+const apiRateLimitConfigWithoutRegExp = generateApiRateLimitConfig(false);
+const apiRateLimitConfigWithRegExp = generateApiRateLimitConfig(true);
+const keysWithRegExp = Object.keys(apiRateLimitConfigWithRegExp).map(key => new RegExp(key));
 
 const consumePoints = async(rateLimiter: RateLimiterMongo, key: string, points: number) => {
   const consumePoints = defaultMaxPoints / points;
@@ -40,12 +42,14 @@ module.exports = () => {
     const endpoint = req.path;
     const key = md5(req.ip + endpoint);
 
-    const filterdKeys = Object.keys(apiRateLimitConfig).filter((key) => {
-      const keyRegExp = new RegExp(key);
-      return keyRegExp.test(endpoint);
+    let customizedConfig;
+    keysWithRegExp.forEach((key) => {
+      if (key.test(endpoint)) {
+        customizedConfig = apiRateLimitConfigWithRegExp[key.toString()];
+      }
     });
 
-    const customizedConfig = apiRateLimitConfig[filterdKeys[0]];
+    customizedConfig = apiRateLimitConfigWithoutRegExp[endpoint];
 
     try {
       if (customizedConfig === undefined) {

+ 21 - 20
packages/app/src/server/util/api-rate-limit-config/defaultApiRateLimitConfig.ts

@@ -1,10 +1,8 @@
 import { IApiRateLimitConfig } from '../../interfaces/api-rate-limit-config';
 
 // strict config
-
 const defaultStrictMaxRequests = 1; // per second
-
-const defaultStrictConfigKey: IApiRateLimitConfig = {
+const defaultStrictConfig: IApiRateLimitConfig = {
   '/login/activateInvited': {
     method: 'POST',
     maxRequests: defaultStrictMaxRequests,
@@ -25,6 +23,26 @@ const defaultStrictConfigKey: IApiRateLimitConfig = {
     method: 'POST',
     maxRequests: defaultStrictMaxRequests,
   },
+  '/user-activation/register': {
+    method: 'POST',
+    maxRequests: defaultStrictMaxRequests,
+  },
+};
+
+
+// infinity config
+const defaultInfinityConfig: IApiRateLimitConfig = {
+  '/_api/v3/healthcheck': {
+    method: 'GET',
+    maxRequests: Infinity,
+  },
+};
+
+// default config without reg exp
+export const defaultConfigWithoutRegExp = { ...defaultStrictConfig, ...defaultInfinityConfig };
+
+// default config with reg exp
+export const defaultConfigWithRegExp = {
   '/forgot-password/.*': {
     method: 'GET',
     maxRequests: defaultStrictMaxRequests,
@@ -33,10 +51,6 @@ const defaultStrictConfigKey: IApiRateLimitConfig = {
     method: 'GET',
     maxRequests: defaultStrictMaxRequests,
   },
-  '/user-activation/register': {
-    method: 'POST',
-    maxRequests: defaultStrictMaxRequests,
-  },
   '/download/[0-9a-z]{24}': {
     method: 'GET',
     maxRequests: defaultStrictMaxRequests,
@@ -46,16 +60,3 @@ const defaultStrictConfigKey: IApiRateLimitConfig = {
     maxRequests: defaultStrictMaxRequests,
   },
 };
-
-
-// infinity config
-
-const defaultInfinityConfigKey: IApiRateLimitConfig = {
-  '/_api/v3/healthcheck': {
-    method: 'GET',
-    maxRequests: Infinity,
-  },
-};
-
-
-export default { ...defaultStrictConfigKey, ...defaultInfinityConfigKey };

+ 19 - 12
packages/app/src/server/util/api-rate-limit-config/generateApiRateLimitConfig.ts

@@ -1,12 +1,17 @@
 import { IApiRateLimitConfig } from '../../interfaces/api-rate-limit-config';
 
-import defaultApiRateLimitConfig from './defaultApiRateLimitConfig';
+import { defaultConfigWithoutRegExp, defaultConfigWithRegExp } from './defaultApiRateLimitConfig';
 
-const getTargetFromKey = (key: string) => {
+const envVar = process.env;
+
+const getTargetFromKey = (key: string, withRegExp: boolean) => {
+  if (withRegExp) {
+    return key.replace(/^API_RATE_LIMIT_/, '').replace(/_ENDPOINT_WITH_REGEXP$/, '');
+  }
   return key.replace(/^API_RATE_LIMIT_/, '').replace(/_ENDPOINT$/, '');
 };
 
-const generateApiRateLimitConfigFromEndpoint = (envVar: NodeJS.ProcessEnv, endpointKeys: string[]): IApiRateLimitConfig => {
+const generateApiRateLimitConfigFromEndpoint = (envVar: NodeJS.ProcessEnv, endpointKeys: string[], withRegExp: boolean): IApiRateLimitConfig => {
   const apiRateLimitConfig: IApiRateLimitConfig = {};
   endpointKeys.forEach((key) => {
 
@@ -16,9 +21,11 @@ const generateApiRateLimitConfigFromEndpoint = (envVar: NodeJS.ProcessEnv, endpo
       return;
     }
 
-    const target = getTargetFromKey(key);
-    const method = envVar[`API_RATE_LIMIT_${target}_METHODS`] ?? 'ALL';
-    const maxRequests = Number(envVar[`API_RATE_LIMIT_${target}_MAX_REQUESTS`]);
+    const target = getTargetFromKey(key, withRegExp);
+    const methodKey = withRegExp ? `API_RATE_LIMIT_${target}_METHODS_WITH_REGEXP` : `API_RATE_LIMIT_${target}_METHODS`;
+    const maxRequestsKey = withRegExp ? `API_RATE_LIMIT_${target}_MAX_REQUESTS_WITH_REGEXP` : `API_RATE_LIMIT_${target}_MAX_REQUESTS`;
+    const method = envVar[methodKey] ?? 'ALL';
+    const maxRequests = Number(envVar[maxRequestsKey]);
 
     if (endpoint == null || maxRequests == null) {
       return;
@@ -35,12 +42,10 @@ const generateApiRateLimitConfigFromEndpoint = (envVar: NodeJS.ProcessEnv, endpo
   return apiRateLimitConfig;
 };
 
-// this method is called only one server starts
-export const generateApiRateLimitConfig = (): IApiRateLimitConfig => {
-  const envVar = process.env;
+export const generateApiRateLimitConfig = (withRegExp: boolean): IApiRateLimitConfig => {
 
   const apiRateEndpointKeys = Object.keys(envVar).filter((key) => {
-    const endpointRegExp = /^API_RATE_LIMIT_\w+_ENDPOINT/;
+    const endpointRegExp = withRegExp ? /^API_RATE_LIMIT_\w+_ENDPOINT_WITH_REGEXP/ : /^API_RATE_LIMIT_\w+_ENDPOINT/;
     return endpointRegExp.test(key);
   });
 
@@ -48,7 +53,9 @@ export const generateApiRateLimitConfig = (): IApiRateLimitConfig => {
   apiRateEndpointKeys.sort().reverse();
 
   // get config
-  const apiRateLimitConfig = generateApiRateLimitConfigFromEndpoint(envVar, apiRateEndpointKeys);
+  const apiRateLimitConfig = generateApiRateLimitConfigFromEndpoint(envVar, apiRateEndpointKeys, withRegExp);
+
+  const defaultConfig = withRegExp ? defaultConfigWithRegExp : defaultConfigWithoutRegExp;
 
-  return { ...defaultApiRateLimitConfig, ...apiRateLimitConfig };
+  return { ...defaultConfig, ...apiRateLimitConfig };
 };