diff --git a/package.json b/package.json index 5d77016..0ba5409 100644 --- a/package.json +++ b/package.json @@ -27,38 +27,38 @@ ], "license": "MIT", "dependencies": { - "axios": "^1.4.0", + "axios": "^1.5.0", "bcryptjs": "^2.4.3", "cors": "^2.8.5", "express": "^4.18.2", "express-basic-auth": "^1.2.1", - "express-rate-limit": "^6.8.0", + "express-rate-limit": "^6.10.0", "express-validator": "^7.0.1", - "graphql": "^16.7.1", - "graphql-http": "^1.21.0", + "graphql": "^16.8.0", + "graphql-http": "^1.22.0", "graphql-tag": "^2.12.6", "helmet": "^7.0.0", - "jsonwebtoken": "^9.0.1", + "jsonwebtoken": "^9.0.2", "moment": "^2.29.4", "mongodb": "^5.7.0", "mongoose": "^7.4.0", - "pino": "^8.14.1", - "pino-pretty": "^10.1.0", + "pino": "^8.15.0", + "pino-pretty": "^10.2.0", "swagger-ui-express": "^5.0.0", - "switcher-client": "^3.1.8", - "validator": "^13.9.0" + "switcher-client": "^3.1.9", + "validator": "^13.11.0" }, "devDependencies": { - "@babel/cli": "^7.22.9", - "@babel/core": "^7.22.9", - "@babel/node": "^7.22.6", - "@babel/preset-env": "^7.22.9", + "@babel/cli": "^7.22.10", + "@babel/core": "^7.22.11", + "@babel/node": "^7.22.10", + "@babel/preset-env": "^7.22.14", "@babel/register": "^7.22.5", - "babel-jest": "^29.6.1", + "babel-jest": "^29.6.4", "babel-polyfill": "^6.26.0", "env-cmd": "^10.1.0", - "eslint": "^8.45.0", - "jest": "^29.6.1", + "eslint": "^8.48.0", + "jest": "^29.6.4", "jest-sonar-reporter": "^2.0.0", "node-notifier": "^10.0.1", "nodemon": "^3.0.1", diff --git a/src/middleware/limiter.js b/src/middleware/limiter.js index 31e11db..6a4cbc0 100644 --- a/src/middleware/limiter.js +++ b/src/middleware/limiter.js @@ -5,11 +5,18 @@ const ERROR_MESSAGE = { error: 'API request per minute quota exceeded' }; +const getMaxRate = (rate_limit) => { + if (rate_limit === 0) + return parseInt(DEFAULT_RATE_LIMIT); + + return rate_limit; +}; + export const DEFAULT_RATE_LIMIT = 1000; export const defaultLimiter = rateLimit({ windowMs: DEFAULT_WINDOWMS, - max: parseInt(process.env.MAX_REQUEST_PER_MINUTE || DEFAULT_RATE_LIMIT), + max: getMaxRate(parseInt(process.env.MAX_REQUEST_PER_MINUTE)), standardHeaders: true, message: ERROR_MESSAGE, store: new MemoryStore(), @@ -18,7 +25,8 @@ export const defaultLimiter = rateLimit({ export const clientLimiter = rateLimit({ windowMs: DEFAULT_WINDOWMS, keyGenerator: (request) => request.domain, - max: (request) => request.rate_limit, + max: (request) => getMaxRate(request.rate_limit), + skip: (request) => request.rate_limit === 0, standardHeaders: true, message: ERROR_MESSAGE, store: new MemoryStore(), diff --git a/tests/client-api.test.js b/tests/client-api.test.js index c697733..33d4214 100644 --- a/tests/client-api.test.js +++ b/tests/client-api.test.js @@ -793,6 +793,38 @@ describe('Testing criteria [REST] ', () => { }); }); +describe('Testing criteria [REST] Rate Limit ', () => { + let token; + + beforeAll(async () => { + process.env.MAX_REQUEST_PER_MINUTE = 1; + + await setupDatabase(); + const response = await createRequestAuth(); + token = response.body.token; + }); + + afterAll(() => { + process.env.MAX_REQUEST_PER_MINUTE = 0; + }); + + test('CLIENT_SUITE - Should limit run to 1 execution', async () => { + await request(app) + .post(`/criteria?key=${keyConfig}`) + .set('Authorization', `Bearer ${token}`) + .send() + .expect(200); + + const req = await request(app) + .post(`/criteria?key=${keyConfig}`) + .set('Authorization', `Bearer ${token}`) + .send() + .expect(429); + + expect(req.body.error).toBe('API request per minute quota exceeded'); + }); +}); + describe('Testing domain [Adm-GraphQL] ', () => { afterAll(setupDatabase);