PasswordResetTests.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. const { expect } = require('chai')
  2. const RateLimiter = require('../../../app/src/infrastructure/RateLimiter')
  3. const UserHelper = require('./helpers/UserHelper')
  4. const { db } = require('../../../app/src/infrastructure/mongodb')
  5. describe('PasswordReset', function () {
  6. let email, response, user, userHelper, token, emailQuery
  7. afterEach(async function () {
  8. await RateLimiter.promises.clearRateLimit(
  9. 'password_reset_rate_limit',
  10. '127.0.0.1'
  11. )
  12. })
  13. beforeEach(async function () {
  14. userHelper = new UserHelper()
  15. email = userHelper.getDefaultEmail()
  16. emailQuery = `?email=${encodeURIComponent(email)}`
  17. userHelper = await UserHelper.createUser({ email })
  18. user = userHelper.user
  19. // generate the token
  20. await userHelper.getCsrfToken()
  21. response = await userHelper.request.post('/user/password/reset', {
  22. form: {
  23. email,
  24. },
  25. })
  26. token = (
  27. await db.tokens.findOne({
  28. 'data.user_id': user._id.toString(),
  29. })
  30. ).token
  31. })
  32. describe('with a valid token', function () {
  33. describe('when logged in', function () {
  34. beforeEach(async function () {
  35. userHelper = await UserHelper.loginUser({
  36. email,
  37. password: userHelper.getDefaultPassword(),
  38. })
  39. response = await userHelper.request.get(
  40. `/user/password/set?passwordResetToken=${token}&email=${email}`,
  41. { simple: false }
  42. )
  43. expect(response.statusCode).to.equal(302)
  44. expect(response.headers.location).to.equal(
  45. `/user/password/set${emailQuery}`
  46. )
  47. // send reset request
  48. response = await userHelper.request.post('/user/password/set', {
  49. form: {
  50. passwordResetToken: token,
  51. password: 'a-password',
  52. },
  53. })
  54. userHelper = await UserHelper.getUser({ email })
  55. user = userHelper.user
  56. })
  57. it('update the password', async function () {
  58. expect(user.hashedPassword).to.exist
  59. expect(user.password).to.not.exist
  60. })
  61. it('log the change with initiatorId', async function () {
  62. const auditLog = userHelper.getAuditLogWithoutNoise()
  63. expect(auditLog).to.exist
  64. expect(auditLog[0]).to.exist
  65. expect(typeof auditLog[0].initiatorId).to.equal('object')
  66. expect(auditLog[0].initiatorId).to.deep.equal(user._id)
  67. expect(auditLog[0].operation).to.equal('reset-password')
  68. expect(auditLog[0].ipAddress).to.equal('127.0.0.1')
  69. expect(auditLog[0].timestamp).to.exist
  70. })
  71. })
  72. describe('when logged in as another user', function () {
  73. let otherUser, otherUserEmail
  74. beforeEach(async function () {
  75. otherUserEmail = userHelper.getDefaultEmail()
  76. userHelper = await UserHelper.createUser({ email: otherUserEmail })
  77. otherUser = userHelper.user
  78. userHelper = await UserHelper.loginUser({
  79. email: otherUserEmail,
  80. password: userHelper.getDefaultPassword(),
  81. })
  82. response = await userHelper.request.get(
  83. `/user/password/set?passwordResetToken=${token}&email=${email}`,
  84. { simple: false }
  85. )
  86. expect(response.statusCode).to.equal(302)
  87. expect(response.headers.location).to.equal(
  88. `/user/password/set${emailQuery}`
  89. )
  90. // send reset request
  91. response = await userHelper.request.post('/user/password/set', {
  92. form: {
  93. passwordResetToken: token,
  94. password: 'a-password',
  95. },
  96. })
  97. userHelper = await UserHelper.getUser({ email })
  98. user = userHelper.user
  99. })
  100. it('update the password', async function () {
  101. expect(user.hashedPassword).to.exist
  102. expect(user.password).to.not.exist
  103. })
  104. it('log the change with the logged in user as the initiatorId', async function () {
  105. const auditLog = userHelper.getAuditLogWithoutNoise()
  106. expect(auditLog).to.exist
  107. expect(auditLog[0]).to.exist
  108. expect(typeof auditLog[0].initiatorId).to.equal('object')
  109. expect(auditLog[0].initiatorId).to.deep.equal(otherUser._id)
  110. expect(auditLog[0].operation).to.equal('reset-password')
  111. expect(auditLog[0].ipAddress).to.equal('127.0.0.1')
  112. expect(auditLog[0].timestamp).to.exist
  113. })
  114. })
  115. describe('when not logged in', function () {
  116. beforeEach(async function () {
  117. response = await userHelper.request.get(
  118. `/user/password/set?passwordResetToken=${token}&email=${email}`,
  119. { simple: false }
  120. )
  121. expect(response.statusCode).to.equal(302)
  122. expect(response.headers.location).to.equal(
  123. `/user/password/set${emailQuery}`
  124. )
  125. // send reset request
  126. response = await userHelper.request.post('/user/password/set', {
  127. form: {
  128. passwordResetToken: token,
  129. password: 'a-password',
  130. },
  131. })
  132. userHelper = await UserHelper.getUser({ email })
  133. user = userHelper.user
  134. })
  135. it('updates the password', function () {
  136. expect(user.hashedPassword).to.exist
  137. expect(user.password).to.not.exist
  138. })
  139. it('log the change', async function () {
  140. const auditLog = userHelper.getAuditLogWithoutNoise()
  141. expect(auditLog).to.exist
  142. expect(auditLog[0]).to.exist
  143. expect(auditLog[0].initiatorId).to.equal(null)
  144. expect(auditLog[0].operation).to.equal('reset-password')
  145. expect(auditLog[0].ipAddress).to.equal('127.0.0.1')
  146. expect(auditLog[0].timestamp).to.exist
  147. })
  148. })
  149. describe('password checks', function () {
  150. beforeEach(async function () {
  151. response = await userHelper.request.get(
  152. `/user/password/set?passwordResetToken=${token}&email=${email}`,
  153. { simple: false }
  154. )
  155. expect(response.statusCode).to.equal(302)
  156. expect(response.headers.location).to.equal(
  157. `/user/password/set${emailQuery}`
  158. )
  159. })
  160. it('without a password should return 400 and not log the change', async function () {
  161. // send reset request
  162. response = await userHelper.request.post('/user/password/set', {
  163. form: {
  164. passwordResetToken: token,
  165. },
  166. simple: false,
  167. })
  168. expect(response.statusCode).to.equal(400)
  169. userHelper = await UserHelper.getUser({ email })
  170. const auditLog = userHelper.getAuditLogWithoutNoise()
  171. expect(auditLog).to.deep.equal([])
  172. })
  173. it('without a valid password should return 400 and not log the change', async function () {
  174. // send reset request
  175. response = await userHelper.request.post('/user/password/set', {
  176. form: {
  177. passwordResetToken: token,
  178. password: 'short',
  179. },
  180. simple: false,
  181. })
  182. expect(response.statusCode).to.equal(400)
  183. userHelper = await UserHelper.getUser({ email })
  184. const auditLog = userHelper.getAuditLogWithoutNoise()
  185. expect(auditLog).to.deep.equal([])
  186. })
  187. })
  188. })
  189. describe('without a valid token', function () {
  190. it('no token should redirect to page to re-request reset token', async function () {
  191. response = await userHelper.request.get(
  192. `/user/password/set?&email=${email}`,
  193. { simple: false }
  194. )
  195. expect(response.statusCode).to.equal(302)
  196. expect(response.headers.location).to.equal('/user/password/reset')
  197. })
  198. it('should return 404 for invalid tokens', async function () {
  199. const invalidToken = 'not-real-token'
  200. response = await userHelper.request.get(
  201. `/user/password/set?&passwordResetToken=${invalidToken}&email=${email}`,
  202. { simple: false }
  203. )
  204. expect(response.statusCode).to.equal(302)
  205. expect(response.headers.location).to.equal(
  206. `/user/password/set${emailQuery}`
  207. )
  208. // send reset request
  209. response = await userHelper.request.post('/user/password/set', {
  210. form: {
  211. passwordResetToken: invalidToken,
  212. password: 'a-password',
  213. },
  214. simple: false,
  215. })
  216. expect(response.statusCode).to.equal(404)
  217. })
  218. })
  219. describe('password reset', function () {
  220. it('should return 200 if email field is valid', async function () {
  221. response = await userHelper.request.post(`/user/password/reset`, {
  222. form: {
  223. email,
  224. },
  225. })
  226. expect(response.statusCode).to.equal(200)
  227. })
  228. it('should return 400 if email field is missing', async function () {
  229. response = await userHelper.request.post(`/user/password/reset`, {
  230. form: {
  231. mail: email,
  232. },
  233. simple: false,
  234. })
  235. expect(response.statusCode).to.equal(400)
  236. })
  237. })
  238. describe('password set', function () {
  239. it('should return 200 if password and passwordResetToken fields are valid', async function () {
  240. response = await userHelper.request.post(`/user/password/set`, {
  241. form: {
  242. password: 'new-password',
  243. passwordResetToken: token,
  244. },
  245. })
  246. expect(response.statusCode).to.equal(200)
  247. })
  248. it('should return 400 if password field is missing', async function () {
  249. response = await userHelper.request.post(`/user/password/set`, {
  250. form: {
  251. passwordResetToken: token,
  252. },
  253. simple: false,
  254. })
  255. expect(response.statusCode).to.equal(400)
  256. })
  257. it('should return 400 if passwordResetToken field is missing', async function () {
  258. response = await userHelper.request.post(`/user/password/set`, {
  259. form: {
  260. password: 'new-password',
  261. },
  262. simple: false,
  263. })
  264. expect(response.statusCode).to.equal(400)
  265. })
  266. })
  267. })