Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): Add MFA #4767

Merged
merged 200 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
200 commits
Select commit Hold shift + click to select a range
b38a0e1
:zap: MFA initial setup
RicardoE105 Nov 29, 2022
c5aee5a
Sync master
RicardoE105 Dec 1, 2022
0bd40cf
Sync master
RicardoE105 Jan 9, 2023
7446db2
Sync master
RicardoE105 Jan 31, 2023
b528dbf
update lock file
RicardoE105 Jan 31, 2023
215b208
fix merge issues
RicardoE105 Jan 31, 2023
5818d29
:zap: Improvements
RicardoE105 Feb 2, 2023
75d5ae3
Improvements
RicardoE105 Feb 9, 2023
31a13fa
Improvements
RicardoE105 Feb 13, 2023
cbc284e
sync master
RicardoE105 Feb 14, 2023
a59ebc4
update lock file
RicardoE105 Feb 14, 2023
e2c9de9
sync master
RicardoE105 Feb 15, 2023
4c60a76
Improvements
RicardoE105 Feb 16, 2023
79c0668
:zap: Improvements
RicardoE105 Feb 17, 2023
3c79b13
:zap: Improvements
RicardoE105 Feb 17, 2023
5fc0706
:zap: Improvements
RicardoE105 Feb 19, 2023
033b808
Sync master
RicardoE105 Feb 20, 2023
9a3d8d4
update lock file
RicardoE105 Feb 20, 2023
805901e
:fire: Remove old MfaSetupView
RicardoE105 Feb 21, 2023
e00723d
:fire: Remove duplicated route
RicardoE105 Feb 21, 2023
bae5c09
:zap: Add loading state to modal
RicardoE105 Feb 21, 2023
280863d
:zap: Update MFA migration timestamp
RicardoE105 Feb 21, 2023
fd7d8df
:zap: Add adi improvements
RicardoE105 Feb 21, 2023
ec1f43a
:zap: simplify MFA migration
RicardoE105 Feb 21, 2023
950221b
:zap: Reset recovery codes once MFA is disabled
RicardoE105 Feb 21, 2023
805b856
:bug: Fix small bug
RicardoE105 Feb 21, 2023
d8463d4
:bug: Fix MFA enable success toast
RicardoE105 Feb 21, 2023
b4180b9
:zap: Show toast when all recovery codes were used
RicardoE105 Feb 21, 2023
596de6f
:zap: Add missing i18n labels
RicardoE105 Feb 21, 2023
904f001
:zap: Apply review feedback
RicardoE105 Feb 22, 2023
c864591
fix issue setting "hasRecoveryCodeLeft" flag
RicardoE105 Feb 22, 2023
c6f486a
:zap: Small improvement
RicardoE105 Feb 22, 2023
8d500e5
sync master
RicardoE105 Feb 22, 2023
58196fb
update lock file
RicardoE105 Feb 22, 2023
e0b2eb9
update MFA migration timestamp
RicardoE105 Feb 22, 2023
107ad54
update the lockfile
netroy Feb 23, 2023
c8deff6
fix the tests
netroy Feb 23, 2023
4a7bcc1
add postgres and mysql migrations
netroy Feb 23, 2023
4ba5c35
Remove br from MfaView
RicardoE105 Feb 23, 2023
76a30cf
Remove icon from infobox
RicardoE105 Feb 23, 2023
6a35b1f
:zap: Add tests
RicardoE105 Feb 23, 2023
eedc6e9
Add missing tests
RicardoE105 Feb 23, 2023
a8de3a7
:zap: Add telemetry
RicardoE105 Feb 24, 2023
259d4e8
Remove duplication
RicardoE105 Feb 24, 2023
79dab61
Small improvement
RicardoE105 Feb 24, 2023
bace508
Isolate speakeasy library
RicardoE105 Feb 24, 2023
8e882dc
:fire: Remove unnecessary constant
RicardoE105 Feb 26, 2023
417d338
Sync master
RicardoE105 Feb 26, 2023
64bb66d
:zap: encrypt secret and recovery codes
RicardoE105 Feb 26, 2023
106a32a
Update migrations timestamp
RicardoE105 Feb 27, 2023
e07099e
:zap: apply feedback
RicardoE105 Feb 28, 2023
85651f6
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 Mar 1, 2023
1701a78
:bug: Fix merge issue
RicardoE105 Mar 1, 2023
53863b7
add e2e tests
RicardoE105 Mar 3, 2023
372d9d5
Sync master
RicardoE105 Mar 4, 2023
3c61dba
update lock file
RicardoE105 Mar 4, 2023
f0625fc
:zap: Only retrieve mfaSecret and mfaRecoveryCodes when needed
RicardoE105 Mar 8, 2023
2bbfefb
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 Mar 8, 2023
e651f4e
:bug: Fix bug with protectFromPhishing function
RicardoE105 Mar 8, 2023
525139c
:fire: remove console.log
RicardoE105 Mar 8, 2023
c37fe76
adjust mfa telemetry
RicardoE105 Mar 8, 2023
4671db0
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 Mar 10, 2023
adee046
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 Mar 13, 2023
1c92fa0
rename phishingAttempt to isRedirectSafe
RicardoE105 Mar 13, 2023
ad37a49
remove unnecessary import
RicardoE105 Mar 13, 2023
b5dcad9
inject mfaService to authentication controller
RicardoE105 Mar 13, 2023
3f4cad8
fix linting issue
RicardoE105 Mar 14, 2023
c5332d2
fix formatting issue
RicardoE105 Mar 14, 2023
59ab944
Merge remote-tracking branch 'upstream/master' into ado-21-sync-curre…
netroy Mar 21, 2023
1cde167
Fix select for postgres and mysql
RicardoE105 Mar 22, 2023
ba6d3c0
Sync master
RicardoE105 Mar 28, 2023
9bf3a33
updat lock file
RicardoE105 Mar 28, 2023
7e575f3
Update migration timestamps
RicardoE105 Mar 28, 2023
a32f7ad
Extend verification window when enabling MFA
RicardoE105 Mar 28, 2023
0aeb530
Show error message when token validation window expired
RicardoE105 Mar 28, 2023
ea17d16
add mfa:disable CLI command
RicardoE105 Mar 28, 2023
cc0e1f1
Fix linting issues
RicardoE105 Mar 28, 2023
195f42e
Fix mysql migration
RicardoE105 Mar 28, 2023
52ed14b
fix linting issue
RicardoE105 Mar 28, 2023
6d647c5
add issuer to QR URL
RicardoE105 Mar 29, 2023
66ed032
cypress-otp should be a devDependency
netroy Mar 29, 2023
02fcfaf
Merge remote-tracking branch 'upstream/master' into ado-21-sync-curre…
netroy Mar 29, 2023
cf491c1
Merge remote-tracking branch 'upstream/master' into ado-21-sync-curre…
netroy Mar 30, 2023
a4dbfbb
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 Apr 2, 2023
3ee10de
Sync master
RicardoE105 Apr 3, 2023
c8dd21f
Apply feedback
RicardoE105 Apr 4, 2023
7b4b86a
Make e2e tests independent
RicardoE105 Apr 4, 2023
12f30fe
Allow to disable MFA feature in instance
RicardoE105 Apr 4, 2023
75257f9
Sync master
RicardoE105 Apr 4, 2023
2f20029
access to mfa.enable optionally
RicardoE105 Apr 4, 2023
1087e5f
Ask for MFA token when resetting password
RicardoE105 Apr 5, 2023
317589a
fix linting issues
RicardoE105 Apr 5, 2023
713af91
Make change password tests pass
RicardoE105 Apr 5, 2023
ce075f6
Add BE tests for change password endpoints
RicardoE105 Apr 5, 2023
109c5aa
Apply formatting to MFA tests
RicardoE105 Apr 5, 2023
18f5fb8
Remove duplicated tests
RicardoE105 Apr 5, 2023
47c90c3
Fix me.controller.test to account for mfa changes
RicardoE105 Apr 5, 2023
7434abe
Tiny refactor to tests utils
RicardoE105 Apr 5, 2023
b2388c0
Remove test.only in mfa tests
RicardoE105 Apr 5, 2023
3dfefc0
fix linting issues
RicardoE105 Apr 5, 2023
251677b
Move MFA fields length to constant file
RicardoE105 Apr 5, 2023
7697a73
centralize MFA helpers in one service and refactor
RicardoE105 Apr 6, 2023
c55a2e1
Make change-password form labels sentence case
RicardoE105 Apr 6, 2023
542077d
Remove unnecessary import
RicardoE105 Apr 6, 2023
0e96f5c
Parse mfaEnable query-string parameter correctly
RicardoE105 Apr 6, 2023
b55ed7f
fix tests
RicardoE105 Apr 6, 2023
3a138bd
Switch speakeasy for otpauth
RicardoE105 Apr 6, 2023
d0c3050
Fix typing issues
RicardoE105 Apr 6, 2023
6502c54
Fix tests
RicardoE105 Apr 6, 2023
1ce51c2
Sync master
RicardoE105 Apr 11, 2023
7aa7788
update pnpm-lock.yaml
RicardoE105 Apr 11, 2023
2fdd38e
Sync master
RicardoE105 Apr 13, 2023
ca89223
Add mfa.update external hooks to MFA controller
RicardoE105 Apr 17, 2023
369ba48
Migrate modals to use createEventBus
RicardoE105 Apr 17, 2023
e6af4c8
Add fallback value to mfaRecoveryCodes
RicardoE105 Apr 17, 2023
009458c
Update mfa.update hook name
RicardoE105 Apr 17, 2023
72b4d7d
Sync master
RicardoE105 Apr 24, 2023
16ff58f
Fix issue with types
RicardoE105 Apr 24, 2023
badb578
Fix linting issues
RicardoE105 Apr 24, 2023
3974419
Sync master
RicardoE105 Apr 26, 2023
3e3f3a3
Update pnpm-lock.yaml
RicardoE105 Apr 26, 2023
d24e7c7
Sync master
RicardoE105 May 6, 2023
675d04f
fix imports
RicardoE105 May 6, 2023
50e84c3
fix migrations
RicardoE105 May 6, 2023
1e56c50
fix linting issues
RicardoE105 May 6, 2023
515dd48
move migration logging. this is implicitly done now
netroy May 7, 2023
17bf246
fix mfa tests
netroy May 7, 2023
ded6190
ADD back the mistakenly removed section in personal settings .
RicardoE105 May 8, 2023
f478884
Sync master
RicardoE105 May 16, 2023
bd7ccda
Fix issues after merge
RicardoE105 May 16, 2023
7214bec
fix linting issues
RicardoE105 May 17, 2023
7cdb484
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 May 30, 2023
46ffa12
Add MFA bus
RicardoE105 May 30, 2023
721f54b
fix event bus mfaView
RicardoE105 May 30, 2023
f7ddf29
fix linting issues
RicardoE105 May 31, 2023
bece85a
fix linting issues
RicardoE105 May 31, 2023
9accb72
fix linting issue
RicardoE105 May 31, 2023
56d9b85
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 Jun 6, 2023
b34f392
Sync master
RicardoE105 Jun 26, 2023
0b39b66
fix merging issue
RicardoE105 Jun 26, 2023
0227be4
fix more merging issues
RicardoE105 Jun 26, 2023
d4cd4bd
fix linting issue
RicardoE105 Jun 26, 2023
ba8bdb8
Sync master
RicardoE105 Jul 29, 2023
a9352ec
update lock file
RicardoE105 Jul 29, 2023
6277454
Fix merge issues
RicardoE105 Jul 29, 2023
a2f8f60
move migrations to common folder
RicardoE105 Jul 29, 2023
90c86f2
update version of qrCode library
RicardoE105 Jul 29, 2023
77b40c2
update tests to use testServer
RicardoE105 Aug 2, 2023
c50b504
more updates to tests
RicardoE105 Aug 2, 2023
94515b9
sync master
RicardoE105 Aug 2, 2023
4042d4f
more test fixes
RicardoE105 Aug 2, 2023
f58ee8c
update lock file
RicardoE105 Aug 3, 2023
ba24ca6
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 Aug 3, 2023
ad7c228
fix linting issues
RicardoE105 Aug 3, 2023
58fc621
fix e2e tests
RicardoE105 Aug 3, 2023
2688fd2
fix format issues
RicardoE105 Aug 3, 2023
08a0b17
remove console.logs
RicardoE105 Aug 3, 2023
1f09920
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 Aug 4, 2023
0743241
Merge branch 'master' into ado-21-sync-current-mfa-functionality-with
RicardoE105 Aug 11, 2023
0856a88
fix linting issue
RicardoE105 Aug 11, 2023
07a2df0
ignore cypress download folder
RicardoE105 Aug 17, 2023
20bd360
fix typo
RicardoE105 Aug 17, 2023
a95b4ed
remove unneccesary default
RicardoE105 Aug 17, 2023
90d944d
remove calls to hook user.mfa.update
RicardoE105 Aug 17, 2023
51aabe2
remove duplicated interface
RicardoE105 Aug 17, 2023
8bd4b54
rename getRawSecretAndRecoveryCodes to getSecretAndRecoveryCodes
RicardoE105 Aug 17, 2023
caa467d
add max length to secret and recovery code columns
RicardoE105 Aug 17, 2023
aea64ad
copy secret directly instead of hiding it the html
RicardoE105 Aug 17, 2023
7f0705c
log telemetry event before redirecting
RicardoE105 Aug 17, 2023
19b45cc
fix typo
RicardoE105 Aug 17, 2023
2fdd211
fix tests description
RicardoE105 Aug 17, 2023
f5b6938
update e2e tests
RicardoE105 Aug 17, 2023
cdcc2d3
sync master
RicardoE105 Aug 17, 2023
518e550
update lock file
RicardoE105 Aug 17, 2023
74fc696
fix linting issues
RicardoE105 Aug 18, 2023
a8fd72a
use string instead of varchar
RicardoE105 Aug 18, 2023
d18610a
use mfaService to create mfa test user
RicardoE105 Aug 18, 2023
2d12efc
fix linting issue
RicardoE105 Aug 18, 2023
ba9430a
fix i18n component with i18n-t
RicardoE105 Aug 18, 2023
fa9b8cf
fix linting issue
RicardoE105 Aug 18, 2023
0439b8f
bump library version
RicardoE105 Aug 18, 2023
77da37a
revert mistakenly committed change to auth.controller
RicardoE105 Aug 18, 2023
1d948fb
remove unnecessary call to userStore.addUsers
RicardoE105 Aug 18, 2023
41aa73f
css improvement
RicardoE105 Aug 18, 2023
631ff55
here fine
RicardoE105 Aug 19, 2023
6a96df1
delete MFA route and move MFA component to sign-in view
RicardoE105 Aug 20, 2023
bf8ccf5
delete mfa route and fix linting issue
RicardoE105 Aug 20, 2023
613f27e
do not ask for mfa token to change password if user already signed in
RicardoE105 Aug 20, 2023
c199dea
general improvements
RicardoE105 Aug 20, 2023
ffc28e7
add variables to css
RicardoE105 Aug 21, 2023
e33ba93
add mfaEnabled flag to password reset
RicardoE105 Aug 21, 2023
b8cd736
use text instead of string
RicardoE105 Aug 21, 2023
af5942a
sync master
RicardoE105 Aug 22, 2023
c97b926
no need to clear credentials
RicardoE105 Aug 22, 2023
2e1300a
improvement
RicardoE105 Aug 22, 2023
94de010
add back mistakenly removed toast
RicardoE105 Aug 22, 2023
4418e7c
sync master
RicardoE105 Aug 22, 2023
91ea4a6
fix merge issue
RicardoE105 Aug 22, 2023
1ac980a
sync master
RicardoE105 Aug 23, 2023
b7818fe
fix e2e tests
RicardoE105 Aug 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ packages/**/.turbo
*.tsbuildinfo
cypress/videos/*
cypress/screenshots/*
cypress/downloads/*
*.swp
CHANGELOG-*.md
70 changes: 70 additions & 0 deletions cypress/e2e/27-two-factor-authentication.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { MainSidebar } from './../pages/sidebar/main-sidebar';
import { INSTANCE_OWNER, BACKEND_BASE_URL } from '../constants';
import { SigninPage } from '../pages';
import { PersonalSettingsPage } from '../pages/settings-personal';
import { MfaLoginPage } from '../pages/mfa-login';

const MFA_SECRET = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD';

const RECOVERY_CODE = 'd04ea17f-e8b2-4afa-a9aa-57a2c735b30e';

const user = {
email: INSTANCE_OWNER.email,
password: INSTANCE_OWNER.password,
firstName: 'User',
lastName: 'A',
mfaEnabled: false,
mfaSecret: MFA_SECRET,
mfaRecoveryCodes: [RECOVERY_CODE],
};

const mfaLoginPage = new MfaLoginPage();
const signinPage = new SigninPage();
const personalSettingsPage = new PersonalSettingsPage();
const mainSidebar = new MainSidebar();

describe('Two-factor authentication', () => {
beforeEach(() => {
Cypress.session.clearAllSavedSessions();
cy.request('POST', `${BACKEND_BASE_URL}/rest/e2e/reset`, {
owner: user,
members: [],
});
cy.on('uncaught:exception', (err, runnable) => {
expect(err.message).to.include('Not logged in');
return false;
});
});

it('Should be able to login with MFA token', () => {
const { email, password } = user;
signinPage.actions.loginWithEmailAndPassword(email, password);
personalSettingsPage.actions.enableMfa();
mainSidebar.actions.signout();
cy.generateToken(user.mfaSecret).then((token) => {
mfaLoginPage.actions.loginWithMfaToken(email, password, token);
mainSidebar.actions.signout();
});
});

it('Should be able to login with 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]);
mainSidebar.actions.signout();
});

it('Should be able to disable MFA in account', () => {
const { email, password } = user;
signinPage.actions.loginWithEmailAndPassword(email, password);
personalSettingsPage.actions.enableMfa();
mainSidebar.actions.signout();
cy.generateToken(user.mfaSecret).then((token) => {
mfaLoginPage.actions.loginWithMfaToken(email, password, token);
personalSettingsPage.actions.disableMfa();
mainSidebar.actions.signout();
});
});
});
1 change: 1 addition & 0 deletions cypress/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './settings-log-streaming';
export * from './sidebar';
export * from './ndv';
export * from './bannerStack';
export * from './signin';
77 changes: 77 additions & 0 deletions cypress/pages/mfa-login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { N8N_AUTH_COOKIE } from '../constants';
import { BasePage } from './base';
import { SigninPage } from './signin';
import { WorkflowsPage } from './workflows';

export class MfaLoginPage extends BasePage {
url = '/mfa';
getters = {
form: () => cy.getByTestId('mfa-login-form'),
token: () => cy.getByTestId('token'),
recoveryCode: () => cy.getByTestId('recoveryCode'),
enterRecoveryCodeButton: () => cy.getByTestId('mfa-enter-recovery-code-button'),
};

actions = {
loginWithMfaToken: (email: string, password: string, mfaToken: string) => {
const signinPage = new SigninPage();
const workflowsPage = new WorkflowsPage();

cy.session(
[mfaToken],
() => {
cy.visit(signinPage.url);

signinPage.getters.form().within(() => {
signinPage.getters.email().type(email);
signinPage.getters.password().type(password);
signinPage.getters.submit().click();
});

this.getters.form().within(() => {
this.getters.token().type(mfaToken);
});

// we should be redirected to /workflows
cy.url().should('include', workflowsPage.url);
},
{
validate() {
cy.getCookie(N8N_AUTH_COOKIE).should('exist');
},
},
);
},
loginWithRecoveryCode: (email: string, password: string, recoveryCode: string) => {
const signinPage = new SigninPage();
const workflowsPage = new WorkflowsPage();

cy.session(
[recoveryCode],
() => {
cy.visit(signinPage.url);

signinPage.getters.form().within(() => {
signinPage.getters.email().type(email);
signinPage.getters.password().type(password);
signinPage.getters.submit().click();
});

this.getters.enterRecoveryCodeButton().click();

this.getters.form().within(() => {
this.getters.recoveryCode().type(recoveryCode);
});

// we should be redirected to /workflows
cy.url().should('include', workflowsPage.url);
},
{
validate() {
cy.getCookie(N8N_AUTH_COOKIE).should('exist');
},
},
);
},
};
}
11 changes: 11 additions & 0 deletions cypress/pages/modals/mfa-setup-modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { BasePage } from './../base';

export class MfaSetupModal extends BasePage {
getters = {
modalContainer: () => cy.getByTestId('changePassword-modal').last(),
tokenInput: () => cy.getByTestId('mfa-token-input'),
copySecretToClipboardButton: () => cy.getByTestId('mfa-secret-button'),
downloadRecoveryCodesButton: () => cy.getByTestId('mfa-recovery-codes-button'),
saveButton: () => cy.getByTestId('mfa-save-button'),
};
}
22 changes: 22 additions & 0 deletions cypress/pages/settings-personal.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { ChangePasswordModal } from './modals/change-password-modal';
import { MfaSetupModal } from './modals/mfa-setup-modal';
import { BasePage } from './base';

const changePasswordModal = new ChangePasswordModal();
const mfaSetupModal = new MfaSetupModal();

export class PersonalSettingsPage extends BasePage {
url = '/settings/personal';
secret = '';

getters = {
currentUserName: () => cy.getByTestId('current-user-name'),
firstNameInput: () => cy.getByTestId('firstName').find('input').first(),
Expand All @@ -13,6 +17,8 @@ export class PersonalSettingsPage extends BasePage {
emailInput: () => cy.getByTestId('email').find('input').first(),
changePasswordLink: () => cy.getByTestId('change-password-link').first(),
saveSettingsButton: () => cy.getByTestId('save-settings-button'),
enableMfaButton: () => cy.getByTestId('enable-mfa-button'),
disableMfaButton: () => cy.getByTestId('disable-mfa-button'),
};
actions = {
loginAndVisit: (email: string, password: string) => {
Expand Down Expand Up @@ -50,5 +56,21 @@ export class PersonalSettingsPage extends BasePage {
this.actions.loginAndVisit(email, password);
cy.url().should('match', new RegExp(this.url));
},
enableMfa: () => {
cy.visit(this.url);
this.getters.enableMfaButton().click();
mfaSetupModal.getters.copySecretToClipboardButton().realClick();
cy.readClipboard().then((secret) => {
cy.generateToken(secret).then((token) => {
mfaSetupModal.getters.tokenInput().type(token);
mfaSetupModal.getters.downloadRecoveryCodesButton().click();
mfaSetupModal.getters.saveButton().click();
});
});
},
disableMfa: () => {
cy.visit(this.url);
this.getters.disableMfaButton().click();
},
};
}
4 changes: 3 additions & 1 deletion cypress/pages/sidebar/main-sidebar.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { BasePage } from '../base';
import { WorkflowsPage } from '../workflows';

const workflowsPage = new WorkflowsPage();

export class MainSidebar extends BasePage {
getters = {
menuItem: (menuLabel: string) =>
Expand All @@ -25,7 +27,7 @@ export class MainSidebar extends BasePage {
this.getters.credentials().click();
},
openUserMenu: () => {
this.getters.userMenu().find('[role="button"]').last().click();
this.getters.userMenu().click();
},
openUserMenu: () => {
this.getters.userMenu().click();
Expand Down
41 changes: 41 additions & 0 deletions cypress/pages/signin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { N8N_AUTH_COOKIE } from '../constants';
import { BasePage } from './base';
import { WorkflowsPage } from './workflows';

export class SigninPage extends BasePage {
url = '/signin';
getters = {
form: () => cy.getByTestId('auth-form'),
email: () => cy.getByTestId('email'),
password: () => cy.getByTestId('password'),
submit: () => cy.get('button'),
};

actions = {
loginWithEmailAndPassword: (email: string, password: string) => {
const signinPage = new SigninPage();
const workflowsPage = new WorkflowsPage();

cy.session(
[email, password],
() => {
cy.visit(signinPage.url);

this.getters.form().within(() => {
this.getters.email().type(email);
this.getters.password().type(password);
this.getters.submit().click();
});

// we should be redirected to /workflows
cy.url().should('include', workflowsPage.url);
},
{
validate() {
cy.getCookie(N8N_AUTH_COOKIE).should('exist');
},
},
);
},
};
}
20 changes: 12 additions & 8 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'cypress-real-events';
import { WorkflowPage } from '../pages';
import { BACKEND_BASE_URL, N8N_AUTH_COOKIE } from '../constants';
import generateOTPToken from 'cypress-otp';

Cypress.Commands.add('getByTestId', (selector, ...args) => {
return cy.get(`[data-test-id="${selector}"]`, ...args);
Expand Down Expand Up @@ -41,14 +42,13 @@ Cypress.Commands.add('waitForLoad', (waitForIntercepts = true) => {

Cypress.Commands.add('signin', ({ email, password }) => {
Cypress.session.clearAllSavedSessions();
cy.session(
[email, password],
() => cy.request('POST', `${BACKEND_BASE_URL}/rest/login`, { email, password }),
{
validate() {
cy.getCookie(N8N_AUTH_COOKIE).should('exist');
},
},
cy.session([email, password], () =>
cy.request({
method: 'POST',
url: `${BACKEND_BASE_URL}/rest/login`,
body: { email, password },
failOnStatusCode: false,
}),
);
});

Expand Down Expand Up @@ -162,3 +162,7 @@ Cypress.Commands.add('draganddrop', (draggableSelector, droppableSelector) => {
}
});
});

Cypress.Commands.add('generateToken', (secret: string) => {
return generateOTPToken(secret);
});
1 change: 1 addition & 0 deletions cypress/support/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ declare global {
options?: { abs?: boolean; index?: number; realMouse?: boolean },
): void;
draganddrop(draggableSelector: string, droppableSelector: string): void;
generateToken(mfaSecret: string): Chainable<string>;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@types/supertest": "^2.0.12",
"@vitest/coverage-v8": "^0.33.0",
"cross-env": "^7.0.3",
"cypress-otp": "^1.0.3",
"cypress": "^12.17.2",
"cypress-real-events": "^1.9.1",
"jest": "^29.6.2",
Expand Down
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
"oauth-1.0a": "^2.2.6",
"open": "^7.0.0",
"openapi-types": "^10.0.0",
"otpauth": "^9.1.1",
"p-cancelable": "^2.0.0",
"p-lazy": "^3.1.0",
"passport": "^0.6.0",
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@ export interface PublicUser {
passwordResetToken?: string;
createdAt: Date;
isPending: boolean;
hasRecoveryCodesLeft: boolean;
globalRole?: Role;
signInType: AuthProviderType;
disabled: boolean;
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/Mfa/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const MFA_FEATURE_ENABLED = 'mfa.enabled';
21 changes: 21 additions & 0 deletions packages/cli/src/Mfa/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import config from '@/config';
import * as Db from '@/Db';
import { MFA_FEATURE_ENABLED } from './constants';

export const isMfaFeatureEnabled = () => config.get(MFA_FEATURE_ENABLED);

const isMfaFeatureDisabled = () => !isMfaFeatureEnabled();

const getUsersWithMfaEnabled = async () =>
Db.collections.User.count({ where: { mfaEnabled: true } });

export const handleMfaDisable = async () => {
if (isMfaFeatureDisabled()) {
// check for users with MFA enabled, and if there are
// users, then keep the feature enabled
const users = await getUsersWithMfaEnabled();
if (users) {
config.set(MFA_FEATURE_ENABLED, true);
}
}
};
Loading
Loading