mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-20 11:22:15 +00:00
fix: Allow disabling MFA with recovery codes (#12014)
Co-authored-by: Tomi Turtiainen <10324676+tomi@users.noreply.github.com>
This commit is contained in:
@@ -26,7 +26,8 @@ export async function verifyMfaCode(
|
||||
}
|
||||
|
||||
export type DisableMfaParams = {
|
||||
mfaCode: string;
|
||||
mfaCode?: string;
|
||||
mfaRecoveryCode?: string;
|
||||
};
|
||||
|
||||
export async function disableMfa(context: IRestApiContext, data: DisableMfaParams): Promise<void> {
|
||||
|
||||
@@ -6,6 +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 validateUuid } from 'uuid';
|
||||
|
||||
const i18n = useI18n();
|
||||
|
||||
@@ -14,11 +15,11 @@ const readyToSubmit = ref(false);
|
||||
|
||||
const formFields: IFormInputs = [
|
||||
{
|
||||
name: 'mfaCode',
|
||||
name: 'mfaCodeOrMfaRecoveryCode',
|
||||
initialValue: '',
|
||||
properties: {
|
||||
label: i18n.baseText('mfa.code.input.label'),
|
||||
placeholder: i18n.baseText('mfa.code.input.placeholder'),
|
||||
label: i18n.baseText('mfa.code.recovery.input.label'),
|
||||
placeholder: i18n.baseText('mfa.code.recovery.input.placeholder'),
|
||||
focusInitially: true,
|
||||
capitalize: true,
|
||||
required: true,
|
||||
@@ -26,9 +27,15 @@ const formFields: IFormInputs = [
|
||||
},
|
||||
];
|
||||
|
||||
function onSubmit(values: { mfaCode: string }) {
|
||||
function onSubmit(values: { mfaCodeOrMfaRecoveryCode: string }) {
|
||||
if (validateUuid(values.mfaCodeOrMfaRecoveryCode)) {
|
||||
promptMfaCodeBus.emit('close', {
|
||||
mfaRecoveryCode: values.mfaCodeOrMfaRecoveryCode,
|
||||
});
|
||||
return;
|
||||
}
|
||||
promptMfaCodeBus.emit('close', {
|
||||
mfaCode: values.mfaCode,
|
||||
mfaCode: values.mfaCodeOrMfaRecoveryCode,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,7 +50,7 @@ function onFormReady(isReady: boolean) {
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
width="460px"
|
||||
width="500px"
|
||||
height="300px"
|
||||
max-height="640px"
|
||||
:title="i18n.baseText('mfa.prompt.code.modal.title')"
|
||||
|
||||
@@ -3,7 +3,8 @@ import { createEventBus } from 'n8n-design-system/utils';
|
||||
export const mfaEventBus = createEventBus();
|
||||
|
||||
export interface MfaModalClosedEventPayload {
|
||||
mfaCode: string;
|
||||
mfaCode?: string;
|
||||
mfaRecoveryCode?: string;
|
||||
}
|
||||
|
||||
export interface MfaModalEvents {
|
||||
|
||||
@@ -2596,7 +2596,9 @@
|
||||
"mfa.button.back": "Back",
|
||||
"mfa.code.input.label": "Two-factor code",
|
||||
"mfa.code.input.placeholder": "e.g. 123456",
|
||||
"mfa.recovery.input.label": "Recovery Code",
|
||||
"mfa.code.recovery.input.label": "Two-factor code or recovery code",
|
||||
"mfa.code.recovery.input.placeholder": "e.g. 123456 or c79f9c02-7b2e-44...",
|
||||
"mfa.recovery.input.label": "Recovery code",
|
||||
"mfa.recovery.input.placeholder": "e.g c79f9c02-7b2e-44...",
|
||||
"mfa.code.invalid": "This code is invalid, try again or",
|
||||
"mfa.recovery.invalid": "This code is invalid or was already used, try again",
|
||||
@@ -2620,7 +2622,7 @@
|
||||
"mfa.setup.step2.toast.setupFinished.message": "Two-factor authentication enabled",
|
||||
"mfa.setup.step2.toast.setupFinished.error.message": "Error enabling two-factor authentication",
|
||||
"mfa.setup.step2.toast.tokenExpired.error.message": "MFA token expired. Close the modal and enable MFA again",
|
||||
"mfa.prompt.code.modal.title": "Two-factor code required",
|
||||
"mfa.prompt.code.modal.title": "Two-factor code or recovery code required",
|
||||
"settings.personal.mfa.section.title": "Two-factor authentication (2FA)",
|
||||
"settings.personal.personalisation": "Personalisation",
|
||||
"settings.personal.theme": "Theme",
|
||||
|
||||
@@ -331,10 +331,8 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
|
||||
}
|
||||
};
|
||||
|
||||
const disableMfa = async (mfaCode: string) => {
|
||||
await mfaApi.disableMfa(rootStore.restApiContext, {
|
||||
mfaCode,
|
||||
});
|
||||
const disableMfa = async (data: mfaApi.DisableMfaParams) => {
|
||||
await mfaApi.disableMfa(rootStore.restApiContext, data);
|
||||
|
||||
if (currentUser.value) {
|
||||
currentUser.value.mfaEnabled = false;
|
||||
|
||||
@@ -226,7 +226,7 @@ async function disableMfa(payload: MfaModalEvents['closed']) {
|
||||
}
|
||||
|
||||
try {
|
||||
await usersStore.disableMfa(payload.mfaCode);
|
||||
await usersStore.disableMfa(payload);
|
||||
|
||||
showToast({
|
||||
title: i18n.baseText('settings.personal.mfa.toast.disabledMfa.title'),
|
||||
|
||||
Reference in New Issue
Block a user