PasswordResetHandlerTests.coffee 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. should = require('chai').should()
  2. SandboxedModule = require('sandboxed-module')
  3. assert = require('assert')
  4. path = require('path')
  5. sinon = require('sinon')
  6. modulePath = path.join __dirname, "../../../../app/js/Features/PasswordReset/PasswordResetHandler"
  7. expect = require("chai").expect
  8. describe "PasswordResetHandler", ->
  9. beforeEach ->
  10. @settings =
  11. siteUrl: "www.sharelatex.com"
  12. @OneTimeTokenHandler =
  13. getNewToken:sinon.stub()
  14. getValueFromTokenAndExpire:sinon.stub()
  15. @UserGetter =
  16. getUserByMainEmail:sinon.stub()
  17. getUser: sinon.stub()
  18. getUserByAnyEmail: sinon.stub()
  19. @EmailHandler =
  20. sendEmail:sinon.stub()
  21. @AuthenticationManager =
  22. setUserPassword:sinon.stub()
  23. setUserPasswordInV1:sinon.stub()
  24. setUserPasswordInV2:sinon.stub()
  25. @V1Api =
  26. request: sinon.stub()
  27. @PasswordResetHandler = SandboxedModule.require modulePath, requires:
  28. "../User/UserGetter": @UserGetter
  29. "../Security/OneTimeTokenHandler": @OneTimeTokenHandler
  30. "../Email/EmailHandler":@EmailHandler
  31. "../Authentication/AuthenticationManager":@AuthenticationManager
  32. "../V1/V1Api": @V1Api
  33. "settings-sharelatex": @settings
  34. "logger-sharelatex":
  35. log:->
  36. err:->
  37. @token = "12312321i"
  38. @user_id = "user_id_here"
  39. @user =
  40. email : @email = "bob@bob.com"
  41. @password = "my great secret password"
  42. @callback = sinon.stub()
  43. describe "generateAndEmailResetToken", ->
  44. describe "when in ShareLaTeX", ->
  45. it "should check the user exists", (done)->
  46. @UserGetter.getUserByMainEmail.callsArgWith(1)
  47. @UserGetter.getUserByAnyEmail.callsArgWith(1)
  48. @OneTimeTokenHandler.getNewToken.yields()
  49. @PasswordResetHandler.generateAndEmailResetToken @user.email, (err, status)=>
  50. should.equal(status, null)
  51. done()
  52. it "should send the email with the token", (done)->
  53. @UserGetter.getUserByMainEmail.callsArgWith(1, null, @user)
  54. @OneTimeTokenHandler.getNewToken.yields(null, @token)
  55. @EmailHandler.sendEmail.callsArgWith(2)
  56. @PasswordResetHandler.generateAndEmailResetToken @user.email, (err, status)=>
  57. @EmailHandler.sendEmail.called.should.equal true
  58. status.should.equal 'primary'
  59. args = @EmailHandler.sendEmail.args[0]
  60. args[0].should.equal "passwordResetRequested"
  61. args[1].setNewPasswordUrl.should.equal "#{@settings.siteUrl}/user/password/set?passwordResetToken=#{@token}&email=#{encodeURIComponent(@user.email)}"
  62. done()
  63. it "should return exists == null for a holdingAccount", (done) ->
  64. @user.holdingAccount = true
  65. @UserGetter.getUserByMainEmail.callsArgWith(1, null, @user)
  66. @UserGetter.getUserByAnyEmail.callsArgWith(1)
  67. @OneTimeTokenHandler.getNewToken.yields()
  68. @PasswordResetHandler.generateAndEmailResetToken @user.email, (err, status)=>
  69. should.equal(status, null)
  70. done()
  71. describe "when in overleaf", ->
  72. beforeEach ->
  73. @settings.overleaf = true
  74. describe "when the email exists", ->
  75. beforeEach ->
  76. @V1Api.request.yields(null, {}, { user_id: 42 })
  77. @OneTimeTokenHandler.getNewToken.yields(null, @token)
  78. @EmailHandler.sendEmail.yields()
  79. @PasswordResetHandler.generateAndEmailResetToken @email, @callback
  80. it 'should call the v1 api for the user', ->
  81. @V1Api.request.calledWith({
  82. url: "/api/v1/sharelatex/user_emails"
  83. qs:
  84. email: @email
  85. expectedStatusCodes: [404]
  86. }).should.equal true
  87. it 'should set the password token data to the user id and email', ->
  88. @OneTimeTokenHandler.getNewToken
  89. .calledWith('password', {
  90. v1_user_id: 42
  91. })
  92. .should.equal true
  93. it 'should send an email with the token', ->
  94. @EmailHandler.sendEmail.called.should.equal true
  95. args = @EmailHandler.sendEmail.args[0]
  96. args[0].should.equal "passwordResetRequested"
  97. args[1].setNewPasswordUrl.should.equal "#{@settings.siteUrl}/user/password/set?passwordResetToken=#{@token}&email=#{encodeURIComponent(@user.email)}"
  98. it 'should return status == true', ->
  99. @callback.calledWith(null, 'primary').should.equal true
  100. describe "when the email doesn't exist", ->
  101. beforeEach ->
  102. @V1Api.request = sinon.stub().yields(null, { statusCode: 404 }, {})
  103. @UserGetter.getUserByAnyEmail.callsArgWith(1)
  104. @PasswordResetHandler.generateAndEmailResetToken @email, @callback
  105. it 'should not set the password token data', ->
  106. @OneTimeTokenHandler.getNewToken
  107. .called.should.equal false
  108. it 'should send an email with the token', ->
  109. @EmailHandler.sendEmail.called.should.equal false
  110. it 'should return status == null', ->
  111. @callback.calledWith(null, null).should.equal true
  112. describe "when the user isn't on v2", ->
  113. beforeEach ->
  114. @V1Api.request = sinon.stub().yields(null, { statusCode: 404 }, {})
  115. @UserGetter.getUserByAnyEmail.callsArgWith(1, null, @user)
  116. @PasswordResetHandler.generateAndEmailResetToken @email, @callback
  117. it 'should not set the password token data', ->
  118. @OneTimeTokenHandler.getNewToken
  119. .called.should.equal false
  120. it 'should not send an email with the token', ->
  121. @EmailHandler.sendEmail.called.should.equal false
  122. it 'should return status == sharelatex', ->
  123. @callback.calledWith(null, 'sharelatex').should.equal true
  124. describe "when the email is a secondary email", ->
  125. beforeEach ->
  126. @V1Api.request = sinon.stub().yields(null, { statusCode: 404 }, {})
  127. @user.overleaf = {id: 101}
  128. @UserGetter.getUserByAnyEmail.callsArgWith(1, null, @user)
  129. @PasswordResetHandler.generateAndEmailResetToken @email, @callback
  130. it 'should not set the password token data', ->
  131. @OneTimeTokenHandler.getNewToken
  132. .called.should.equal false
  133. it 'should not send an email with the token', ->
  134. @EmailHandler.sendEmail.called.should.equal false
  135. it 'should return status == secondary', ->
  136. @callback.calledWith(null, 'secondary').should.equal true
  137. describe "setNewUserPassword", ->
  138. describe "when no data is found", ->
  139. beforeEach ->
  140. @OneTimeTokenHandler.getValueFromTokenAndExpire.yields(null, null)
  141. @PasswordResetHandler.setNewUserPassword @token, @password, @callback
  142. it 'should return exists == false', ->
  143. @callback.calledWith(null, false).should.equal true
  144. describe 'when the data is an old style user_id', ->
  145. beforeEach ->
  146. @AuthenticationManager.setUserPassword.yields(null, true, @user_id)
  147. @OneTimeTokenHandler.getValueFromTokenAndExpire.yields(null, @user_id)
  148. @PasswordResetHandler.setNewUserPassword @token, @password, @callback
  149. it 'should call setUserPasswordInV2', ->
  150. @AuthenticationManager.setUserPassword
  151. .calledWith(@user_id, @password)
  152. .should.equal true
  153. it 'should reset == true and the user_id', ->
  154. @callback.calledWith(null, true, @user_id).should.equal true
  155. describe 'when the data is a new style user_id', ->
  156. beforeEach ->
  157. @AuthenticationManager.setUserPassword.yields(null, true, @user_id)
  158. @OneTimeTokenHandler.getValueFromTokenAndExpire.yields(null, {@user_id})
  159. @PasswordResetHandler.setNewUserPassword @token, @password, @callback
  160. it 'should call setUserPasswordInV2', ->
  161. @AuthenticationManager.setUserPassword
  162. .calledWith(@user_id, @password)
  163. .should.equal true
  164. it 'should reset == true and the user_id', ->
  165. @callback.calledWith(null, true, @user_id).should.equal true
  166. describe 'when the data is v1 id', ->
  167. beforeEach ->
  168. @v1_user_id = 2345
  169. @AuthenticationManager.setUserPasswordInV1.yields(null, true)
  170. @UserGetter.getUser.withArgs({'overleaf.id': @v1_user_id}).yields(null, { _id: @user_id })
  171. @OneTimeTokenHandler.getValueFromTokenAndExpire.yields(null, {@v1_user_id})
  172. @PasswordResetHandler.setNewUserPassword @token, @password, @callback
  173. it 'should call setUserPasswordInV1', ->
  174. @AuthenticationManager.setUserPasswordInV1
  175. .calledWith(@v1_user_id, @password)
  176. .should.equal true
  177. it 'should look up the user by v1 id for the v2 user id', ->
  178. @UserGetter.getUser
  179. .calledWith({'overleaf.id': @v1_user_id})
  180. .should.equal true
  181. it 'should reset == true and the user_id', ->
  182. @callback.calledWith(null, true, @user_id).should.equal true