added rate limiting to password reset endpoint

This commit is contained in:
Henry Oswald 2014-05-16 10:31:33 +01:00
parent ca1539cac0
commit bf1bb22afd
2 changed files with 31 additions and 9 deletions

View file

@ -1,4 +1,6 @@
PasswordResetHandler = require("./PasswordResetHandler") PasswordResetHandler = require("./PasswordResetHandler")
RateLimiter = require("../../infrastructure/RateLimiter")
module.exports = module.exports =
@ -8,11 +10,19 @@ module.exports =
requestReset: (req, res)-> requestReset: (req, res)->
email = req.body.email.trim() email = req.body.email.trim()
PasswordResetHandler.generateAndEmailResetToken email, (err)-> opts =
if err? endpointName:"auto_compile"
res.send 500 timeInterval:60
else subjectName:email
res.send 200 throttle: 3
RateLimiter.addCount opts, (err, canCompile)->
if !canCompile
return res.send 500
PasswordResetHandler.generateAndEmailResetToken email, (err)->
if err?
res.send 500
else
res.send 200
renderSetPasswordForm: (req, res)-> renderSetPasswordForm: (req, res)->
res.render "user/setPassword", res.render "user/setPassword",

View file

@ -14,10 +14,13 @@ describe "PasswordResetController", ->
@PasswordResetHandler = @PasswordResetHandler =
generateAndEmailResetToken:sinon.stub() generateAndEmailResetToken:sinon.stub()
setNewUserPassword:sinon.stub() setNewUserPassword:sinon.stub()
@RateLimiter =
addCount: sinon.stub()
@PasswordResetController = SandboxedModule.require modulePath, requires: @PasswordResetController = SandboxedModule.require modulePath, requires:
"settings-sharelatex":@settings "settings-sharelatex":@settings
"./PasswordResetHandler":@PasswordResetHandler "./PasswordResetHandler":@PasswordResetHandler
"logger-sharelatex": log:-> "logger-sharelatex": log:->
"../../infrastructure/RateLimiter":@RateLimiter
@email = "bob@bob.com " @email = "bob@bob.com "
@token = "my security token that was emailed to me" @token = "my security token that was emailed to me"
@ -28,12 +31,23 @@ describe "PasswordResetController", ->
passwordResetToken:@token passwordResetToken:@token
password:@password password:@password
@res ={} @res = {}
describe "requestReset", -> describe "requestReset", ->
it "should error if the rate limit is hit", (done)->
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1)
@RateLimiter.addCount.callsArgWith(1, null, false)
@res.send = (code)=>
code.should.equal 500
@PasswordResetHandler.generateAndEmailResetToken.calledWith(@email.trim()).should.equal false
done()
@PasswordResetController.requestReset @req, @res
it "should tell the handler to process that email", (done)-> it "should tell the handler to process that email", (done)->
@RateLimiter.addCount.callsArgWith(1, null, true)
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1) @PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1)
@res.send = (code)=> @res.send = (code)=>
code.should.equal 200 code.should.equal 200
@ -41,8 +55,8 @@ describe "PasswordResetController", ->
done() done()
@PasswordResetController.requestReset @req, @res @PasswordResetController.requestReset @req, @res
it "should send a 500 if there is an error", (done)-> it "should send a 500 if there is an error", (done)->
@RateLimiter.addCount.callsArgWith(1, null, true)
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, "error") @PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, "error")
@res.send = (code)=> @res.send = (code)=>
code.should.equal 500 code.should.equal 500
@ -75,8 +89,6 @@ describe "PasswordResetController", ->
done() done()
@PasswordResetController.setNewUserPassword @req, @res @PasswordResetController.setNewUserPassword @req, @res
it "should error if there is no password", (done)-> it "should error if there is no password", (done)->
@req.body.passwordResetToken = "" @req.body.passwordResetToken = ""
@PasswordResetHandler.setNewUserPassword.callsArgWith(2) @PasswordResetHandler.setNewUserPassword.callsArgWith(2)