PasswordResetControllerTests.coffee 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. should = require('chai').should()
  2. expect = require("chai").expect
  3. SandboxedModule = require('sandboxed-module')
  4. assert = require('assert')
  5. path = require('path')
  6. sinon = require('sinon')
  7. modulePath = path.join __dirname, "../../../../app/js/Features/PasswordReset/PasswordResetController"
  8. expect = require("chai").expect
  9. describe "PasswordResetController", ->
  10. beforeEach ->
  11. @settings = {}
  12. @PasswordResetHandler =
  13. generateAndEmailResetToken:sinon.stub()
  14. setNewUserPassword:sinon.stub()
  15. @RateLimiter =
  16. addCount: sinon.stub()
  17. @UserSessionsManager =
  18. revokeAllUserSessions: sinon.stub().callsArgWith(2, null)
  19. @PasswordResetController = SandboxedModule.require modulePath, requires:
  20. "settings-sharelatex":@settings
  21. "./PasswordResetHandler":@PasswordResetHandler
  22. "logger-sharelatex": log:->
  23. "../../infrastructure/RateLimiter":@RateLimiter
  24. "../Authentication/AuthenticationController": @AuthenticationController = {}
  25. "../User/UserGetter": @UserGetter = {}
  26. "../User/UserSessionsManager": @UserSessionsManager
  27. @email = "bob@bob.com "
  28. @user_id = 'mock-user-id'
  29. @token = "my security token that was emailed to me"
  30. @password = "my new password"
  31. @req =
  32. body:
  33. email:@email
  34. passwordResetToken:@token
  35. password:@password
  36. i18n:
  37. translate:->
  38. session: {}
  39. query: {}
  40. @res = {}
  41. describe "requestReset", ->
  42. it "should error if the rate limit is hit", (done)->
  43. @PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
  44. @RateLimiter.addCount.callsArgWith(1, null, false)
  45. @res.send = (code)=>
  46. code.should.equal 500
  47. @PasswordResetHandler.generateAndEmailResetToken.calledWith(@email.trim()).should.equal false
  48. done()
  49. @PasswordResetController.requestReset @req, @res
  50. it "should tell the handler to process that email", (done)->
  51. @RateLimiter.addCount.callsArgWith(1, null, true)
  52. @PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
  53. @res.sendStatus = (code)=>
  54. code.should.equal 200
  55. @PasswordResetHandler.generateAndEmailResetToken.calledWith(@email.trim()).should.equal true
  56. done()
  57. @PasswordResetController.requestReset @req, @res
  58. it "should send a 500 if there is an error", (done)->
  59. @RateLimiter.addCount.callsArgWith(1, null, true)
  60. @PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, "error")
  61. @res.send = (code)=>
  62. code.should.equal 500
  63. done()
  64. @PasswordResetController.requestReset @req, @res
  65. it "should send a 404 if the email doesn't exist", (done)->
  66. @RateLimiter.addCount.callsArgWith(1, null, true)
  67. @PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, false)
  68. @res.send = (code)=>
  69. code.should.equal 404
  70. done()
  71. @PasswordResetController.requestReset @req, @res
  72. it "should lowercase the email address", (done)->
  73. @email = "UPerCaseEMAIL@example.Com"
  74. @req.body.email = @email
  75. @RateLimiter.addCount.callsArgWith(1, null, true)
  76. @PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
  77. @res.sendStatus = (code)=>
  78. code.should.equal 200
  79. @PasswordResetHandler.generateAndEmailResetToken.calledWith(@email.toLowerCase()).should.equal true
  80. done()
  81. @PasswordResetController.requestReset @req, @res
  82. describe "setNewUserPassword", ->
  83. beforeEach ->
  84. @req.session.resetToken = @token
  85. it "should tell the user handler to reset the password", (done)->
  86. @PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, true, @user_id)
  87. @res.sendStatus = (code)=>
  88. code.should.equal 200
  89. @PasswordResetHandler.setNewUserPassword.calledWith(@token, @password).should.equal true
  90. done()
  91. @PasswordResetController.setNewUserPassword @req, @res
  92. it "should send 404 if the token didn't work", (done)->
  93. @PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, false, @user_id)
  94. @res.sendStatus = (code)=>
  95. code.should.equal 404
  96. done()
  97. @PasswordResetController.setNewUserPassword @req, @res
  98. it "should return 400 (Bad Request) if there is no password", (done)->
  99. @req.body.password = ""
  100. @PasswordResetHandler.setNewUserPassword.callsArgWith(2)
  101. @res.sendStatus = (code)=>
  102. code.should.equal 400
  103. @PasswordResetHandler.setNewUserPassword.called.should.equal false
  104. done()
  105. @PasswordResetController.setNewUserPassword @req, @res
  106. it "should return 400 (Bad Request) if there is no passwordResetToken", (done)->
  107. @req.body.passwordResetToken = ""
  108. @PasswordResetHandler.setNewUserPassword.callsArgWith(2)
  109. @res.sendStatus = (code)=>
  110. code.should.equal 400
  111. @PasswordResetHandler.setNewUserPassword.called.should.equal false
  112. done()
  113. @PasswordResetController.setNewUserPassword @req, @res
  114. it "should clear the session.resetToken", (done) ->
  115. @PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, true, @user_id)
  116. @res.sendStatus = (code)=>
  117. code.should.equal 200
  118. @req.session.should.not.have.property 'resetToken'
  119. done()
  120. @PasswordResetController.setNewUserPassword @req, @res
  121. it 'should clear sessions', (done) ->
  122. @PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, true, @user_id)
  123. @res.sendStatus = (code)=>
  124. @UserSessionsManager.revokeAllUserSessions.callCount.should.equal 1
  125. done()
  126. @PasswordResetController.setNewUserPassword @req, @res
  127. describe 'when login_after is set', ->
  128. beforeEach ->
  129. @UserGetter.getUser = sinon.stub().callsArgWith(2, null, { email: "joe@example.com" })
  130. @PasswordResetHandler.setNewUserPassword.callsArgWith(2, null, true, @user_id = "user-id-123")
  131. @req.body.login_after = "true"
  132. @res.json = sinon.stub()
  133. @AuthenticationController.afterLoginSessionSetup = sinon.stub().callsArgWith(2, null)
  134. @AuthenticationController._getRedirectFromSession = sinon.stub().returns('/some/path')
  135. it "should login user if login_after is set", (done) ->
  136. @PasswordResetController.setNewUserPassword @req, @res
  137. @AuthenticationController.afterLoginSessionSetup.callCount.should.equal 1
  138. @AuthenticationController.afterLoginSessionSetup.calledWith(
  139. @req,
  140. {email: 'joe@example.com'}
  141. ).should.equal true
  142. @AuthenticationController._getRedirectFromSession.callCount.should.equal 1
  143. @res.json.callCount.should.equal 1
  144. @res.json.calledWith({redir: '/some/path'}).should.equal true
  145. done()
  146. describe "renderSetPasswordForm", ->
  147. describe "with token in query-string", ->
  148. beforeEach ->
  149. @req.query.passwordResetToken = @token
  150. it "should set session.resetToken and redirect", (done) ->
  151. @req.session.should.not.have.property 'resetToken'
  152. @res.redirect = (path) =>
  153. path.should.equal '/user/password/set'
  154. @req.session.resetToken.should.equal @token
  155. done()
  156. @PasswordResetController.renderSetPasswordForm(@req, @res)
  157. describe "without a token in query-string", ->
  158. describe "with token in session", ->
  159. beforeEach ->
  160. @req.session.resetToken = @token
  161. it "should render the page, passing the reset token", (done) ->
  162. @res.render = (template_path, options) =>
  163. options.passwordResetToken.should.equal @req.session.resetToken
  164. done()
  165. @PasswordResetController.renderSetPasswordForm(@req, @res)
  166. describe "without a token in session", ->
  167. it "should redirect to the reset request page", (done) ->
  168. @res.redirect = (path) =>
  169. path.should.equal "/user/password/reset"
  170. @req.session.should.not.have.property 'resetToken'
  171. done()
  172. @PasswordResetController.renderSetPasswordForm(@req, @res)