mirror of
https://github.com/fullstack-cash/bch-api.git
synced 2026-09-21 16:52:04 -07:00
fix(local rate limits): Skipping basic auth and rate limits with an env var
This commit is contained in:
+10
-1
@@ -96,17 +96,26 @@ app.use('/', logReqInfo)
|
||||
|
||||
const v4prefix = 'v4'
|
||||
|
||||
// START Rate Limits
|
||||
// Allow users to turn off rate limits with an environment variable.
|
||||
const USE_RATE_LIMITS = process.env.USE_RATE_LIMITS
|
||||
? process.env.USE_RATE_LIMITS
|
||||
: true
|
||||
const auth = new AuthMW()
|
||||
|
||||
if (USE_RATE_LIMITS) {
|
||||
// Inspect the header for a JWT token.
|
||||
app.use(`/${v4prefix}/`, jwtAuth.getTokenFromHeaders)
|
||||
|
||||
// Instantiate the authorization middleware, used to implement pro-tier rate limiting.
|
||||
// Handles Anonymous and Basic Authorization schemes used by passport.js
|
||||
const auth = new AuthMW()
|
||||
app.use(`/${v4prefix}/`, auth.mw())
|
||||
|
||||
// Rate limit on all v4 routes
|
||||
// Establish and enforce rate limits.
|
||||
app.use(`/${v4prefix}/`, rateLimits.rateLimitByResource)
|
||||
}
|
||||
// END Rate Limits
|
||||
|
||||
// Connect v4 routes
|
||||
app.use(`/${v4prefix}/` + 'health-check', healthCheckV4)
|
||||
|
||||
+12
-8
@@ -1,22 +1,25 @@
|
||||
/*
|
||||
CT 2/4/20 Note: This library handles anonymous and Basic auth. This library
|
||||
can be phased out with the chage to JWT tokens and the new rate-limit library.
|
||||
|
||||
Handle authorization for bypassing rate limits.
|
||||
This library handles anonymous and Basic Authentication.
|
||||
|
||||
1) Default is 'Anonymous Authentication', which unlocks the freemimum tier by
|
||||
default.
|
||||
|
||||
2) Hard-coded 'Basic Authentication' is a token that does not expire and is
|
||||
provided to buisiness partners.
|
||||
provided for clients who run their own isolated infrastructure without rate
|
||||
limits, but still need a way from preventing the random public from using
|
||||
their API.
|
||||
|
||||
3) JWT-based 'Local Authentication' is used for normal users that pay to
|
||||
access the premium pro-tier services.
|
||||
|
||||
This file uses the passport npm library to check the header of each REST API
|
||||
call for the prescence of a Basic authorization header:
|
||||
call for the prescence of a Basic Authentication header:
|
||||
https://en.wikipedia.org/wiki/Basic_access_authentication
|
||||
|
||||
If the header is found and validated, the req.locals.proLimit Boolean value
|
||||
is set and passed to the route-ratelimits.ts middleware.
|
||||
is set and passed to the route-ratelimit.js middleware. route-ratelimit.js
|
||||
is for fine-grain JWT-based rate limits. If req.locals.proLimit is set to
|
||||
true, then those rate limits will be skipped.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
@@ -76,8 +79,9 @@ class AuthMW {
|
||||
req.locals.proLimit = false
|
||||
|
||||
// Evaluate the username and password and set the rate limit accordingly.
|
||||
// if (username === "BITBOX" && password === PRO_PASS) {
|
||||
if (username === 'fullstackcash') {
|
||||
// Can set several different passwords in the environment variable.
|
||||
// Loop through each one to see if one matches.
|
||||
for (let i = 0; i < PRO_PASS.length; i++) {
|
||||
const thisPass = PRO_PASS[i]
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
This file will replace the original rate-limit.js file.
|
||||
|
||||
Sets the rate limits for the anonymous and paid tiers. Current rate limits:
|
||||
- 1000 points in 60 seconds
|
||||
- 10 points per call for paid tier (100 RPM)
|
||||
- 50 points per call for anonymous tier (20 RPM)
|
||||
|
||||
The rate limit handling is designed for these four use cases:
|
||||
- Users who want to buy a JWT token for 24 hour access.
|
||||
- Users who want to buy different RPM tiers: 100, 250, 600
|
||||
- Basic Authentication which should not have any rate limits applied.
|
||||
|
||||
The Basci Auth use cases is considered when determining internal rate limits.
|
||||
The internal rate limits should not be applied to calls from those users.
|
||||
|
||||
A lot of attention has been paid to passing rate-limit information for the user
|
||||
when they trigger an endpoint that makes a lot of internal API calls. Examples
|
||||
are hydrateUtxos() and getPublicKey().
|
||||
*/
|
||||
|
||||
// Public npm libraries.
|
||||
const jwt = require('jsonwebtoken')
|
||||
const Redis = require('ioredis')
|
||||
const { RateLimiterRedis } = require('rate-limiter-flexible')
|
||||
|
||||
// local libraries.
|
||||
// const wlogger = require('../util/winston-logging')
|
||||
const config = require('../../config')
|
||||
|
||||
// let _this // Global pointer to instance of class, when 'this' context is lost.
|
||||
|
||||
// Setup Redis to track rate limits for each user.
|
||||
const redisOptions = {
|
||||
enableOfflineQueue: false,
|
||||
port: process.env.REDIS_PORT ? process.env.REDIS_PORT : 6379,
|
||||
host: process.env.REDIS_HOST ? process.env.REDIS_HOST : '127.0.0.1'
|
||||
}
|
||||
console.log(`redisOptions: ${JSON.stringify(redisOptions, null, 2)}`)
|
||||
const redisClient = new Redis(redisOptions)
|
||||
const rateLimitOptions = {
|
||||
storeClient: redisClient,
|
||||
points: 1000, // Number of points
|
||||
duration: 60 // Per minute (per 60 seconds)
|
||||
}
|
||||
|
||||
// Constants
|
||||
// const ANON_LIMITS = config.anonRateLimit
|
||||
// const WHITELIST_RATE_LIMIT = config.whitelistRateLimit
|
||||
// const WHITELIST_DOMAINS = config.whitelistDomains
|
||||
// const INTERNAL_RATE_LIMIT = 1
|
||||
|
||||
class RateLimits {
|
||||
constructor () {
|
||||
// _this = this
|
||||
|
||||
this.jwt = jwt
|
||||
this.rateLimiter = new RateLimiterRedis(rateLimitOptions)
|
||||
this.config = config
|
||||
}
|
||||
|
||||
// This is the main middleware funciton of this library. All other functions
|
||||
// support this function.
|
||||
async applyRateLimits (req, res, next) {
|
||||
try {
|
||||
// let userId
|
||||
// let decoded = {}
|
||||
|
||||
// Create a re*Q*.locals object if not passed in.
|
||||
// req.locals.proLimit will be true if the user is using Basic Authentication.
|
||||
if (!req.locals) {
|
||||
req.locals = {
|
||||
// default values
|
||||
jwtToken: '',
|
||||
proLimit: false,
|
||||
apiLevel: 0
|
||||
}
|
||||
}
|
||||
|
||||
// Create a re*S*.locals object if it does not exist.
|
||||
if (!res.locals) {
|
||||
res.locals = {
|
||||
rateLimitTriggered: false
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Used to disconnect from the Redis DB.
|
||||
// Called by unit tests so that node.js thread doesn't live forever.
|
||||
closeRedis () {
|
||||
redisClient.disconnect()
|
||||
}
|
||||
|
||||
// Clear the redis database. Used by unit tests.
|
||||
async wipeRedis () {
|
||||
await redisClient.flushdb()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RateLimits
|
||||
Reference in New Issue
Block a user