RateLimiterMiddlewear.coffee 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738
  1. RateLimiter = require "../../infrastructure/RateLimiter"
  2. logger = require "logger-sharelatex"
  3. AuthenticationController = require('../Authentication/AuthenticationController')
  4. module.exports = RateLimiterMiddlewear =
  5. ###
  6. Do not allow more than opts.maxRequests from a single client in
  7. opts.timeInterval. Pass an array of opts.params to segment this based on
  8. parameters in the request URL, e.g.:
  9. app.get "/project/:project_id", RateLimiterMiddlewear.rateLimit(endpointName: "open-editor", params: ["project_id"])
  10. will rate limit each project_id separately.
  11. Unique clients are identified by user_id if logged in, and IP address if not.
  12. ###
  13. rateLimit: (opts) ->
  14. return (req, res, next) ->
  15. user_id = AuthenticationController.getLoggedInUserId(req) || req.ip
  16. params = (opts.params or []).map (p) -> req.params[p]
  17. params.push user_id
  18. if !opts.endpointName?
  19. throw new Error("no endpointName provided")
  20. options = {
  21. endpointName: opts.endpointName
  22. timeInterval: opts.timeInterval or 60
  23. subjectName: params.join(":")
  24. throttle: opts.maxRequests or 6
  25. }
  26. RateLimiter.addCount options, (error, canContinue)->
  27. return next(error) if error?
  28. if canContinue
  29. next()
  30. else
  31. logger.warn options, "rate limit exceeded"
  32. res.status(429) # Too many requests
  33. res.write("Rate limit reached, please try again later")
  34. res.end()