diff --git a/config/index.js b/config/index.js index 542ffb1..00bb0ca 100644 --- a/config/index.js +++ b/config/index.js @@ -1,11 +1,22 @@ /* Common configuration settings. + Default settings in this file can be overridden by an environment variable. */ const config = { + // This is the same secret used by jwt-bch-api apiTokenSecret: process.env.TOKENSECRET ? process.env.TOKENSECRET - : 'secret-jwt-token' + : 'secret-jwt-token', + + // Rate Limits + anonRateLimit: process.env.ANON_RATE_LIMIT ? process.env.ANON_RATE_LIMIT : 50, + whitelistRateLimit: process.env.WHITELIST_RATE_LIMIT + ? process.env.WHITELIST_RATE_LIMIT + : 10, + whitelistDomains: process.env.WHITELIST_DOMAINS + ? process.env.WHITELIST_DOMAINS.split(',') + : ['fullstack.cash', 'psfoundation.cash'] } module.exports = config diff --git a/package.json b/package.json index 3afd381..0597122 100644 --- a/package.json +++ b/package.json @@ -17,12 +17,13 @@ "test": "npm run lint && npm run test-v4", "lint": "standard --env mocha --fix", "test-v4": "export NETWORK=mainnet && nyc --reporter=text mocha --timeout 60000 test/v4/", - "test:temp": "export NETWORK=mainnet && export TEST=integration && mocha --timeout 25000 test/v4/integration/price.js", "test:integration": "mocha test/v4/integration", "test:integration:slpdb": "mocha --timeout 25000 -g '#validate2Single' test/v4/integration/slp*.js", "coverage": "nyc report --reporter=text-lcov | coveralls", "coverage:report": "export NETWORK=mainnet && nyc --reporter=html mocha --timeout 25000 test/v4/", - "docs": "./node_modules/.bin/apidoc -i src/routes/v4 -o docs" + "docs": "./node_modules/.bin/apidoc -i src/routes/v4 -o docs", + "test:temp1": "export NETWORK=mainnet && export TEST=integration && mocha --timeout 25000 test/v4/integration/price.js", + "test:temp2": "mocha test/v4/rate-limits.js" }, "engines": { "node": ">=10.15.1" diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js index cce93d0..a89ee2c 100644 --- a/src/middleware/route-ratelimit.js +++ b/src/middleware/route-ratelimit.js @@ -12,12 +12,17 @@ 'use strict' +// Public npm libraries. const jwt = require('jsonwebtoken') +// local libraries. const wlogger = require('../util/winston-logging') const config = require('../../config') -const ANON_LIMITS = 50 +const ANON_LIMITS = config.anonRateLimit +const WHITELIST_RATE_LIMIT = config.whitelistRateLimit +const WHITELIST_DOMAINS = config.whitelistDomains +const INTERNAL_RATE_LIMIT = 1 // Redis const redisOptions = { @@ -144,13 +149,10 @@ class RateLimits { // If the request originates from one of the approved wallet apps, then // apply paid-access rate limits. - if ( - origin && - (origin.toString().indexOf('fullstack.cash') > -1 || - origin.toString().indexOf('splitbch.com') > -1 || - origin.toString().indexOf('slp-api') > -1) - ) { - pointsToConsume = 10 + // console.log(`origin: ${JSON.stringify(origin, null, 2)}`) + // console.log(`whitelist: ${JSON.stringify(WHITELIST_DOMAINS, null, 2)}`) + if (this.isInWhitelist(origin)) { + pointsToConsume = WHITELIST_RATE_LIMIT res.locals.pointsToConsume = pointsToConsume // Feedback for tests. } @@ -161,7 +163,7 @@ class RateLimits { // Do not comment out this line. key.toString().indexOf('172.17.') > -1 ) { - pointsToConsume = 1 + pointsToConsume = INTERNAL_RATE_LIMIT res.locals.pointsToConsume = pointsToConsume // Feedback for tests. } @@ -263,6 +265,31 @@ class RateLimits { throw err } } + + // Returns a boolean if the origin of the request matches a domain in the + // whitelist. + isInWhitelist (origin) { + try { + const retVal = false // Default value. + + if (!origin) return false + + // console.log(`WHITELIST_DOMAINS: ${JSON.stringify(WHITELIST_DOMAINS, null, 2)}`) + + for (let i = 0; i < WHITELIST_DOMAINS.length; i++) { + const thisDomain = WHITELIST_DOMAINS[i] + + if (origin.toString().indexOf(thisDomain) > -1) { + return true + } + } + + return retVal + } catch (err) { + wlogger.error('Error in route-ratelimit.js/isInWhitelist(). Returning false by default.') + return false + } + } } module.exports = RateLimits diff --git a/test/v4/rate-limits.js b/test/v4/rate-limits.js index 5dd61ff..6ebaeee 100644 --- a/test/v4/rate-limits.js +++ b/test/v4/rate-limits.js @@ -445,6 +445,30 @@ describe('#route-ratelimits & jwt-auth', () => { assert.equal(res.locals.pointsToConsume, 50) }) }) + + describe('#isInWhitelist', () => { + it('should return false when no argument is passed in', () => { + const result = rateLimits.isInWhitelist() + + assert.equal(result, false) + }) + + it('should return false when origin is not in the whitelist', () => { + const origin = 'blah.com' + + const result = rateLimits.isInWhitelist(origin) + + assert.equal(result, false) + }) + + it('should return true when origin is in the whitelist', () => { + const origin = 'message.fullstack.cash' + + const result = rateLimits.isInWhitelist(origin) + + assert.equal(result, true) + }) + }) }) // Generates a Basic authorization header.