mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
Apply feedback
This commit is contained in:
parent
a0afd32413
commit
afe75f3b8f
|
@ -22,7 +22,7 @@ export class PersonalSettingsPage extends BasePage {
|
|||
saveSettingsButton: () => cy.getByTestId('save-settings-button'),
|
||||
enableMfaButton: () => cy.getByTestId('enable-mfa-button'),
|
||||
disableMfaButton: () => cy.getByTestId('disable-mfa-button'),
|
||||
mfaCodeInput: () => cy.getByTestId('mfa-code-input'),
|
||||
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'),
|
||||
|
@ -85,10 +85,10 @@ export class PersonalSettingsPage extends BasePage {
|
|||
mfaSetupModal.getters.saveButton().click();
|
||||
});
|
||||
},
|
||||
disableMfa: (code: string) => {
|
||||
disableMfa: (mfaCodeOrRecoveryCode: string) => {
|
||||
cy.visit(this.url);
|
||||
this.getters.disableMfaButton().click();
|
||||
this.getters.mfaCodeInput().type(code);
|
||||
this.getters.mfaCodeOrMfaRecoveryCodeInput().type(mfaCodeOrRecoveryCode);
|
||||
this.getters.mfaSaveButton().click();
|
||||
},
|
||||
};
|
||||
|
|
|
@ -79,8 +79,12 @@ export class AuthController {
|
|||
throw new AuthError('MFA Error', 998);
|
||||
}
|
||||
|
||||
const isMFACodeValid = await this.mfaService.validateMfa(user.id, mfaCode, mfaRecoveryCode);
|
||||
if (!isMFACodeValid) {
|
||||
const isMFACodeOrMfaRecoveryCodeValid = await this.mfaService.validateMfa(
|
||||
user.id,
|
||||
mfaCode,
|
||||
mfaRecoveryCode,
|
||||
);
|
||||
if (!isMFACodeOrMfaRecoveryCodeValid) {
|
||||
throw new AuthError('Invalid mfa token or recovery code');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,10 @@ export class MFAController {
|
|||
|
||||
const { mfaCode, mfaRecoveryCode } = req.body;
|
||||
|
||||
if (!mfaCode && !mfaRecoveryCode) {
|
||||
throw new BadRequestError('MFA code or recovery code is required to disable MFA feature');
|
||||
}
|
||||
|
||||
if (mfaCode && typeof mfaCode === 'string') {
|
||||
await this.mfaService.disableMfaWithMfaCode(userId, mfaCode);
|
||||
} else if (mfaRecoveryCode && typeof mfaRecoveryCode === 'string') {
|
||||
|
|
|
@ -87,7 +87,7 @@ export class MfaService {
|
|||
}
|
||||
|
||||
async disableMfaWithMfaCode(userId: string, mfaCode: string) {
|
||||
const isValidToken = await this.validateMfa(userId, mfaCode, '');
|
||||
const isValidToken = await this.validateMfa(userId, mfaCode, undefined);
|
||||
|
||||
if (!isValidToken) {
|
||||
throw new InvalidMfaCodeError();
|
||||
|
@ -97,7 +97,7 @@ export class MfaService {
|
|||
}
|
||||
|
||||
async disableMfaWithRecoveryCode(userId: string, recoveryCode: string) {
|
||||
const isValidToken = await this.validateMfa(userId, '', recoveryCode);
|
||||
const isValidToken = await this.validateMfa(userId, undefined, recoveryCode);
|
||||
|
||||
if (!isValidToken) {
|
||||
throw new InvalidMfaRecoveryCodeError();
|
||||
|
|
|
@ -207,6 +207,12 @@ describe('Disable MFA setup', () => {
|
|||
})
|
||||
.expect(403);
|
||||
});
|
||||
|
||||
test('POST /disable should fail if neither MFA code nor recovery code is sent', async () => {
|
||||
const { user } = await createUserWithMfaEnabled();
|
||||
|
||||
await testServer.authAgentFor(user).post('/mfa/disable').send({ anotherParam: '' }).expect(400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Change password with MFA enabled', () => {
|
||||
|
|
|
@ -6,7 +6,7 @@ import { useI18n } from '@/composables/useI18n';
|
|||
import { promptMfaCodeBus } from '@/event-bus';
|
||||
import type { IFormInputs } from '@/Interface';
|
||||
import { createFormEventBus } from 'n8n-design-system';
|
||||
import { validate as uuidValidate } from 'uuid';
|
||||
import { validate as validateUuid } from 'uuid';
|
||||
|
||||
const i18n = useI18n();
|
||||
|
||||
|
@ -15,7 +15,7 @@ const readyToSubmit = ref(false);
|
|||
|
||||
const formFields: IFormInputs = [
|
||||
{
|
||||
name: 'code',
|
||||
name: 'mfaCodeOrMfaRecoveryCode',
|
||||
initialValue: '',
|
||||
properties: {
|
||||
label: i18n.baseText('mfa.code.recovery.input.label'),
|
||||
|
@ -28,7 +28,7 @@ const formFields: IFormInputs = [
|
|||
];
|
||||
|
||||
function onSubmit(values: { code: string }) {
|
||||
if (uuidValidate(values.code)) {
|
||||
if (validateUuid(values.code)) {
|
||||
promptMfaCodeBus.emit('close', {
|
||||
mfaRecoveryCode: values.code,
|
||||
});
|
||||
|
@ -63,7 +63,7 @@ function onFormReady(isReady: boolean) {
|
|||
<template #content>
|
||||
<div :class="[$style.formContainer]">
|
||||
<n8n-form-inputs
|
||||
data-test-id="mfa-code-input"
|
||||
data-test-id="mfa-code-or-recovery-code-input"
|
||||
:inputs="formFields"
|
||||
:event-bus="formBus"
|
||||
@submit="onSubmit"
|
||||
|
|
|
@ -106,7 +106,7 @@ const onSubmit = async (form: { mfaCode: string; mfaRecoveryCode: string }) => {
|
|||
};
|
||||
|
||||
const onInput = ({ target: { value, name } }: { target: { value: string; name: string } }) => {
|
||||
const isSubmittingMfaCode = name === 'mfaToken';
|
||||
const isSubmittingMfaCode = name === 'mfaCode';
|
||||
const inputValidLength = isSubmittingMfaCode
|
||||
? MFA_AUTHENTICATION_TOKEN_INPUT_MAX_LENGTH
|
||||
: MFA_AUTHENTICATION_RECOVERY_CODE_INPUT_MAX_LENGTH;
|
||||
|
@ -139,7 +139,7 @@ const mfaRecoveryCodeFieldWithDefaults = () => {
|
|||
|
||||
const mfaCodeFieldWithDefaults = () => {
|
||||
return formField(
|
||||
'mfaToken',
|
||||
'mfaCode',
|
||||
i18.baseText('mfa.code.input.label'),
|
||||
i18.baseText('mfa.code.input.placeholder'),
|
||||
MFA_AUTHENTICATION_TOKEN_INPUT_MAX_LENGTH,
|
||||
|
|
Loading…
Reference in a new issue