apiLimitsMiddleware.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. var config = (process.env.IS_TEST) ? require('../../../test/fixtures/settings.json') : require('../../../server_config/settings.json');
  2. var debug = require('debug')('apiLimitsMiddleware');
  3. var apiLimitsMiddleware = function(req, res, next) {
  4. 'use strict';
  5. var ipAddress = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  6. debug('Entering API Limits Middleware with IP address %s', ipAddress);
  7. if (req.path.indexOf('/api/') === 0 && !res.locals.hasApiKey) {
  8. // Monitoring requests
  9. if (req.path === '/api/runs' && req.method === 'GET') {
  10. next();
  11. return;
  12. }
  13. // New tests
  14. if (req.path === '/api/runs' && req.method === 'POST') {
  15. if (!runsTable.accepts(ipAddress)) {
  16. // Sorry :/
  17. debug('Too many tests launched from IP address %s', ipAddress);
  18. res.status(429).send('Too many requests');
  19. return;
  20. }
  21. }
  22. // Every other calls
  23. if (!callsTable.accepts(ipAddress)) {
  24. // Sorry :/
  25. debug('Too many API requests from IP address %s', ipAddress);
  26. res.status(429).send('Too many requests');
  27. return;
  28. }
  29. debug('Not blocked by the API limits');
  30. // It's ok for the moment
  31. }
  32. next();
  33. };
  34. var RecordTable = function(maxPerDay) {
  35. var table = {};
  36. // Check if the user overpassed the limit and save its visit
  37. this.accepts = function(ipAddress) {
  38. if (table[ipAddress]) {
  39. this.cleanEntry(ipAddress);
  40. debug('%d visits in the last 24 hours', table[ipAddress].length);
  41. if (table[ipAddress].length >= maxPerDay) {
  42. return false;
  43. } else {
  44. table[ipAddress].push(Date.now());
  45. }
  46. } else {
  47. table[ipAddress] = [];
  48. table[ipAddress].push(Date.now());
  49. }
  50. return true;
  51. };
  52. // Clean the table for this guy
  53. this.cleanEntry = function(ipAddress) {
  54. table[ipAddress] = table[ipAddress].filter(function(date) {
  55. return date > Date.now() - 1000*60*60*24;
  56. });
  57. };
  58. // Clean the entire table once in a while
  59. this.removeOld = function() {
  60. for (var ipAddress in table) {
  61. this.cleanEntry(ipAddress);
  62. }
  63. };
  64. };
  65. // Init the records tables
  66. var runsTable = new RecordTable(config.maxAnonymousRunsPerDay);
  67. var callsTable = new RecordTable(config.maxAnonymousCallsPerDay);
  68. module.exports = apiLimitsMiddleware;