AddSecondaryEmailTests.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. const { expect } = require('chai')
  2. const User = require('./helpers/User').promises
  3. const logger = require('@overleaf/logger')
  4. const sinon = require('sinon')
  5. const { db } = require('../../../app/src/infrastructure/mongodb')
  6. const Features = require('../../../app/src/infrastructure/Features')
  7. describe('Add secondary email address confirmation code email', function () {
  8. let spy
  9. let user, user2, res, confirmCode
  10. const extractConfirmCode = () => {
  11. const emailDebugLog = spy.args.find(
  12. ([, msg]) => msg === 'Would send email if enabled.'
  13. )
  14. const emailConfirmSubject = emailDebugLog[0].options.subject
  15. return emailConfirmSubject.match(/\((\d{6})\)/)[1]
  16. }
  17. beforeEach(async function () {
  18. if (!Features.hasFeature('saas')) {
  19. this.skip()
  20. }
  21. spy = sinon.spy(logger, 'info')
  22. user = new User()
  23. await user.register()
  24. await user.login()
  25. spy.resetHistory()
  26. res = await user.doRequest('POST', {
  27. json: {
  28. email: 'secondary@overleaf.com',
  29. },
  30. uri: `/user/emails/secondary`,
  31. })
  32. confirmCode = extractConfirmCode()
  33. })
  34. afterEach(function () {
  35. if (!Features.hasFeature('saas')) {
  36. this.skip()
  37. }
  38. spy.restore()
  39. })
  40. it('should send email with confirmation code', function () {
  41. expect(res.response.statusCode).to.equal(200)
  42. expect(confirmCode.length).to.equal(6)
  43. })
  44. describe('with a valid confirmation code', function () {
  45. beforeEach(async function () {
  46. this.result = await user.doRequest('POST', {
  47. json: {
  48. code: confirmCode,
  49. },
  50. uri: '/user/emails/confirm-secondary',
  51. })
  52. })
  53. it('should redirect to /project', async function () {
  54. expect(this.result.response.statusCode).to.equal(200)
  55. expect(this.result.body.redir).to.equal('/project')
  56. })
  57. it('the new email should be saved in mongo', async function () {
  58. const userInDb = await db.users.findOne(
  59. { email: user.email },
  60. { projection: { emails: 1 } }
  61. )
  62. expect(userInDb).to.exist
  63. const newSecondaryEmail = userInDb.emails.find(
  64. email => email.email === 'secondary@overleaf.com'
  65. )
  66. expect(newSecondaryEmail).to.exist
  67. expect(newSecondaryEmail.confirmedAt).to.exist
  68. expect(newSecondaryEmail.reconfirmedAt).to.exist
  69. expect(newSecondaryEmail.reconfirmedAt).to.deep.equal(
  70. newSecondaryEmail.confirmedAt
  71. )
  72. })
  73. })
  74. describe('with an invalid confirmation code', function () {
  75. beforeEach(async function () {
  76. this.result = await user.doRequest('POST', {
  77. json: {
  78. code: '123',
  79. },
  80. uri: '/user/emails/confirm-secondary',
  81. })
  82. })
  83. it('should respond with invalid confirmation code error', async function () {
  84. expect(this.result.response.statusCode).to.equal(403)
  85. expect(this.result.body.message.key).to.equal('invalid_confirmation_code')
  86. })
  87. })
  88. describe('with a duplicate email', async function () {
  89. beforeEach(async function () {
  90. await user.doRequest('POST', {
  91. json: {
  92. code: confirmCode,
  93. },
  94. uri: '/user/emails/confirm-secondary',
  95. })
  96. user2 = new User()
  97. await user2.register()
  98. await user2.login()
  99. })
  100. it('should respond with a email already registered error', async function () {
  101. res = await user2.doRequest('POST', {
  102. json: {
  103. email: 'secondary@overleaf.com',
  104. },
  105. uri: `/user/emails/secondary`,
  106. })
  107. expect(res.response.statusCode).to.equal(409)
  108. expect(res.body.message.text).to.equal('This email is already registered')
  109. })
  110. })
  111. it('should hit rate limit on code check', async function () {
  112. let confirmEmailReq
  113. for (let i = 0; i < 20; i++) {
  114. confirmEmailReq = await user.doRequest('POST', {
  115. json: {
  116. code: '123',
  117. },
  118. uri: '/user/emails/confirm-secondary',
  119. })
  120. }
  121. expect(confirmEmailReq.response.statusCode).to.equal(429)
  122. })
  123. it('should resend confirm code', async function () {
  124. const oldConfirmCode = extractConfirmCode()
  125. spy.resetHistory()
  126. const resendCodeRes = await user.doRequest('POST', {
  127. uri: '/user/emails/resend-secondary-confirmation',
  128. })
  129. const newConfirmCode = extractConfirmCode()
  130. expect(resendCodeRes.response.statusCode).to.equal(200)
  131. expect(JSON.parse(resendCodeRes.body).message.key).to.equal(
  132. 'we_sent_new_code'
  133. )
  134. const oldConfirmRes = await user.doRequest('POST', {
  135. json: {
  136. code: oldConfirmCode,
  137. },
  138. uri: '/user/emails/confirm-secondary',
  139. })
  140. expect(oldConfirmRes.response.statusCode).to.equal(403)
  141. expect(oldConfirmRes.body.message.key).to.equal('invalid_confirmation_code')
  142. const newCodeRes = await user.doRequest('POST', {
  143. json: {
  144. code: newConfirmCode,
  145. },
  146. uri: '/user/emails/confirm-secondary',
  147. })
  148. expect(newCodeRes.response.statusCode).to.equal(200)
  149. expect(newCodeRes.body.redir).to.equal('/project')
  150. })
  151. it('should hit rate limit on code resend', async function () {
  152. let resendCodeReq
  153. for (let i = 0; i < 5; i++) {
  154. resendCodeReq = await user.doRequest('POST', {
  155. json: true,
  156. uri: '/user/emails/resend-secondary-confirmation',
  157. })
  158. }
  159. expect(resendCodeReq.response.statusCode).to.equal(429)
  160. })
  161. })