feat(rate-limit tiers): Created finer-resolution rate limits + unit tests

This commit is contained in:
Chris Troutner
2019-10-31 14:15:53 -07:00
parent 41d048f6a5
commit 17525a40d5
2 changed files with 72 additions and 19 deletions
+12 -6
View File
@@ -1,10 +1,13 @@
/*
This file controls the request-per-minute (RPM) rate limits.
It is assumed that this middleware is run AFTER the auth.js middleware which
checks for Basic auth. If the user adds the correct Basic auth to the header
of their API request, they will get pro-tier rate limits. By default, the
freemium rate limits apply.
It is assumed that this middleware is run AFTER the jwt-auth.js and auth.js
middleware.
Current rate limiting rules in requests-per-minute:
- anonymous access: 3
- free access: 10
- any paid tier: 100
*/
"use strict"
@@ -16,10 +19,10 @@ const axios = require("axios")
// Set max requests per minute
const maxRequests = process.env.RATE_LIMIT_MAX_REQUESTS
? parseInt(process.env.RATE_LIMIT_MAX_REQUESTS)
: 10
: 3
// Pro-tier rate limits are 10x the freemium limits.
const PRO_RPM = 10 * maxRequests
// const PRO_RPM = 10 * maxRequests
// Unique route mapped to its rate limit
const uniqueRateLimits = {}
@@ -87,6 +90,9 @@ const routeRateLimit = async function(req, res, next) {
// TODO: replace the console.logs with calls to our logging system.
//console.log(`applying pro-rate limits`)
let PRO_RPM = 10 // Default value for free tier
if (req.locals.apiLevel > 0) PRO_RPM = 100 // RPM for paid tiers.
// Create new RateLimit if none exists for this route
if (!uniqueRateLimits[route]) {
uniqueRateLimits[route] = new RateLimit({
+60 -13
View File
@@ -62,12 +62,67 @@ describe("#route-ratelimits", () => {
assert.equal(next.called, true)
})
it("should trigger rate-limit handler if rate limits exceeds 25 request per minute", async () => {
it("should trigger rate-limit handler if rate limits exceeds 5 request per minute", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
for (let i = 0; i < 35; i++) {
for (let i = 0; i < 5; i++) {
next.reset() // reset the stubbed next() function.
await routeRateLimit(req, res, next)
//console.log(`next() called: ${next.called}`)
}
// Note: next() will be called unless the rate-limit kicks in.
assert.equal(
next.called,
false,
`next should not be called if rate limit was triggered.`
)
})
it("should NOT trigger rate-limit for free-tier at 5 RPM", async () => {
// Clear the require cache before running this test.
delete require.cache[
require.resolve("../../src/middleware/route-ratelimit")
]
rateLimitMiddleware = require("../../src/middleware/route-ratelimit")
routeRateLimit = rateLimitMiddleware.routeRateLimit
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
req.locals.proLimit = true
req.locals.apiLevel = 0
for (let i = 0; i < 5; i++) {
next.reset() // reset the stubbed next() function.
await routeRateLimit(req, res, next)
//console.log(`next() called: ${next.called}`)
}
//console.log(`req.locals after test: ${util.inspect(req.locals)}`)
// Note: next() will be called unless the rate-limit kicks in.
assert.equal(
next.called,
true,
`next should be called if rate limit was not triggered.`
)
})
it("should trigger rate-limit for free tier 10 RPM", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
req.locals.proLimit = true
req.locals.apiLevel = 0
for (let i = 0; i < 12; i++) {
next.reset() // reset the stubbed next() function.
await routeRateLimit(req, res, next)
@@ -95,11 +150,7 @@ describe("#route-ratelimits", () => {
req.method = "GET"
req.locals.proLimit = true
//console.log(`req.locals before test: ${util.inspect(req.locals)}`)
// Prepare the authorization header
//req.headers.authorization = generateAuthHeader("BITBOX")
req.locals.apiLevel = 10
for (let i = 0; i < 25; i++) {
next.reset() // reset the stubbed next() function.
@@ -131,13 +182,9 @@ describe("#route-ratelimits", () => {
req.method = "GET"
req.locals.proLimit = true
req.locals.apiLevel = 10
//console.log(`req.locals before test: ${util.inspect(req.locals)}`)
// Prepare the authorization header
//req.headers.authorization = generateAuthHeader("BITBOX")
for (let i = 0; i < 400; i++) {
for (let i = 0; i < 150; i++) {
next.reset() // reset the stubbed next() function.
await routeRateLimit(req, res, next)