diff --git a/packages/core/src/routes/interaction/utils/totp-validation.ts b/packages/core/src/routes/interaction/utils/totp-validation.ts index 26d52c6da..7b404eca3 100644 --- a/packages/core/src/routes/interaction/utils/totp-validation.ts +++ b/packages/core/src/routes/interaction/utils/totp-validation.ts @@ -1,6 +1,17 @@ import { authenticator } from 'otplib'; +/** + * Note: + * Considering T1 and T2 two consecutive time steps, + * any token generated within T1 but checked with T2 could be considered valid according to [RFC 6238 5.2](https://datatracker.ietf.org/doc/html/rfc6238#section-5.2). + * + * FYI: https://github.com/yeojz/otplib/issues/697#issuecomment-1655749578 + */ +// eslint-disable-next-line @silverhand/fp/no-mutation +authenticator.options = { window: 1 }; + export const generateTotpSecret = () => authenticator.generateSecret(); -export const validateTotpToken = (secret: string, token: string) => - authenticator.check(token, secret); +export const validateTotpToken = (secret: string, token: string) => { + return authenticator.check(token, secret); +}; diff --git a/packages/integration-tests/src/ui-helpers/expect-totp-experience.ts b/packages/integration-tests/src/ui-helpers/expect-totp-experience.ts index ef3291db7..7df91c732 100644 --- a/packages/integration-tests/src/ui-helpers/expect-totp-experience.ts +++ b/packages/integration-tests/src/ui-helpers/expect-totp-experience.ts @@ -1,6 +1,5 @@ import { authenticator } from 'otplib'; -import { demoAppUrl } from '#src/constants.js'; import { waitFor, dcls } from '#src/utils.js'; import ExpectExperience from './expect-experience.js'; @@ -35,10 +34,7 @@ export default class ExpectTotpExperience extends ExpectExperience { const code = authenticator.generate(secret); - for (const [index, char] of code.split('').entries()) { - // eslint-disable-next-line no-await-in-loop - await this.toFillInput(`totpCode_${index}`, char); - } + await this.fillTotpCode(code); // Wait for the form to commit automatically await waitFor(500); @@ -64,10 +60,7 @@ export default class ExpectTotpExperience extends ExpectExperience { const code = authenticator.generate(secret); - for (const [index, char] of code.split('').entries()) { - // eslint-disable-next-line no-await-in-loop - await this.toFillInput(`totpCode_${index}`, char); - } + await this.fillTotpCode(code); // Wait for the form to commit automatically await waitFor(500); @@ -76,17 +69,10 @@ export default class ExpectTotpExperience extends ExpectExperience { } } - /** - * Assert the page is at the demo app page and get the user ID from the page. - * @returns The user ID. - */ - async getUserIdFromDemoAppPage() { - this.toMatchUrl(demoAppUrl); - const userIdDiv = await expect(this.page).toMatchElement([dcls('infoCard'), 'div'].join(' '), { - text: 'User ID: ', - }); - const userIdSpan = await expect(userIdDiv).toMatchElement('span'); - - return (await userIdSpan.evaluate((element) => element.textContent)) ?? ''; + private async fillTotpCode(code: string) { + for (const [index, char] of code.split('').entries()) { + // eslint-disable-next-line no-await-in-loop + await this.toFillInput(`totpCode_${index}`, char); + } } }