From 70706d81e1530ed90ccecb4f2ebf27a8350e90ac Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Tue, 3 Dec 2024 07:15:29 -0500 Subject: [PATCH] refactor: Standardize MFA code and recovery code naming across code base (#12011) --- .../e2e/27-two-factor-authentication.cy.ts | 20 +++--- cypress/pages/mfa-login.ts | 16 ++--- cypress/pages/settings-personal.ts | 6 +- .../cli/src/controllers/auth.controller.ts | 10 +-- packages/cli/src/controllers/me.controller.ts | 8 +-- .../cli/src/controllers/mfa.controller.ts | 20 +++--- .../controllers/password-reset.controller.ts | 6 +- packages/cli/src/mfa/mfa.service.ts | 10 +-- packages/cli/src/mfa/totp.service.ts | 8 ++- packages/cli/src/requests.ts | 10 +-- .../cli/test/integration/auth.api.test.ts | 2 +- .../cli/test/integration/mfa/mfa.api.test.ts | 62 +++++++++---------- packages/editor-ui/src/api/mfa.ts | 11 ++-- packages/editor-ui/src/api/users.ts | 4 +- .../src/components/MfaSetupModal.vue | 12 ++-- .../PromptMfaCodeModal/PromptMfaCodeModal.vue | 2 +- packages/editor-ui/src/constants.ts | 4 +- packages/editor-ui/src/stores/users.store.ts | 14 ++--- .../src/views/ChangePasswordView.vue | 8 +-- packages/editor-ui/src/views/MfaView.vue | 38 ++++++------ .../editor-ui/src/views/SigninView.test.ts | 2 +- packages/editor-ui/src/views/SigninView.vue | 14 ++--- 22 files changed, 150 insertions(+), 137 deletions(-) diff --git a/cypress/e2e/27-two-factor-authentication.cy.ts b/cypress/e2e/27-two-factor-authentication.cy.ts index dc62a0c58c..759964f155 100644 --- a/cypress/e2e/27-two-factor-authentication.cy.ts +++ b/cypress/e2e/27-two-factor-authentication.cy.ts @@ -49,33 +49,35 @@ describe('Two-factor authentication', { disableAutoLogin: true }, () => { cy.intercept('GET', '/rest/mfa/qr').as('getMfaQrCode'); }); - it('Should be able to login with MFA token', () => { + it('Should be able to login with MFA code', () => { const { email, password } = user; signinPage.actions.loginWithEmailAndPassword(email, password); personalSettingsPage.actions.enableMfa(); mainSidebar.actions.signout(); - const token = generateOTPToken(user.mfaSecret); - mfaLoginPage.actions.loginWithMfaToken(email, password, token); + const mfaCode = generateOTPToken(user.mfaSecret); + mfaLoginPage.actions.loginWithMfaCode(email, password, mfaCode); mainSidebar.actions.signout(); }); - it('Should be able to login with recovery code', () => { + it('Should be able to login with MFA recovery code', () => { const { email, password } = user; signinPage.actions.loginWithEmailAndPassword(email, password); personalSettingsPage.actions.enableMfa(); mainSidebar.actions.signout(); - mfaLoginPage.actions.loginWithRecoveryCode(email, password, user.mfaRecoveryCodes[0]); + mfaLoginPage.actions.loginWithMfaRecoveryCode(email, password, user.mfaRecoveryCodes[0]); mainSidebar.actions.signout(); }); - it('Should be able to disable MFA in account', () => { + it('Should be able to disable MFA in account with MFA code ', () => { const { email, password } = user; signinPage.actions.loginWithEmailAndPassword(email, password); personalSettingsPage.actions.enableMfa(); mainSidebar.actions.signout(); - const token = generateOTPToken(user.mfaSecret); - mfaLoginPage.actions.loginWithMfaToken(email, password, token); - personalSettingsPage.actions.disableMfa(); + const loginToken = generateOTPToken(user.mfaSecret); + mfaLoginPage.actions.loginWithMfaCode(email, password, loginToken); + const disableToken = generateOTPToken(user.mfaSecret); + personalSettingsPage.actions.disableMfa(disableToken); + personalSettingsPage.getters.enableMfaButton().should('exist'); mainSidebar.actions.signout(); }); }); diff --git a/cypress/pages/mfa-login.ts b/cypress/pages/mfa-login.ts index 66fc197e3f..7e679804ff 100644 --- a/cypress/pages/mfa-login.ts +++ b/cypress/pages/mfa-login.ts @@ -8,18 +8,18 @@ export class MfaLoginPage extends BasePage { getters = { form: () => cy.getByTestId('mfa-login-form'), - token: () => cy.getByTestId('token'), - recoveryCode: () => cy.getByTestId('recoveryCode'), + mfaCode: () => cy.getByTestId('mfaCode'), + mfaRecoveryCode: () => cy.getByTestId('mfaRecoveryCode'), enterRecoveryCodeButton: () => cy.getByTestId('mfa-enter-recovery-code-button'), }; actions = { - loginWithMfaToken: (email: string, password: string, mfaToken: string) => { + loginWithMfaCode: (email: string, password: string, mfaCode: string) => { const signinPage = new SigninPage(); const workflowsPage = new WorkflowsPage(); cy.session( - [mfaToken], + [mfaCode], () => { cy.visit(signinPage.url); @@ -30,7 +30,7 @@ export class MfaLoginPage extends BasePage { }); this.getters.form().within(() => { - this.getters.token().type(mfaToken); + this.getters.mfaCode().type(mfaCode); }); // we should be redirected to /workflows @@ -43,12 +43,12 @@ export class MfaLoginPage extends BasePage { }, ); }, - loginWithRecoveryCode: (email: string, password: string, recoveryCode: string) => { + loginWithMfaRecoveryCode: (email: string, password: string, mfaRecoveryCode: string) => { const signinPage = new SigninPage(); const workflowsPage = new WorkflowsPage(); cy.session( - [recoveryCode], + [mfaRecoveryCode], () => { cy.visit(signinPage.url); @@ -61,7 +61,7 @@ export class MfaLoginPage extends BasePage { this.getters.enterRecoveryCodeButton().click(); this.getters.form().within(() => { - this.getters.recoveryCode().type(recoveryCode); + this.getters.mfaRecoveryCode().type(mfaRecoveryCode); }); // we should be redirected to /workflows diff --git a/cypress/pages/settings-personal.ts b/cypress/pages/settings-personal.ts index 4574f95691..5602bd7e92 100644 --- a/cypress/pages/settings-personal.ts +++ b/cypress/pages/settings-personal.ts @@ -22,6 +22,8 @@ export class PersonalSettingsPage extends BasePage { saveSettingsButton: () => cy.getByTestId('save-settings-button'), enableMfaButton: () => cy.getByTestId('enable-mfa-button'), disableMfaButton: () => cy.getByTestId('disable-mfa-button'), + mfaCodeOrMfaRecoveryCodeInput: () => cy.getByTestId('mfa-code-or-recovery-code-input'), + mfaSaveButton: () => cy.getByTestId('mfa-save-button'), themeSelector: () => cy.getByTestId('theme-select'), selectOptionsVisible: () => cy.get('.el-select-dropdown:visible .el-select-dropdown__item'), }; @@ -83,9 +85,11 @@ export class PersonalSettingsPage extends BasePage { mfaSetupModal.getters.saveButton().click(); }); }, - disableMfa: () => { + disableMfa: (mfaCodeOrRecoveryCode: string) => { cy.visit(this.url); this.getters.disableMfaButton().click(); + this.getters.mfaCodeOrMfaRecoveryCodeInput().type(mfaCodeOrRecoveryCode); + this.getters.mfaSaveButton().click(); }, }; } diff --git a/packages/cli/src/controllers/auth.controller.ts b/packages/cli/src/controllers/auth.controller.ts index c2ee1c92fb..46ee73a562 100644 --- a/packages/cli/src/controllers/auth.controller.ts +++ b/packages/cli/src/controllers/auth.controller.ts @@ -41,7 +41,7 @@ export class AuthController { /** Log in a user */ @Post('/login', { skipAuth: true, rateLimit: true }) async login(req: LoginRequest, res: Response): Promise { - const { email, password, mfaToken, mfaRecoveryCode } = req.body; + const { email, password, mfaCode, mfaRecoveryCode } = req.body; if (!email) throw new ApplicationError('Email is required to log in'); if (!password) throw new ApplicationError('Password is required to log in'); @@ -75,16 +75,16 @@ export class AuthController { if (user) { if (user.mfaEnabled) { - if (!mfaToken && !mfaRecoveryCode) { + if (!mfaCode && !mfaRecoveryCode) { throw new AuthError('MFA Error', 998); } - const isMFATokenValid = await this.mfaService.validateMfa( + const isMfaCodeOrMfaRecoveryCodeValid = await this.mfaService.validateMfa( user.id, - mfaToken, + mfaCode, mfaRecoveryCode, ); - if (!isMFATokenValid) { + if (!isMfaCodeOrMfaRecoveryCodeValid) { throw new AuthError('Invalid mfa token or recovery code'); } } diff --git a/packages/cli/src/controllers/me.controller.ts b/packages/cli/src/controllers/me.controller.ts index 6cbbda3622..a7fb7235fd 100644 --- a/packages/cli/src/controllers/me.controller.ts +++ b/packages/cli/src/controllers/me.controller.ts @@ -68,8 +68,8 @@ export class MeController { throw new BadRequestError('Two-factor code is required to change email'); } - const isMfaTokenValid = await this.mfaService.validateMfa(userId, payload.mfaCode, undefined); - if (!isMfaTokenValid) { + const isMfaCodeValid = await this.mfaService.validateMfa(userId, payload.mfaCode, undefined); + if (!isMfaCodeValid) { throw new InvalidMfaCodeError(); } } @@ -142,8 +142,8 @@ export class MeController { throw new BadRequestError('Two-factor code is required to change password.'); } - const isMfaTokenValid = await this.mfaService.validateMfa(user.id, mfaCode, undefined); - if (!isMfaTokenValid) { + const isMfaCodeValid = await this.mfaService.validateMfa(user.id, mfaCode, undefined); + if (!isMfaCodeValid) { throw new InvalidMfaCodeError(); } } diff --git a/packages/cli/src/controllers/mfa.controller.ts b/packages/cli/src/controllers/mfa.controller.ts index 694765761c..54e67692ee 100644 --- a/packages/cli/src/controllers/mfa.controller.ts +++ b/packages/cli/src/controllers/mfa.controller.ts @@ -59,7 +59,7 @@ export class MFAController { @Post('/enable', { rateLimit: true }) async activateMFA(req: MFA.Activate) { - const { token = null } = req.body; + const { mfaCode = null } = req.body; const { id, mfaEnabled } = req.user; await this.externalHooks.run('mfa.beforeSetup', [req.user]); @@ -67,7 +67,7 @@ export class MFAController { const { decryptedSecret: secret, decryptedRecoveryCodes: recoveryCodes } = await this.mfaService.getSecretAndRecoveryCodes(id); - if (!token) throw new BadRequestError('Token is required to enable MFA feature'); + if (!mfaCode) throw new BadRequestError('Token is required to enable MFA feature'); if (mfaEnabled) throw new BadRequestError('MFA already enabled'); @@ -75,10 +75,10 @@ export class MFAController { throw new BadRequestError('Cannot enable MFA without generating secret and recovery codes'); } - const verified = this.mfaService.totp.verifySecret({ secret, token, window: 10 }); + const verified = this.mfaService.totp.verifySecret({ secret, mfaCode, window: 10 }); if (!verified) - throw new BadRequestError('MFA token expired. Close the modal and enable MFA again', 997); + throw new BadRequestError('MFA code expired. Close the modal and enable MFA again', 997); await this.mfaService.enableMfa(id); } @@ -86,27 +86,27 @@ export class MFAController { @Post('/disable', { rateLimit: true }) async disableMFA(req: MFA.Disable) { const { id: userId } = req.user; - const { token = null } = req.body; + const { mfaCode = null } = req.body; - if (typeof token !== 'string' || !token) { + if (typeof mfaCode !== 'string' || !mfaCode) { throw new BadRequestError('Token is required to disable MFA feature'); } - await this.mfaService.disableMfa(userId, token); + await this.mfaService.disableMfa(userId, mfaCode); } @Post('/verify', { rateLimit: true }) async verifyMFA(req: MFA.Verify) { const { id } = req.user; - const { token } = req.body; + const { mfaCode } = req.body; const { decryptedSecret: secret } = await this.mfaService.getSecretAndRecoveryCodes(id); - if (!token) throw new BadRequestError('Token is required to enable MFA feature'); + if (!mfaCode) throw new BadRequestError('MFA code is required to enable MFA feature'); if (!secret) throw new BadRequestError('No MFA secret se for this user'); - const verified = this.mfaService.totp.verifySecret({ secret, token }); + const verified = this.mfaService.totp.verifySecret({ secret, mfaCode }); if (!verified) throw new BadRequestError('MFA secret could not be verified'); } diff --git a/packages/cli/src/controllers/password-reset.controller.ts b/packages/cli/src/controllers/password-reset.controller.ts index a14b1f06be..2179ff3d9e 100644 --- a/packages/cli/src/controllers/password-reset.controller.ts +++ b/packages/cli/src/controllers/password-reset.controller.ts @@ -171,7 +171,7 @@ export class PasswordResetController { */ @Post('/change-password', { skipAuth: true }) async changePassword(req: PasswordResetRequest.NewPassword, res: Response) { - const { token, password, mfaToken } = req.body; + const { token, password, mfaCode } = req.body; if (!token || !password) { this.logger.debug( @@ -189,11 +189,11 @@ export class PasswordResetController { if (!user) throw new NotFoundError(''); if (user.mfaEnabled) { - if (!mfaToken) throw new BadRequestError('If MFA enabled, mfaToken is required.'); + if (!mfaCode) throw new BadRequestError('If MFA enabled, mfaCode is required.'); const { decryptedSecret: secret } = await this.mfaService.getSecretAndRecoveryCodes(user.id); - const validToken = this.mfaService.totp.verifySecret({ secret, token: mfaToken }); + const validToken = this.mfaService.totp.verifySecret({ secret, mfaCode }); if (!validToken) throw new BadRequestError('Invalid MFA token.'); } diff --git a/packages/cli/src/mfa/mfa.service.ts b/packages/cli/src/mfa/mfa.service.ts index 5f730b7bf1..afce8927f9 100644 --- a/packages/cli/src/mfa/mfa.service.ts +++ b/packages/cli/src/mfa/mfa.service.ts @@ -56,13 +56,13 @@ export class MfaService { async validateMfa( userId: string, - mfaToken: string | undefined, + mfaCode: string | undefined, mfaRecoveryCode: string | undefined, ) { const user = await this.authUserRepository.findOneByOrFail({ id: userId }); - if (mfaToken) { + if (mfaCode) { const decryptedSecret = this.cipher.decrypt(user.mfaSecret!); - return this.totp.verifySecret({ secret: decryptedSecret, token: mfaToken }); + return this.totp.verifySecret({ secret: decryptedSecret, mfaCode }); } if (mfaRecoveryCode) { @@ -85,8 +85,8 @@ export class MfaService { return await this.authUserRepository.save(user); } - async disableMfa(userId: string, mfaToken: string) { - const isValidToken = await this.validateMfa(userId, mfaToken, undefined); + async disableMfa(userId: string, mfaCode: string) { + const isValidToken = await this.validateMfa(userId, mfaCode, undefined); if (!isValidToken) { throw new InvalidMfaCodeError(); } diff --git a/packages/cli/src/mfa/totp.service.ts b/packages/cli/src/mfa/totp.service.ts index cbb1f65aac..ec9f651635 100644 --- a/packages/cli/src/mfa/totp.service.ts +++ b/packages/cli/src/mfa/totp.service.ts @@ -23,10 +23,14 @@ export class TOTPService { }).toString(); } - verifySecret({ secret, token, window = 2 }: { secret: string; token: string; window?: number }) { + verifySecret({ + secret, + mfaCode, + window = 2, + }: { secret: string; mfaCode: string; window?: number }) { return new OTPAuth.TOTP({ secret: OTPAuth.Secret.fromBase32(secret), - }).validate({ token, window }) === null + }).validate({ token: mfaCode, window }) === null ? false : true; } diff --git a/packages/cli/src/requests.ts b/packages/cli/src/requests.ts index f233d7db46..72d6fcf135 100644 --- a/packages/cli/src/requests.ts +++ b/packages/cli/src/requests.ts @@ -228,7 +228,7 @@ export declare namespace PasswordResetRequest { export type NewPassword = AuthlessRequest< {}, {}, - Pick & { token?: string; userId?: string; mfaToken?: string } + Pick & { token?: string; userId?: string; mfaCode?: string } >; } @@ -306,7 +306,7 @@ export type LoginRequest = AuthlessRequest< { email: string; password: string; - mfaToken?: string; + mfaCode?: string; mfaRecoveryCode?: string; } >; @@ -316,9 +316,9 @@ export type LoginRequest = AuthlessRequest< // ---------------------------------- export declare namespace MFA { - type Verify = AuthenticatedRequest<{}, {}, { token: string }, {}>; - type Activate = AuthenticatedRequest<{}, {}, { token: string }, {}>; - type Disable = AuthenticatedRequest<{}, {}, { token: string }, {}>; + type Verify = AuthenticatedRequest<{}, {}, { mfaCode: string }, {}>; + type Activate = AuthenticatedRequest<{}, {}, { mfaCode: string }, {}>; + type Disable = AuthenticatedRequest<{}, {}, { mfaCode: string }, {}>; type Config = AuthenticatedRequest<{}, {}, { login: { enabled: boolean } }, {}>; type ValidateRecoveryCode = AuthenticatedRequest< {}, diff --git a/packages/cli/test/integration/auth.api.test.ts b/packages/cli/test/integration/auth.api.test.ts index 2880526668..6c1ddc5892 100644 --- a/packages/cli/test/integration/auth.api.test.ts +++ b/packages/cli/test/integration/auth.api.test.ts @@ -89,7 +89,7 @@ describe('POST /login', () => { const response = await testServer.authlessAgent.post('/login').send({ email: owner.email, password: ownerPassword, - mfaToken: mfaService.totp.generateTOTP(secret), + mfaCode: mfaService.totp.generateTOTP(secret), }); expect(response.statusCode).toBe(200); diff --git a/packages/cli/test/integration/mfa/mfa.api.test.ts b/packages/cli/test/integration/mfa/mfa.api.test.ts index 3f19632506..95c3334277 100644 --- a/packages/cli/test/integration/mfa/mfa.api.test.ts +++ b/packages/cli/test/integration/mfa/mfa.api.test.ts @@ -55,8 +55,8 @@ describe('Enable MFA setup', () => { secondCall.body.data.recoveryCodes.join(''), ); - const token = new TOTPService().generateTOTP(firstCall.body.data.secret); - await testServer.authAgentFor(owner).post('/mfa/disable').send({ token }).expect(200); + const mfaCode = new TOTPService().generateTOTP(firstCall.body.data.secret); + await testServer.authAgentFor(owner).post('/mfa/disable').send({ mfaCode }).expect(200); const thirdCall = await testServer.authAgentFor(owner).get('/mfa/qr').expect(200); @@ -84,22 +84,22 @@ describe('Enable MFA setup', () => { await testServer.authlessAgent.post('/mfa/verify').expect(401); }); - test('POST /verify should fail due to invalid MFA token', async () => { - await testServer.authAgentFor(owner).post('/mfa/verify').send({ token: '123' }).expect(400); + test('POST /verify should fail due to invalid MFA code', async () => { + await testServer.authAgentFor(owner).post('/mfa/verify').send({ mfaCode: '123' }).expect(400); }); - test('POST /verify should fail due to missing token parameter', async () => { + test('POST /verify should fail due to missing mfaCode parameter', async () => { await testServer.authAgentFor(owner).get('/mfa/qr').expect(200); - await testServer.authAgentFor(owner).post('/mfa/verify').send({ token: '' }).expect(400); + await testServer.authAgentFor(owner).post('/mfa/verify').send({ mfaCode: '' }).expect(400); }); - test('POST /verify should validate MFA token', async () => { + test('POST /verify should validate MFA code', async () => { const response = await testServer.authAgentFor(owner).get('/mfa/qr').expect(200); const { secret } = response.body.data; - const token = new TOTPService().generateTOTP(secret); + const mfaCode = new TOTPService().generateTOTP(secret); - await testServer.authAgentFor(owner).post('/mfa/verify').send({ token }).expect(200); + await testServer.authAgentFor(owner).post('/mfa/verify').send({ mfaCode }).expect(200); }); }); @@ -108,13 +108,13 @@ describe('Enable MFA setup', () => { await testServer.authlessAgent.post('/mfa/enable').expect(401); }); - test('POST /verify should fail due to missing token parameter', async () => { - await testServer.authAgentFor(owner).post('/mfa/verify').send({ token: '' }).expect(400); + test('POST /verify should fail due to missing mfaCode parameter', async () => { + await testServer.authAgentFor(owner).post('/mfa/verify').send({ mfaCode: '' }).expect(400); }); - test('POST /enable should fail due to invalid MFA token', async () => { + test('POST /enable should fail due to invalid MFA code', async () => { await testServer.authAgentFor(owner).get('/mfa/qr').expect(200); - await testServer.authAgentFor(owner).post('/mfa/enable').send({ token: '123' }).expect(400); + await testServer.authAgentFor(owner).post('/mfa/enable').send({ mfaCode: '123' }).expect(400); }); test('POST /enable should fail due to empty secret and recovery codes', async () => { @@ -125,10 +125,10 @@ describe('Enable MFA setup', () => { const response = await testServer.authAgentFor(owner).get('/mfa/qr').expect(200); const { secret } = response.body.data; - const token = new TOTPService().generateTOTP(secret); + const mfaCode = new TOTPService().generateTOTP(secret); - await testServer.authAgentFor(owner).post('/mfa/verify').send({ token }).expect(200); - await testServer.authAgentFor(owner).post('/mfa/enable').send({ token }).expect(200); + await testServer.authAgentFor(owner).post('/mfa/verify').send({ mfaCode }).expect(200); + await testServer.authAgentFor(owner).post('/mfa/enable').send({ mfaCode }).expect(200); const user = await Container.get(AuthUserRepository).findOneOrFail({ where: {}, @@ -145,13 +145,13 @@ describe('Enable MFA setup', () => { const response = await testServer.authAgentFor(owner).get('/mfa/qr').expect(200); const { secret } = response.body.data; - const token = new TOTPService().generateTOTP(secret); + const mfaCode = new TOTPService().generateTOTP(secret); - await testServer.authAgentFor(owner).post('/mfa/verify').send({ token }).expect(200); + await testServer.authAgentFor(owner).post('/mfa/verify').send({ mfaCode }).expect(200); externalHooks.run.mockRejectedValue(new BadRequestError('Error message')); - await testServer.authAgentFor(owner).post('/mfa/enable').send({ token }).expect(400); + await testServer.authAgentFor(owner).post('/mfa/enable').send({ mfaCode }).expect(400); const user = await Container.get(AuthUserRepository).findOneOrFail({ where: {}, @@ -165,13 +165,13 @@ describe('Enable MFA setup', () => { describe('Disable MFA setup', () => { test('POST /disable should disable login with MFA', async () => { const { user, rawSecret } = await createUserWithMfaEnabled(); - const token = new TOTPService().generateTOTP(rawSecret); + const mfaCode = new TOTPService().generateTOTP(rawSecret); await testServer .authAgentFor(user) .post('/mfa/disable') .send({ - token, + mfaCode, }) .expect(200); @@ -184,21 +184,21 @@ describe('Disable MFA setup', () => { expect(dbUser.mfaRecoveryCodes.length).toBe(0); }); - test('POST /disable should fail if invalid token is given', async () => { + test('POST /disable should fail if invalid mfaCode is given', async () => { const { user } = await createUserWithMfaEnabled(); await testServer .authAgentFor(user) .post('/mfa/disable') .send({ - token: 'invalid token', + mfaCode: 'invalid token', }) .expect(403); }); }); describe('Change password with MFA enabled', () => { - test('POST /change-password should fail due to missing MFA token', async () => { + test('POST /change-password should fail due to missing MFA code', async () => { await createUserWithMfaEnabled(); const newPassword = randomValidPassword(); @@ -210,7 +210,7 @@ describe('Change password with MFA enabled', () => { .expect(404); }); - test('POST /change-password should fail due to invalid MFA token', async () => { + test('POST /change-password should fail due to invalid MFA code', async () => { await createUserWithMfaEnabled(); const newPassword = randomValidPassword(); @@ -221,7 +221,7 @@ describe('Change password with MFA enabled', () => { .send({ password: newPassword, token: resetPasswordToken, - mfaToken: randomInt(10), + mfaCode: randomInt(10), }) .expect(404); }); @@ -235,14 +235,14 @@ describe('Change password with MFA enabled', () => { const resetPasswordToken = Container.get(AuthService).generatePasswordResetToken(user); - const mfaToken = new TOTPService().generateTOTP(rawSecret); + const mfaCode = new TOTPService().generateTOTP(rawSecret); await testServer.authlessAgent .post('/change-password') .send({ password: newPassword, token: resetPasswordToken, - mfaToken, + mfaCode, }) .expect(200); @@ -252,7 +252,7 @@ describe('Change password with MFA enabled', () => { .send({ email: user.email, password: newPassword, - mfaToken: new TOTPService().generateTOTP(rawSecret), + mfaCode: new TOTPService().generateTOTP(rawSecret), }) .expect(200); @@ -315,7 +315,7 @@ describe('Login', () => { await testServer.authlessAgent .post('/login') - .send({ email: user.email, password: rawPassword, mfaToken: 'wrongvalue' }) + .send({ email: user.email, password: rawPassword, mfaCode: 'wrongvalue' }) .expect(401); }); @@ -337,7 +337,7 @@ describe('Login', () => { const response = await testServer.authlessAgent .post('/login') - .send({ email: user.email, password: rawPassword, mfaToken: token }) + .send({ email: user.email, password: rawPassword, mfaCode: token }) .expect(200); const data = response.body.data; diff --git a/packages/editor-ui/src/api/mfa.ts b/packages/editor-ui/src/api/mfa.ts index 0cce31c96d..a28e2146b1 100644 --- a/packages/editor-ui/src/api/mfa.ts +++ b/packages/editor-ui/src/api/mfa.ts @@ -11,19 +11,22 @@ export async function getMfaQR( return await makeRestApiRequest(context, 'GET', '/mfa/qr'); } -export async function enableMfa(context: IRestApiContext, data: { token: string }): Promise { +export async function enableMfa( + context: IRestApiContext, + data: { mfaCode: string }, +): Promise { return await makeRestApiRequest(context, 'POST', '/mfa/enable', data); } -export async function verifyMfaToken( +export async function verifyMfaCode( context: IRestApiContext, - data: { token: string }, + data: { mfaCode: string }, ): Promise { return await makeRestApiRequest(context, 'POST', '/mfa/verify', data); } export type DisableMfaParams = { - token: string; + mfaCode: string; }; export async function disableMfa(context: IRestApiContext, data: DisableMfaParams): Promise { diff --git a/packages/editor-ui/src/api/users.ts b/packages/editor-ui/src/api/users.ts index ea14cb6c79..bff4f65fac 100644 --- a/packages/editor-ui/src/api/users.ts +++ b/packages/editor-ui/src/api/users.ts @@ -21,7 +21,7 @@ export async function loginCurrentUser( export async function login( context: IRestApiContext, - params: { email: string; password: string; mfaToken?: string; mfaRecoveryToken?: string }, + params: { email: string; password: string; mfaCode?: string; mfaRecoveryToken?: string }, ): Promise { return await makeRestApiRequest(context, 'POST', '/login', params); } @@ -84,7 +84,7 @@ export async function validatePasswordToken( export async function changePassword( context: IRestApiContext, - params: { token: string; password: string; mfaToken?: string }, + params: { token: string; password: string; mfaCode?: string }, ): Promise { await makeRestApiRequest(context, 'POST', '/change-password', params); } diff --git a/packages/editor-ui/src/components/MfaSetupModal.vue b/packages/editor-ui/src/components/MfaSetupModal.vue index 9f292124c3..77f1d88648 100644 --- a/packages/editor-ui/src/components/MfaSetupModal.vue +++ b/packages/editor-ui/src/components/MfaSetupModal.vue @@ -1,8 +1,8 @@