Quellcode durchsuchen

refactor api rate limit

yuken vor 3 Jahren
Ursprung
Commit
f282985193

+ 15 - 19
packages/app/src/server/middlewares/api-rate-limiter.ts

@@ -1,34 +1,35 @@
-import { NextFunction, Request, Response } from 'express';
+import { NextFunction, Request } from 'express';
 
 
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
 
 
 const logger = loggerFactory('growi:middleware:api-rate-limit');
 const logger = loggerFactory('growi:middleware:api-rate-limit');
 
 
-module.exports = (crowi, rateLimiter) => {
 
 
-  return async(req: Request, res: Response, next: NextFunction) => {
+// API_RATE_LIMIT_010_FOO_ENDPOINT=/_api/v3/foo
+// API_RATE_LIMIT_010_FOO_METHODS=GET,POST
+// API_RATE_LIMIT_010_FOO_CONSUME_POINTS=10
+
+module.exports = (rateLimiter, defaultPoints: number) => {
+
+  return async(req: Request, next: NextFunction) => {
 
 
     const endpoint = req.url.replace(/\?.*$/, '');
     const endpoint = req.url.replace(/\?.*$/, '');
     const key = req.ip + endpoint;
     const key = req.ip + endpoint;
 
 
-    const defaultPoints = 10;
-
     const consumePoints = async(points: number = defaultPoints) => {
     const consumePoints = async(points: number = defaultPoints) => {
       await rateLimiter.consume(key, points)
       await rateLimiter.consume(key, points)
         .then(() => {
         .then(() => {
-          logger.info(`${key}: consume 2 points!!!`);
-          return next();
+          next();
         })
         })
         .catch(() => {
         .catch(() => {
-          logger.error(`${key}: point is not enough!`);
-          return next();
+          logger.error(`too many request at ${endpoint}`);
         });
         });
     };
     };
 
 
-    // pick up API_RATE_LIMIT_*_ENDPOINT from env var
+    // pick up API_RATE_LIMIT_*_ENDPOINT from ENV
     const apiRateEndpointKeys = Object.keys(process.env).filter((key) => {
     const apiRateEndpointKeys = Object.keys(process.env).filter((key) => {
-      const endpointRegExp = /^API_RATE_LIMIT_*_ENDPOINT/;
+      const endpointRegExp = /^API_RATE_LIMIT_.*_ENDPOINT/;
       return endpointRegExp.test(key);
       return endpointRegExp.test(key);
     });
     });
 
 
@@ -36,13 +37,11 @@ module.exports = (crowi, rateLimiter) => {
       return process.env[key] === endpoint;
       return process.env[key] === endpoint;
     });
     });
 
 
-    // return default
     if (matchedEndpointKeys.length === 0) {
     if (matchedEndpointKeys.length === 0) {
-      logger.info(`endpoint: ${endpoint} => return default api limit1`);
       await consumePoints();
       await consumePoints();
+      return;
     }
     }
 
 
-
     let prioritizedTarget: [string, string] | null = null; // priprity and keyword
     let prioritizedTarget: [string, string] | null = null; // priprity and keyword
     matchedEndpointKeys.forEach((key) => {
     matchedEndpointKeys.forEach((key) => {
       const target = key.replace('API_RATE_LIMIT_', '').replace('_ENDPOINT', '');
       const target = key.replace('API_RATE_LIMIT_', '').replace('_ENDPOINT', '');
@@ -54,7 +53,6 @@ module.exports = (crowi, rateLimiter) => {
     });
     });
 
 
     if (prioritizedTarget === null) {
     if (prioritizedTarget === null) {
-      logger.info(`endpoint: ${endpoint} => return default api limit2`);
       await consumePoints();
       await consumePoints();
       return;
       return;
     }
     }
@@ -63,16 +61,14 @@ module.exports = (crowi, rateLimiter) => {
     const targetConsumePointsKey = `API_RATE_LIMIT_${prioritizedTarget[0]}_${prioritizedTarget[1]}_CONSUME_POINTS`;
     const targetConsumePointsKey = `API_RATE_LIMIT_${prioritizedTarget[0]}_${prioritizedTarget[1]}_CONSUME_POINTS`;
 
 
     const targetMethods = process.env[targetMethodsKey];
     const targetMethods = process.env[targetMethodsKey];
-    if (targetMethods === undefined || targetMethods.includes(req.method)) {
+    if (targetMethods === undefined || !targetMethods.includes(req.method)) {
       await consumePoints();
       await consumePoints();
       return;
       return;
     }
     }
 
 
     const customizedConsumePoints = process.env[targetConsumePointsKey];
     const customizedConsumePoints = process.env[targetConsumePointsKey];
-    if (typeof customizedConsumePoints !== 'number') {
-      await consumePoints();
-    }
 
 
     await consumePoints(Number(customizedConsumePoints));
     await consumePoints(Number(customizedConsumePoints));
+    return;
   };
   };
 };
 };

+ 3 - 3
packages/app/src/server/routes/index.js

@@ -20,8 +20,8 @@ const autoReap = require('multer-autoreap');
 const { RateLimiterMemory } = require('rate-limiter-flexible');
 const { RateLimiterMemory } = require('rate-limiter-flexible');
 
 
 const opts = {
 const opts = {
-  points: 6, // 6 points
-  duration: 1, // Per second
+  points: 100, // set default value
+  duration: 1, // set default value
 };
 };
 
 
 const rateLimiter = new RateLimiterMemory(opts);
 const rateLimiter = new RateLimiterMemory(opts);
@@ -39,6 +39,7 @@ module.exports = function(crowi, app) {
   const certifySharedFile = require('../middlewares/certify-shared-file')(crowi);
   const certifySharedFile = require('../middlewares/certify-shared-file')(crowi);
   const csrf = require('../middlewares/csrf')(crowi);
   const csrf = require('../middlewares/csrf')(crowi);
   const injectUserUISettings = require('../middlewares/inject-user-ui-settings-to-localvars')();
   const injectUserUISettings = require('../middlewares/inject-user-ui-settings-to-localvars')();
+  const apiRateLimiter = require('../middlewares/api-rate-limiter')(rateLimiter, 10);
 
 
   const uploads = multer({ dest: `${crowi.tmpDir}uploads` });
   const uploads = multer({ dest: `${crowi.tmpDir}uploads` });
   const page = require('./page')(crowi, app);
   const page = require('./page')(crowi, app);
@@ -53,7 +54,6 @@ module.exports = function(crowi, app) {
   const search = require('./search')(crowi, app);
   const search = require('./search')(crowi, app);
   const hackmd = require('./hackmd')(crowi, app);
   const hackmd = require('./hackmd')(crowi, app);
   const ogp = require('./ogp')(crowi);
   const ogp = require('./ogp')(crowi);
-  const apiRateLimiter = require('../middlewares/api-rate-limiter')(crowi, rateLimiter);
 
 
   const unavailableWhenMaintenanceMode = generateUnavailableWhenMaintenanceModeMiddleware(crowi);
   const unavailableWhenMaintenanceMode = generateUnavailableWhenMaintenanceModeMiddleware(crowi);
   const unavailableWhenMaintenanceModeForApi = generateUnavailableWhenMaintenanceModeMiddlewareForApi(crowi);
   const unavailableWhenMaintenanceModeForApi = generateUnavailableWhenMaintenanceModeMiddlewareForApi(crowi);