diff --git a/cypress/e2e/27-two-factor-authentication.cy.ts b/cypress/e2e/27-two-factor-authentication.cy.ts index 05949a188c..2201e65285 100644 --- a/cypress/e2e/27-two-factor-authentication.cy.ts +++ b/cypress/e2e/27-two-factor-authentication.cy.ts @@ -4,6 +4,7 @@ import { MainSidebar } from './../pages/sidebar/main-sidebar'; import { INSTANCE_OWNER, INSTANCE_ADMIN, BACKEND_BASE_URL } from '../constants'; import { SigninPage } from '../pages'; import { MfaLoginPage } from '../pages/mfa-login'; +import { successToast } from '../pages/notifications'; import { PersonalSettingsPage } from '../pages/settings-personal'; const MFA_SECRET = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD'; @@ -81,6 +82,38 @@ describe('Two-factor authentication', { disableAutoLogin: true }, () => { mainSidebar.actions.signout(); }); + it('Should prompt for MFA code when email changes', () => { + const { email, password } = user; + signinPage.actions.loginWithEmailAndPassword(email, password); + personalSettingsPage.actions.enableMfa(); + personalSettingsPage.actions.updateEmail('newemail@test.com'); + const mfaCode = generateOTPToken(user.mfaSecret); + personalSettingsPage.getters.mfaCodeOrMfaRecoveryCodeInput().type(mfaCode); + personalSettingsPage.getters.mfaSaveButton().click(); + successToast().should('exist'); + mainSidebar.actions.signout(); + }); + + it('Should prompt for MFA recovery code when email changes', () => { + const { email, password } = user; + signinPage.actions.loginWithEmailAndPassword(email, password); + personalSettingsPage.actions.enableMfa(); + personalSettingsPage.actions.updateEmail('newemail@test.com'); + personalSettingsPage.getters.mfaCodeOrMfaRecoveryCodeInput().type(RECOVERY_CODE); + personalSettingsPage.getters.mfaSaveButton().click(); + successToast().should('exist'); + mainSidebar.actions.signout(); + }); + + it('Should not prompt for MFA code or recovery code when first name or last name changes', () => { + const { email, password } = user; + signinPage.actions.loginWithEmailAndPassword(email, password); + personalSettingsPage.actions.enableMfa(); + personalSettingsPage.actions.updateFirstAndLastName('newFirstName', 'newLastName'); + successToast().should('exist'); + mainSidebar.actions.signout(); + }); + it('Should be able to disable MFA in account with recovery code', () => { const { email, password } = user; signinPage.actions.loginWithEmailAndPassword(email, password); diff --git a/packages/frontend/editor-ui/src/views/SettingsPersonalView.vue b/packages/frontend/editor-ui/src/views/SettingsPersonalView.vue index bc21fff4c5..17da1a3362 100644 --- a/packages/frontend/editor-ui/src/views/SettingsPersonalView.vue +++ b/packages/frontend/editor-ui/src/views/SettingsPersonalView.vue @@ -151,24 +151,25 @@ async function saveUserSettings(params: UserBasicDetailsWithMfa) { } async function onSubmit(form: UserBasicDetailsForm) { - if (!usersStore.currentUser?.mfaEnabled) { - await saveUserSettings(form); - return; - } + const emailChanged = usersStore.currentUser?.email !== form.email; - uiStore.openModal(PROMPT_MFA_CODE_MODAL_KEY); + if (usersStore.currentUser?.mfaEnabled && emailChanged) { + uiStore.openModal(PROMPT_MFA_CODE_MODAL_KEY); - promptMfaCodeBus.once('closed', async (payload: MfaModalEvents['closed']) => { - if (!payload) { - // User closed the modal without submitting the form - return; - } + promptMfaCodeBus.once('closed', async (payload: MfaModalEvents['closed']) => { + if (!payload) { + // User closed the modal without submitting the form + return; + } - await saveUserSettings({ - ...form, - mfaCode: payload.mfaCode, + await saveUserSettings({ + ...form, + mfaCode: payload.mfaCode, + }); }); - }); + } else { + await saveUserSettings(form); + } } async function updateUserBasicInfo(userBasicInfo: UserBasicDetailsWithMfa) {