diff --git a/src/middleware/auth.js b/src/middleware/auth.js index 128e9ba..32fae28 100644 --- a/src/middleware/auth.js +++ b/src/middleware/auth.js @@ -22,7 +22,7 @@ 'use strict' const passport = require('passport') -const BasicStrategy = require('passport-http').BasicStrategy +// const BasicStrategy = require('passport-http').BasicStrategy const AnonymousStrategy = require('passport-anonymous') const wlogger = require('../util/winston-logging') @@ -48,55 +48,55 @@ class AuthMW { passport.use(new AnonymousStrategy()) // Initialize passport for 'basic' authentication. - passport.use( - new BasicStrategy({ passReqToCallback: true }, function ( - req, - username, - password, - done - ) { - // console.log(`req: ${util.inspect(req)}`) - // console.log(`username: ${username}`) - // console.log(`password: ${password}`) - - // Create the req.locals property if it does not yet exist. - if (!req.locals) { - req.locals = { - // default values - proLimit: false, - apiLevel: 0 - } - } - - // Set pro-tier rate limit to flag to false by default. - req.locals.proLimit = false - - // Evaluate the username and password and set the rate limit accordingly. - // if (username === "BITBOX" && password === PRO_PASS) { - if (username === 'BITBOX') { - for (let i = 0; i < PRO_PASS.length; i++) { - const thisPass = PRO_PASS[i] - - if (password === thisPass) { - wlogger.verbose(`${req.url} called by ${password.slice(0, 6)}`) - - // Success - req.locals.proLimit = true - break - } - } - } - - // console.log(`req.locals: ${util.inspect(req.locals)}`) - - return done(null, true) - }) - ) + // passport.use( + // new BasicStrategy({ passReqToCallback: true }, function ( + // req, + // username, + // password, + // done + // ) { + // // console.log(`req: ${util.inspect(req)}`) + // // console.log(`username: ${username}`) + // // console.log(`password: ${password}`) + // + // // Create the req.locals property if it does not yet exist. + // if (!req.locals) { + // req.locals = { + // // default values + // proLimit: false, + // apiLevel: 0 + // } + // } + // + // // Set pro-tier rate limit to flag to false by default. + // req.locals.proLimit = false + // + // // Evaluate the username and password and set the rate limit accordingly. + // // if (username === "BITBOX" && password === PRO_PASS) { + // if (username === 'BITBOX') { + // for (let i = 0; i < PRO_PASS.length; i++) { + // const thisPass = PRO_PASS[i] + // + // if (password === thisPass) { + // wlogger.verbose(`${req.url} called by ${password.slice(0, 6)}`) + // + // // Success + // req.locals.proLimit = true + // break + // } + // } + // } + // + // // console.log(`req.locals: ${util.inspect(req.locals)}`) + // + // return done(null, true) + // }) + // ) } // Middleware called by the route. mw () { - return passport.authenticate(['basic', 'anonymous'], { + return passport.authenticate(['anonymous'], { session: false }) } diff --git a/src/middleware/route-ratelimit.js b/src/middleware/route-ratelimit.js index a53b52d..2576500 100644 --- a/src/middleware/route-ratelimit.js +++ b/src/middleware/route-ratelimit.js @@ -20,7 +20,7 @@ const redisClient = new Redis(redisOptions) const { RateLimiterRedis } = require('rate-limiter-flexible') const rateLimitOptions = { storeClient: redisClient, - points: 100, // Number of points + points: 1000, // Number of points duration: 60 // Per minute (per 60 seconds) } @@ -98,8 +98,8 @@ class RateLimits { wlogger.debug('No JWT token found!') } - // Used for displaying error message. Default value is 3. - let rateLimit = 3 + // Used for displaying error message. Default value is 30. + let rateLimit = 30 // Code here for the rate limiter is adapted from this example: // https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#authorized-and-not-authorized-users @@ -131,7 +131,7 @@ class RateLimits { origin.toString().indexOf('sandbox.fullstack.cash') > -1 || origin === 'slp-api') ) { - pointsToConsume = 1 + pointsToConsume = 10 res.locals.pointsToConsume = pointsToConsume // Feedback for tests. } @@ -145,7 +145,7 @@ class RateLimits { `User ${key} consuming ${pointsToConsume} point for resource ${resource}.` ) - rateLimit = Math.floor(100 / pointsToConsume) + rateLimit = Math.floor(1000 / pointsToConsume) // Update the key so that rate limits track both the user and the resource. key = `${key}-${resource}` @@ -175,7 +175,7 @@ class RateLimits { // Calculates the points consumed, based on the jwt information and the route // requested. calcPoints (jwtInfo) { - let retVal = 30 // By default, use anonymous tier. + let retVal = 300 // By default, use anonymous tier. try { // console.log(`jwtInfo: ${JSON.stringify(jwtInfo, null, 2)}`) @@ -194,20 +194,20 @@ class RateLimits { if (level40Routes.includes(resource)) { if (apiLevel >= 40) retVal = 1 // else if (apiLevel >= 10) retVal = 10 - else retVal = 10 + else retVal = 100 // Normal indexer routes } else if (level30Routes.includes(resource)) { if (apiLevel >= 30) retVal = 1 - else retVal = 10 + else retVal = 100 // Full node tier } else if (apiLevel >= 20) { - retVal = 1 + retVal = 10 // Free tier, full node only. } else { - retVal = 10 + retVal = 100 } } @@ -215,7 +215,7 @@ class RateLimits { } catch (err) { wlogger.error('Error in route-ratelimit.js/calcPoints()') // throw err - retVal = 30 + retVal = 300 } return retVal diff --git a/test/v3/integration/rate-limits.js b/test/v3/integration/rate-limits.js index c26790b..cb4c65f 100644 --- a/test/v3/integration/rate-limits.js +++ b/test/v3/integration/rate-limits.js @@ -16,9 +16,10 @@ util.inspect.defaultOptions = { depth: 1 } // const SERVER = `http://192.168.0.36:12400/v3/` const SERVER = 'http://localhost:3000/v3/' +// const SERVER = 'https://api.fullstack.cash/v3/' const TEST_JWT = - 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlM2EwNDE1ZWIyOWE5NjJkYTI3MDhiNCIsImFwaUxldmVsIjowLCJyYXRlTGltaXQiOjEwLCJpYXQiOjE1ODA4NjA0NjcsImV4cCI6MTU4MzQ1MjQ2N30.fuY5S-YrF0J11h5uyMjPe7wiVkYRnIyXi4dL9-V-C6pLJm33p0dSq_pSheVVWw78n5kAvL_9kFHngbnmQiOJYQ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMDYyODk1MSwiZXhwIjoxNjAzMjIwOTUxfQ.JPXDJQsxJFtCGZjHOd-hRfJuY41Ef_FQ4ET06CtYdNk' describe('#rate limits', () => { it('should get control/getNetworkInfo() with no auth', async () => { @@ -35,7 +36,7 @@ describe('#rate limits', () => { assert.hasAnyKeys(result.data, ['version']) }) - it('should trigger rate-limit handler if rate limits exceeds 30 request per minute', async () => { + it('should trigger rate-limit handler if rate limits exceeds 5 request per minute', async () => { try { // Actual rate limit is 60 per minute X 4 nodes = 240 rpm. const options = { @@ -44,7 +45,7 @@ describe('#rate limits', () => { } const promises = [] - for (let i = 0; i < 30; i++) { + for (let i = 0; i < 5; i++) { const promise = axios(options) promises.push(promise) } @@ -60,79 +61,79 @@ describe('#rate limits', () => { } }) - it('should not trigger rate-limit handler if correct pro-tier password is used', async () => { - try { - const username = 'BITBOX' + // it('should not trigger rate-limit handler if correct pro-tier password is used', async () => { + // try { + // const username = 'BITBOX' + // + // // Pro-tier is accessed by using the right password. + // const password = 'BITBOX' + // // const password = "something" + // + // const combined = `${username}:${password}` + // const base64Credential = Buffer.from(combined).toString('base64') + // const readyCredential = `Basic ${base64Credential}` + // + // const options = { + // method: 'GET', + // url: `${SERVER}control/getNetworkInfo`, + // headers: { Authorization: readyCredential } + // } + // + // const promises = [] + // for (let i = 0; i < 30; i++) { + // const promise = axios(options) + // promises.push(promise) + // } + // + // await Promise.all(promises) + // + // assert.equal(true, true, 'Not throwing an error is a pass!') + // } catch (err) { + // // console.log(`err.response: ${util.inspect(err.response)}`) + // + // assert.equal( + // true, + // false, + // 'This error handler should not have been triggered. Is the password correct?' + // ) + // } + // }) - // Pro-tier is accessed by using the right password. - const password = 'BITBOX' - // const password = "something" - - const combined = `${username}:${password}` - const base64Credential = Buffer.from(combined).toString('base64') - const readyCredential = `Basic ${base64Credential}` - - const options = { - method: 'GET', - url: `${SERVER}control/getNetworkInfo`, - headers: { Authorization: readyCredential } - } - - const promises = [] - for (let i = 0; i < 30; i++) { - const promise = axios(options) - promises.push(promise) - } - - await Promise.all(promises) - - assert.equal(true, true, 'Not throwing an error is a pass!') - } catch (err) { - // console.log(`err.response: ${util.inspect(err.response)}`) - - assert.equal( - true, - false, - 'This error handler should not have been triggered. Is the password correct?' - ) - } - }) - - it('should trigger rate-limit handler if rate limits exceeds pro-tier limit', async () => { - try { - const username = 'BITBOX' - - // Pro-tier is accessed by using the right password. - const password = 'BITBOX' - // const password = "something" - - const combined = `${username}:${password}` - const base64Credential = Buffer.from(combined).toString('base64') - const readyCredential = `Basic ${base64Credential}` - - // Actual rate limit is 60 per minute X 4 nodes = 240 rpm. - const options = { - method: 'GET', - url: `${SERVER}control/getNetworkInfo`, - headers: { Authorization: readyCredential } - } - - const promises = [] - for (let i = 0; i < 80; i++) { - const promise = axios(options) - promises.push(promise) - } - - await Promise.all(promises) - - assert.equal(true, false, 'Unexpected result!') - } catch (err) { - // console.log(`err.response: ${util.inspect(err.response)}`) - - assert.equal(err.response.status, 429) - assert.include(err.response.data.error, 'Too many requests') - } - }) + // it('should trigger rate-limit handler if rate limits exceeds pro-tier limit', async () => { + // try { + // const username = 'BITBOX' + // + // // Pro-tier is accessed by using the right password. + // const password = 'BITBOX' + // // const password = "something" + // + // const combined = `${username}:${password}` + // const base64Credential = Buffer.from(combined).toString('base64') + // const readyCredential = `Basic ${base64Credential}` + // + // // Actual rate limit is 60 per minute X 4 nodes = 240 rpm. + // const options = { + // method: 'GET', + // url: `${SERVER}control/getNetworkInfo`, + // headers: { Authorization: readyCredential } + // } + // + // const promises = [] + // for (let i = 0; i < 80; i++) { + // const promise = axios(options) + // promises.push(promise) + // } + // + // await Promise.all(promises) + // + // assert.equal(true, false, 'Unexpected result!') + // } catch (err) { + // // console.log(`err.response: ${util.inspect(err.response)}`) + // + // assert.equal(err.response.status, 429) + // assert.include(err.response.data.error, 'Too many requests') + // } + // }) it('should unlock pro-tier for a valid JWT token', async () => { try {