2014-05-15 11:20:23 -04:00
|
|
|
should = require('chai').should()
|
2015-12-11 06:30:06 -05:00
|
|
|
expect = require("chai").expect
|
2014-05-15 11:20:23 -04:00
|
|
|
SandboxedModule = require('sandboxed-module')
|
|
|
|
assert = require('assert')
|
|
|
|
path = require('path')
|
|
|
|
sinon = require('sinon')
|
|
|
|
modulePath = path.join __dirname, "../../../../app/js/Features/PasswordReset/PasswordResetController"
|
|
|
|
expect = require("chai").expect
|
|
|
|
|
|
|
|
describe "PasswordResetController", ->
|
|
|
|
|
|
|
|
beforeEach ->
|
|
|
|
|
|
|
|
@settings = {}
|
2014-05-15 11:50:38 -04:00
|
|
|
@PasswordResetHandler =
|
|
|
|
generateAndEmailResetToken:sinon.stub()
|
|
|
|
setNewUserPassword:sinon.stub()
|
2015-08-24 06:53:33 -04:00
|
|
|
@RateLimiter =
|
2014-05-16 05:31:33 -04:00
|
|
|
addCount: sinon.stub()
|
2016-07-05 09:19:59 -04:00
|
|
|
@UserSessionsManager =
|
|
|
|
revokeAllUserSessions: sinon.stub().callsArgWith(2, null)
|
2014-05-15 11:20:23 -04:00
|
|
|
@PasswordResetController = SandboxedModule.require modulePath, requires:
|
|
|
|
"settings-sharelatex":@settings
|
2014-05-15 11:50:38 -04:00
|
|
|
"./PasswordResetHandler":@PasswordResetHandler
|
2014-05-15 11:20:23 -04:00
|
|
|
"logger-sharelatex": log:->
|
2014-05-16 05:31:33 -04:00
|
|
|
"../../infrastructure/RateLimiter":@RateLimiter
|
2015-12-11 06:30:06 -05:00
|
|
|
"../Authentication/AuthenticationController": @AuthenticationController = {}
|
|
|
|
"../User/UserGetter": @UserGetter = {}
|
2016-07-05 09:19:59 -04:00
|
|
|
"../User/UserSessionsManager": @UserSessionsManager
|
2014-05-15 11:20:23 -04:00
|
|
|
|
2014-05-15 11:50:38 -04:00
|
|
|
@email = "bob@bob.com "
|
|
|
|
@token = "my security token that was emailed to me"
|
|
|
|
@password = "my new password"
|
|
|
|
@req =
|
|
|
|
body:
|
|
|
|
email:@email
|
2014-05-15 12:16:20 -04:00
|
|
|
passwordResetToken:@token
|
2014-05-15 11:50:38 -04:00
|
|
|
password:@password
|
2014-08-01 09:03:38 -04:00
|
|
|
i18n:
|
|
|
|
translate:->
|
2015-08-24 06:53:33 -04:00
|
|
|
session: {}
|
|
|
|
query: {}
|
2014-05-15 11:20:23 -04:00
|
|
|
|
2014-05-16 05:31:33 -04:00
|
|
|
@res = {}
|
2014-05-15 11:20:23 -04:00
|
|
|
|
|
|
|
|
2014-05-15 11:50:38 -04:00
|
|
|
describe "requestReset", ->
|
2014-05-15 11:20:23 -04:00
|
|
|
|
2014-05-16 05:31:33 -04:00
|
|
|
it "should error if the rate limit is hit", (done)->
|
2014-08-08 06:41:54 -04:00
|
|
|
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
|
2014-05-16 05:31:33 -04:00
|
|
|
@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
|
|
|
|
|
|
|
|
|
2014-05-15 11:50:38 -04:00
|
|
|
it "should tell the handler to process that email", (done)->
|
2014-05-16 05:31:33 -04:00
|
|
|
@RateLimiter.addCount.callsArgWith(1, null, true)
|
2014-08-08 06:41:54 -04:00
|
|
|
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
|
2015-07-08 11:56:38 -04:00
|
|
|
@res.sendStatus = (code)=>
|
2014-05-15 11:50:38 -04:00
|
|
|
code.should.equal 200
|
|
|
|
@PasswordResetHandler.generateAndEmailResetToken.calledWith(@email.trim()).should.equal true
|
|
|
|
done()
|
|
|
|
@PasswordResetController.requestReset @req, @res
|
2014-05-15 11:20:23 -04:00
|
|
|
|
2014-05-15 11:50:38 -04:00
|
|
|
it "should send a 500 if there is an error", (done)->
|
2014-05-16 05:31:33 -04:00
|
|
|
@RateLimiter.addCount.callsArgWith(1, null, true)
|
2014-05-15 11:50:38 -04:00
|
|
|
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, "error")
|
|
|
|
@res.send = (code)=>
|
|
|
|
code.should.equal 500
|
|
|
|
done()
|
|
|
|
@PasswordResetController.requestReset @req, @res
|
|
|
|
|
2014-08-08 06:41:54 -04:00
|
|
|
it "should send a 404 if the email doesn't exist", (done)->
|
|
|
|
@RateLimiter.addCount.callsArgWith(1, null, true)
|
|
|
|
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, false)
|
|
|
|
@res.send = (code)=>
|
|
|
|
code.should.equal 404
|
|
|
|
done()
|
|
|
|
@PasswordResetController.requestReset @req, @res
|
|
|
|
|
2014-06-10 12:54:29 -04:00
|
|
|
it "should lowercase the email address", (done)->
|
|
|
|
@email = "UPerCaseEMAIL@example.Com"
|
|
|
|
@req.body.email = @email
|
|
|
|
@RateLimiter.addCount.callsArgWith(1, null, true)
|
2014-08-08 06:41:54 -04:00
|
|
|
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
|
2015-07-08 11:56:38 -04:00
|
|
|
@res.sendStatus = (code)=>
|
2014-06-10 12:54:29 -04:00
|
|
|
code.should.equal 200
|
|
|
|
@PasswordResetHandler.generateAndEmailResetToken.calledWith(@email.toLowerCase()).should.equal true
|
|
|
|
done()
|
|
|
|
@PasswordResetController.requestReset @req, @res
|
|
|
|
|
2014-05-15 11:50:38 -04:00
|
|
|
describe "setNewUserPassword", ->
|
|
|
|
|
2015-08-24 06:53:33 -04:00
|
|
|
beforeEach ->
|
|
|
|
@req.session.resetToken = @token
|
|
|
|
|
2014-05-15 11:50:38 -04:00
|
|
|
it "should tell the user handler to reset the password", (done)->
|
2014-10-08 12:18:24 -04:00
|
|
|
@PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, true)
|
2015-07-08 11:56:38 -04:00
|
|
|
@res.sendStatus = (code)=>
|
2014-05-15 11:50:38 -04:00
|
|
|
code.should.equal 200
|
|
|
|
@PasswordResetHandler.setNewUserPassword.calledWith(@token, @password).should.equal true
|
|
|
|
done()
|
|
|
|
@PasswordResetController.setNewUserPassword @req, @res
|
|
|
|
|
2014-10-08 12:18:24 -04:00
|
|
|
it "should send 404 if the token didn't work", (done)->
|
|
|
|
@PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, false)
|
2015-12-11 06:30:06 -05:00
|
|
|
@res.sendStatus = (code)=>
|
2014-10-08 12:18:24 -04:00
|
|
|
code.should.equal 404
|
2014-05-15 11:50:38 -04:00
|
|
|
done()
|
|
|
|
@PasswordResetController.setNewUserPassword @req, @res
|
|
|
|
|
2014-10-08 12:18:24 -04:00
|
|
|
it "should return 400 (Bad Request) if there is no password", (done)->
|
2014-05-15 11:50:38 -04:00
|
|
|
@req.body.password = ""
|
|
|
|
@PasswordResetHandler.setNewUserPassword.callsArgWith(2)
|
2015-07-08 11:56:38 -04:00
|
|
|
@res.sendStatus = (code)=>
|
2014-10-08 12:18:24 -04:00
|
|
|
code.should.equal 400
|
2014-05-15 11:50:38 -04:00
|
|
|
@PasswordResetHandler.setNewUserPassword.called.should.equal false
|
|
|
|
done()
|
|
|
|
@PasswordResetController.setNewUserPassword @req, @res
|
|
|
|
|
2014-10-08 12:18:24 -04:00
|
|
|
it "should return 400 (Bad Request) if there is no passwordResetToken", (done)->
|
2014-05-15 12:16:20 -04:00
|
|
|
@req.body.passwordResetToken = ""
|
2014-05-15 11:50:38 -04:00
|
|
|
@PasswordResetHandler.setNewUserPassword.callsArgWith(2)
|
2015-07-08 11:56:38 -04:00
|
|
|
@res.sendStatus = (code)=>
|
2014-10-08 12:18:24 -04:00
|
|
|
code.should.equal 400
|
2014-05-15 11:50:38 -04:00
|
|
|
@PasswordResetHandler.setNewUserPassword.called.should.equal false
|
|
|
|
done()
|
|
|
|
@PasswordResetController.setNewUserPassword @req, @res
|
|
|
|
|
2015-08-24 06:53:33 -04:00
|
|
|
it "should clear the session.resetToken", (done) ->
|
|
|
|
@PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, true)
|
|
|
|
@res.sendStatus = (code)=>
|
|
|
|
code.should.equal 200
|
|
|
|
@req.session.should.not.have.property 'resetToken'
|
|
|
|
done()
|
|
|
|
@PasswordResetController.setNewUserPassword @req, @res
|
2016-07-05 09:19:59 -04:00
|
|
|
|
|
|
|
it 'should clear sessions', (done) ->
|
|
|
|
@PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, true)
|
|
|
|
@res.sendStatus = (code)=>
|
|
|
|
@UserSessionsManager.revokeAllUserSessions.callCount.should.equal 1
|
|
|
|
done()
|
|
|
|
@PasswordResetController.setNewUserPassword @req, @res
|
|
|
|
|
2015-12-11 06:30:06 -05:00
|
|
|
it "should login user if login_after is set", (done) ->
|
|
|
|
@UserGetter.getUser = sinon.stub().callsArgWith(2, null, { email: "joe@example.com" })
|
|
|
|
@PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, true, @user_id = "user-id-123")
|
|
|
|
@req.body.login_after = "true"
|
|
|
|
@AuthenticationController.doLogin = (options, req, res, next)=>
|
|
|
|
@UserGetter.getUser.calledWith(@user_id).should.equal true
|
|
|
|
expect(options).to.deep.equal {
|
|
|
|
email: "joe@example.com",
|
|
|
|
password: @password
|
|
|
|
}
|
|
|
|
done()
|
|
|
|
@PasswordResetController.setNewUserPassword @req, @res
|
2015-08-24 06:53:33 -04:00
|
|
|
|
|
|
|
describe "renderSetPasswordForm", ->
|
|
|
|
|
|
|
|
describe "with token in query-string", ->
|
|
|
|
beforeEach ->
|
|
|
|
@req.query.passwordResetToken = @token
|
|
|
|
|
|
|
|
it "should set session.resetToken and redirect", (done) ->
|
|
|
|
@req.session.should.not.have.property 'resetToken'
|
|
|
|
@res.redirect = (path) =>
|
|
|
|
path.should.equal '/user/password/set'
|
|
|
|
@req.session.resetToken.should.equal @token
|
|
|
|
done()
|
|
|
|
@PasswordResetController.renderSetPasswordForm(@req, @res)
|
|
|
|
|
|
|
|
describe "without a token in query-string", ->
|
|
|
|
|
|
|
|
describe "with token in session", ->
|
|
|
|
beforeEach ->
|
|
|
|
@req.session.resetToken = @token
|
|
|
|
|
|
|
|
it "should render the page, passing the reset token", (done) ->
|
|
|
|
@res.render = (template_path, options) =>
|
|
|
|
options.passwordResetToken.should.equal @req.session.resetToken
|
|
|
|
done()
|
|
|
|
@PasswordResetController.renderSetPasswordForm(@req, @res)
|
2014-05-15 11:20:23 -04:00
|
|
|
|
2015-08-24 06:53:33 -04:00
|
|
|
describe "without a token in session", ->
|
2014-05-15 11:20:23 -04:00
|
|
|
|
2015-08-24 06:53:33 -04:00
|
|
|
it "should redirect to the reset request page", (done) ->
|
|
|
|
@res.redirect = (path) =>
|
|
|
|
path.should.equal "/user/password/reset"
|
|
|
|
@req.session.should.not.have.property 'resetToken'
|
|
|
|
done()
|
|
|
|
@PasswordResetController.renderSetPasswordForm(@req, @res)
|