Просмотр исходного кода

[web] In tests, update email confirmation to use the 6-digits flow (#27069)

* Rename `sendExistingSecondaryEmailConfirmationCode` to `sendExistingEmailConfirmationCode`

* Deduplicate error handling into `throwIfErrorResponse`

* Update `userHelper.confirmEmail` to use the 6-digits flow

GitOrigin-RevId: 91bdf7b185407b58520ca6b2aa1a7c71bdd23bc8
Antoine Clausse 1 год назад
Родитель
Сommit
98af0e3d82

+ 3 - 3
services/web/app/src/Features/User/UserEmailsController.js

@@ -141,7 +141,7 @@ async function sendReconfirmation(req, res) {
   res.sendStatus(204)
 }
 
-async function sendExistingSecondaryEmailConfirmationCode(req, res) {
+async function sendExistingEmailConfirmationCode(req, res) {
   const userId = SessionManager.getLoggedInUserId(req.session)
   const email = EmailHelper.parseEmail(req.body.email)
   if (!email) {
@@ -715,8 +715,8 @@ const UserEmailsController = {
 
   sendReconfirmation: expressify(sendReconfirmation),
 
-  sendExistingSecondaryEmailConfirmationCode: expressify(
-    sendExistingSecondaryEmailConfirmationCode
+  sendExistingEmailConfirmationCode: expressify(
+    sendExistingEmailConfirmationCode
   ),
 
   addSecondaryEmailPage: expressify(addSecondaryEmailPage),

+ 1 - 1
services/web/app/src/router.mjs

@@ -345,7 +345,7 @@ async function initialize(webRouter, privateApiRouter, publicApiRouter) {
     '/user/emails/send-confirmation-code',
     AuthenticationController.requireLogin(),
     RateLimiterMiddleware.rateLimit(rateLimiters.sendConfirmation),
-    UserEmailsController.sendExistingSecondaryEmailConfirmationCode
+    UserEmailsController.sendExistingEmailConfirmationCode
   )
 
   webRouter.post(

+ 39 - 76
services/web/test/acceptance/src/helpers/UserHelper.mjs

@@ -7,7 +7,6 @@ import UserGetter from '../../../../app/src/Features/User/UserGetter.js'
 import UserUpdater from '../../../../app/src/Features/User/UserUpdater.js'
 import moment from 'moment'
 import fetch from 'node-fetch'
-import { db } from '../../../../app/src/infrastructure/mongodb.js'
 import mongodb from 'mongodb-legacy'
 
 import { UserAuditLogEntry } from '../../../../app/src/models/UserAuditLogEntry.js'
@@ -19,11 +18,20 @@ import { RateLimiter } from '../../../../app/src/infrastructure/RateLimiter.js'
 const { ObjectId } = mongodb
 
 const rateLimiters = {
-  resendConfirmation: new RateLimiter('resend-confirmation'),
+  sendConfirmation: new RateLimiter('send-confirmation'),
 }
 
 let globalUserNum = Settings.test.counterInit
 
+const throwIfErrorResponse = async response => {
+  if (response.status < 200 || response.status >= 300) {
+    const body = await response.text()
+    throw new Error(
+      `request failed: status=${response.status} body=${JSON.stringify(body)}`
+    )
+  }
+}
+
 class UserHelper {
   /**
    * Create UserHelper
@@ -129,13 +137,7 @@ class UserHelper {
     // get csrf token from api and store
     const response = await this.fetch('/dev/csrf')
     const body = await response.text()
-    if (response.status !== 200) {
-      throw new Error(
-        `get csrf token failed: status=${response.status} body=${JSON.stringify(
-          body
-        )}`
-      )
-    }
+    await throwIfErrorResponse(response)
     this._csrfToken = body
   }
 
@@ -145,14 +147,7 @@ class UserHelper {
   async getSession() {
     const response = await this.fetch('/dev/session')
     const body = await response.text()
-
-    if (response.status !== 200) {
-      throw new Error(
-        `get session failed: status=${response.status} body=${JSON.stringify(
-          body
-        )}`
-      )
-    }
+    await throwIfErrorResponse(response)
     return JSON.parse(body)
   }
 
@@ -160,24 +155,22 @@ class UserHelper {
     const response = await this.fetch(
       `/dev/split_test/get_assignment?splitTestName=${splitTestName}`
     )
+    await throwIfErrorResponse(response)
     const body = await response.text()
-
-    if (response.status !== 200) {
-      throw new Error(
-        `get split test assignment failed: status=${response.status} body=${JSON.stringify(
-          body
-        )}`
-      )
-    }
     return JSON.parse(body)
   }
 
-  async getEmailConfirmationCode() {
+  /**
+   *
+   * @param {'pendingExistingEmail'|'pendingUserRegistration'}sessionKey
+   * @return {Promise<*>}
+   */
+  async getEmailConfirmationCode(sessionKey) {
     const session = await this.getSession()
 
-    const code = session.pendingUserRegistration?.confirmCode
+    const code = session[sessionKey]?.confirmCode
     if (!code) {
-      throw new Error('No confirmation code found in session')
+      throw new Error(`No confirmation code found in session (${sessionKey})`)
     }
     return code
   }
@@ -383,14 +376,8 @@ class UserHelper {
       body: JSON.stringify(userData),
       ...options,
     })
+    await throwIfErrorResponse(response)
     const body = await response.json()
-    if (response.status !== 200) {
-      throw new Error(
-        `register failed: status=${response.status} body=${JSON.stringify(
-          body
-        )}`
-      )
-    }
     if (body.message && body.message.type === 'error') {
       throw new Error(`register api error: ${body.message.text}`)
     }
@@ -400,7 +387,9 @@ class UserHelper {
       )
     }
 
-    const code = await userHelper.getEmailConfirmationCode()
+    const code = await userHelper.getEmailConfirmationCode(
+      'pendingUserRegistration'
+    )
 
     const confirmationResponse = await userHelper.fetch(
       '/registration/confirm-email',
@@ -446,14 +435,7 @@ class UserHelper {
       method: 'POST',
       body: new URLSearchParams([['email', email]]),
     })
-    const body = await response.text()
-    if (response.status !== 204) {
-      throw new Error(
-        `add email failed: status=${response.status} body=${JSON.stringify(
-          body
-        )}`
-      )
-    }
+    await throwIfErrorResponse(response)
   }
 
   async addEmailAndConfirm(userId, email) {
@@ -519,40 +501,21 @@ class UserHelper {
 
   async confirmEmail(userId, email) {
     // clear ratelimiting on resend confirmation endpoint
-    await rateLimiters.resendConfirmation.delete(userId)
-    // UserHelper.createUser does not create a confirmation token
-    let response = await this.fetch('/user/emails/resend_confirmation', {
-      method: 'POST',
-      body: new URLSearchParams([['email', email]]),
-    })
-    if (response.status !== 200) {
-      const body = await response.text()
-      throw new Error(
-        `resend confirmation failed: status=${
-          response.status
-        } body=${JSON.stringify(body)}`
-      )
-    }
-    const tokenData = await db.tokens
-      .find({
-        use: 'email_confirmation',
-        'data.user_id': userId.toString(),
-        'data.email': email,
-        usedAt: { $exists: false },
-      })
-      .next()
-    response = await this.fetch('/user/emails/confirm', {
+    await rateLimiters.sendConfirmation.delete(userId)
+    const requestConfirmationCode = await this.fetch(
+      '/user/emails/send-confirmation-code',
+      {
+        method: 'POST',
+        body: new URLSearchParams({ email }),
+      }
+    )
+    await throwIfErrorResponse(requestConfirmationCode)
+    const code = await this.getEmailConfirmationCode('pendingExistingEmail')
+    const requestConfirmCode = await this.fetch('/user/emails/confirm-code', {
       method: 'POST',
-      body: new URLSearchParams([['token', tokenData.token]]),
+      body: new URLSearchParams({ code }),
     })
-    if (response.status !== 200) {
-      const body = await response.text()
-      throw new Error(
-        `confirm email failed: status=${response.status} body=${JSON.stringify(
-          body
-        )}`
-      )
-    }
+    await throwIfErrorResponse(requestConfirmCode)
   }
 }
 

+ 5 - 5
services/web/test/unit/src/User/UserEmailsControllerTests.js

@@ -905,7 +905,7 @@ describe('UserEmailsController', function () {
     })
   })
 
-  describe('sendExistingSecondaryEmailConfirmationCode', function () {
+  describe('sendExistingEmailConfirmationCode', function () {
     beforeEach(function () {
       this.email = 'existing-email@example.com'
       this.req.body.email = this.email
@@ -923,7 +923,7 @@ describe('UserEmailsController', function () {
     })
 
     it('should send confirmation code for existing email', async function () {
-      await this.UserEmailsController.sendExistingSecondaryEmailConfirmationCode(
+      await this.UserEmailsController.sendExistingEmailConfirmationCode(
         this.req,
         {
           sendStatus: code => {
@@ -944,7 +944,7 @@ describe('UserEmailsController', function () {
       this.UserEmailsConfirmationHandler.promises.sendConfirmationCode.resolves(
         { confirmCode, confirmCodeExpiresTimestamp }
       )
-      await this.UserEmailsController.sendExistingSecondaryEmailConfirmationCode(
+      await this.UserEmailsController.sendExistingEmailConfirmationCode(
         this.req,
         { sendStatus: sinon.stub() }
       )
@@ -958,7 +958,7 @@ describe('UserEmailsController', function () {
 
     it('should handle invalid email', async function () {
       this.EmailHelper.parseEmail.returns(null)
-      await this.UserEmailsController.sendExistingSecondaryEmailConfirmationCode(
+      await this.UserEmailsController.sendExistingEmailConfirmationCode(
         this.req,
         {
           sendStatus: code => {
@@ -975,7 +975,7 @@ describe('UserEmailsController', function () {
       this.UserGetter.promises.getUserByAnyEmail.resolves({
         _id: 'another-user-id',
       })
-      await this.UserEmailsController.sendExistingSecondaryEmailConfirmationCode(
+      await this.UserEmailsController.sendExistingEmailConfirmationCode(
         this.req,
         {
           sendStatus: code => {