|
| 1 | +import { expect } from '@playwright/test'; |
| 2 | +import { authenticator } from 'otplib'; |
| 3 | + |
| 4 | +import type { n8nPage } from '../pages/n8nPage'; |
| 5 | + |
| 6 | +export class MfaComposer { |
| 7 | + constructor(private readonly n8n: n8nPage) {} |
| 8 | + |
| 9 | + /** |
| 10 | + * Enable MFA for a user using predefined secret |
| 11 | + * @param email - User email |
| 12 | + * @param password - User password |
| 13 | + * @param mfaSecret - Known MFA secret to use for token generation |
| 14 | + */ |
| 15 | + async enableMfa(email: string, password: string, mfaSecret: string): Promise<void> { |
| 16 | + await this.n8n.signIn.loginWithEmailAndPassword(email, password, true); |
| 17 | + await this.n8n.settings.goToPersonalSettings(); |
| 18 | + |
| 19 | + await this.n8n.settings.clickEnableMfa(); |
| 20 | + |
| 21 | + await this.n8n.mfaSetupModal.getModalContainer().waitFor({ state: 'visible' }); |
| 22 | + |
| 23 | + await this.n8n.mfaSetupModal.clickCopySecretToClipboard(); |
| 24 | + |
| 25 | + const token = authenticator.generate(mfaSecret); |
| 26 | + await this.n8n.mfaSetupModal.fillToken(token); |
| 27 | + await expect(this.n8n.mfaSetupModal.getDownloadRecoveryCodesButton()).toBeVisible(); |
| 28 | + await this.n8n.mfaSetupModal.clickDownloadRecoveryCodes(); |
| 29 | + await this.n8n.mfaSetupModal.clickSave(); |
| 30 | + await this.n8n.mfaSetupModal.waitForHidden(); |
| 31 | + } |
| 32 | + |
| 33 | + /** |
| 34 | + * Login with MFA code |
| 35 | + * @param email - User email |
| 36 | + * @param password - User password |
| 37 | + * @param mfaSecret - Known MFA secret for token generation |
| 38 | + */ |
| 39 | + async loginWithMfaCode(email: string, password: string, mfaSecret: string): Promise<void> { |
| 40 | + await this.n8n.signIn.fillEmail(email); |
| 41 | + await this.n8n.signIn.fillPassword(password); |
| 42 | + await this.n8n.signIn.clickSubmit(); |
| 43 | + |
| 44 | + await expect(this.n8n.mfaLogin.getForm()).toBeVisible(); |
| 45 | + const loginMfaCode = authenticator.generate(mfaSecret); |
| 46 | + await this.n8n.mfaLogin.submitMfaCode(loginMfaCode); |
| 47 | + await expect(this.n8n.page).toHaveURL(/workflows/); |
| 48 | + } |
| 49 | + |
| 50 | + /** |
| 51 | + * Login with MFA recovery code |
| 52 | + * @param email - User email |
| 53 | + * @param password - User password |
| 54 | + * @param recoveryCode - Known recovery code |
| 55 | + */ |
| 56 | + async loginWithMfaRecoveryCode( |
| 57 | + email: string, |
| 58 | + password: string, |
| 59 | + recoveryCode: string, |
| 60 | + ): Promise<void> { |
| 61 | + await this.n8n.signIn.fillEmail(email); |
| 62 | + await this.n8n.signIn.fillPassword(password); |
| 63 | + await this.n8n.signIn.clickSubmit(); |
| 64 | + |
| 65 | + await expect(this.n8n.mfaLogin.getForm()).toBeVisible(); |
| 66 | + await this.n8n.mfaLogin.submitMfaRecoveryCode(recoveryCode); |
| 67 | + await expect(this.n8n.page).toHaveURL(/workflows/); |
| 68 | + } |
| 69 | +} |
0 commit comments