RateLimiterMiddlewearTests.coffee 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. SandboxedModule = require('sandboxed-module')
  2. sinon = require('sinon')
  3. require('chai').should()
  4. modulePath = require('path').join __dirname, '../../../../app/js/Features/Security/RateLimiterMiddlewear'
  5. describe "RateLimiterMiddlewear", ->
  6. beforeEach ->
  7. @AuthenticationController =
  8. getLoggedInUserId: () =>
  9. @req?.session?.user?._id
  10. @RateLimiterMiddlewear = SandboxedModule.require modulePath, requires:
  11. '../../infrastructure/RateLimiter' : @RateLimiter = {}
  12. "logger-sharelatex": @logger = {warn: sinon.stub()}
  13. '../Authentication/AuthenticationController': @AuthenticationController
  14. @req =
  15. params: {}
  16. @res =
  17. status: sinon.stub()
  18. write: sinon.stub()
  19. end: sinon.stub()
  20. @next = sinon.stub()
  21. describe "rateLimit", ->
  22. beforeEach ->
  23. @rateLimiter = @RateLimiterMiddlewear.rateLimit({
  24. endpointName: "test-endpoint"
  25. params: ["project_id", "doc_id"]
  26. timeInterval: 42
  27. maxRequests: 12
  28. })
  29. @req.params = {
  30. project_id: @project_id = "project-id"
  31. doc_id: @doc_id = "doc-id"
  32. }
  33. describe "when there is no session", ->
  34. beforeEach ->
  35. @RateLimiter.addCount = sinon.stub().callsArgWith(1, null, true)
  36. @req.ip = @ip = "1.2.3.4"
  37. @rateLimiter(@req, @res, @next)
  38. it "should call the rate limiter backend with the ip address", ->
  39. @RateLimiter.addCount
  40. .calledWith({
  41. endpointName: "test-endpoint"
  42. timeInterval: 42
  43. throttle: 12
  44. subjectName: "#{@project_id}:#{@doc_id}:#{@ip}"
  45. })
  46. .should.equal true
  47. it "should pass on to next()", ->
  48. describe "when under the rate limit with logged in user", ->
  49. beforeEach ->
  50. @req.session =
  51. user :
  52. _id: @user_id = "user-id"
  53. @RateLimiter.addCount = sinon.stub().callsArgWith(1, null, true)
  54. @rateLimiter(@req, @res, @next)
  55. it "should call the rate limiter backend with the user_id", ->
  56. @RateLimiter.addCount
  57. .calledWith({
  58. endpointName: "test-endpoint"
  59. timeInterval: 42
  60. throttle: 12
  61. subjectName: "#{@project_id}:#{@doc_id}:#{@user_id}"
  62. })
  63. .should.equal true
  64. it "should pass on to next()", ->
  65. @next.called.should.equal true
  66. describe "when under the rate limit with anonymous user", ->
  67. beforeEach ->
  68. @req.ip = @ip = "1.2.3.4"
  69. @RateLimiter.addCount = sinon.stub().callsArgWith(1, null, true)
  70. @rateLimiter(@req, @res, @next)
  71. it "should call the rate limiter backend with the ip address", ->
  72. @RateLimiter.addCount
  73. .calledWith({
  74. endpointName: "test-endpoint"
  75. timeInterval: 42
  76. throttle: 12
  77. subjectName: "#{@project_id}:#{@doc_id}:#{@ip}"
  78. })
  79. .should.equal true
  80. it "should pass on to next()", ->
  81. @next.called.should.equal true
  82. describe "when over the rate limit", ->
  83. beforeEach ->
  84. @req.session =
  85. user :
  86. _id: @user_id = "user-id"
  87. @RateLimiter.addCount = sinon.stub().callsArgWith(1, null, false)
  88. @rateLimiter(@req, @res, @next)
  89. it "should return a 429", ->
  90. @res.status.calledWith(429).should.equal true
  91. @res.end.called.should.equal true
  92. it "should not continue", ->
  93. @next.called.should.equal false
  94. it "should log a warning", ->
  95. @logger.warn
  96. .calledWith({
  97. endpointName: "test-endpoint"
  98. timeInterval: 42
  99. throttle: 12
  100. subjectName: "#{@project_id}:#{@doc_id}:#{@user_id}"
  101. }, "rate limit exceeded")
  102. .should.equal true