From 9bb6cfa512b43fcff76f418614dfd8048ed562fa Mon Sep 17 00:00:00 2001 From: Noelle Daley Date: Fri, 21 Jun 2024 15:17:00 -0700 Subject: [PATCH 1/3] mfa-form: fix regex matching so error msg displays --- ui/app/components/mfa/mfa-form.js | 14 +++++++-- .../integration/components/mfa-form-test.js | 31 ++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/ui/app/components/mfa/mfa-form.js b/ui/app/components/mfa/mfa-form.js index 484d13905f9a..c81ff42ff98d 100644 --- a/ui/app/components/mfa/mfa-form.js +++ b/ui/app/components/mfa/mfa-form.js @@ -102,10 +102,20 @@ export default class MfaForm extends Component { } } - @task *newCodeDelay(message) { + @task *newCodeDelay(errorMessage) { + let delay; + // parse validity period from error string to initialize countdown - this.countdown = parseInt(message.match(/(\d\w seconds)/)[0].split(' ')[0]); + const delayRegExMatches = errorMessage.match(/(\d+\w seconds)/); + if (delayRegExMatches && delayRegExMatches.length) { + delay = delayRegExMatches[0].split(' ')[0]; + } else { + // default to 30 seconds if error message doesn't specify one + delay = 30; + } + this.countdown = parseInt(delay); + // skip countdown in testing environment if (Ember.testing) return; while (this.countdown > 0) { diff --git a/ui/tests/integration/components/mfa-form-test.js b/ui/tests/integration/components/mfa-form-test.js index 128b5b38519d..daceb7bda584 100644 --- a/ui/tests/integration/components/mfa-form-test.js +++ b/ui/tests/integration/components/mfa-form-test.js @@ -177,9 +177,9 @@ module('Integration | Component | mfa-form', function (hooks) { test('it should show countdown on passcode already used and rate limit errors', async function (assert) { const messages = { - used: 'code already used; new code is available in 45 seconds', + used: 'code already used; new code is available in 30 seconds', limit: - 'maximum TOTP validation attempts 4 exceeded the allowed attempts 3. Please try again in 15 seconds', + 'maximum TOTP validation attempts 4 exceeded the allowed attempts 3. Please try again in 30s seconds', }; const codes = ['used', 'limit']; for (const code of codes) { @@ -188,12 +188,10 @@ module('Integration | Component | mfa-form', function (hooks) { throw { errors: [messages[code]] }; }, }); - const expectedTime = code === 'used' ? 45 : 15; await render(hbs``); - await fillIn('[data-test-mfa-passcode]', code); - + await fillIn('[data-test-mfa-passcode]', 'foo'); await click('[data-test-mfa-validate]'); await waitFor('[data-test-mfa-countdown]'); @@ -207,6 +205,29 @@ module('Integration | Component | mfa-form', function (hooks) { } }); + test('it defaults countdown to 30 seconds if error message does not indicate when user can try again ', async function (assert) { + this.owner.lookup('service:auth').reopen({ + totpValidate() { + throw { + errors: ['maximum TOTP validation attempts 4 exceeded the allowed attempts 3. Beep-boop.'], + }; + }, + }); + await render(hbs``); + + await fillIn('[data-test-mfa-passcode]', 'foo'); + await click('[data-test-mfa-validate]'); + + await waitFor('[data-test-mfa-countdown]'); + + assert + .dom('[data-test-mfa-countdown]') + .includesText('30', 'countdown renders with correct initial value from error response'); + assert.dom('[data-test-mfa-validate]').isDisabled('Button is disabled during countdown'); + assert.dom('[data-test-mfa-passcode]').isDisabled('Input is disabled during countdown'); + assert.dom('[data-test-inline-error-message]').exists('Alert message renders'); + }); + test('it should show error message for passcode invalid error', async function (assert) { this.owner.lookup('service:auth').reopen({ totpValidate() { From 522dddb33fe3a197e8c7f0da15ca37e0bcb3b0a2 Mon Sep 17 00:00:00 2001 From: Noelle Daley Date: Fri, 21 Jun 2024 15:52:33 -0700 Subject: [PATCH 2/3] changelog --- changelog/27574.txt | 3 +++ ui/tests/integration/components/mfa-form-test.js | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelog/27574.txt diff --git a/changelog/27574.txt b/changelog/27574.txt new file mode 100644 index 000000000000..8c1f888242c8 --- /dev/null +++ b/changelog/27574.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: Display an error and force a timeout when TOTP passcode is incorrect +``` \ No newline at end of file diff --git a/ui/tests/integration/components/mfa-form-test.js b/ui/tests/integration/components/mfa-form-test.js index daceb7bda584..9877f0753fca 100644 --- a/ui/tests/integration/components/mfa-form-test.js +++ b/ui/tests/integration/components/mfa-form-test.js @@ -178,6 +178,8 @@ module('Integration | Component | mfa-form', function (hooks) { test('it should show countdown on passcode already used and rate limit errors', async function (assert) { const messages = { used: 'code already used; new code is available in 30 seconds', + // there an intentional typo in the error message (30s seconds) + // that is what the backend returns limit: 'maximum TOTP validation attempts 4 exceeded the allowed attempts 3. Please try again in 30s seconds', }; @@ -198,7 +200,7 @@ module('Integration | Component | mfa-form', function (hooks) { assert .dom('[data-test-mfa-countdown]') - .includesText(expectedTime, 'countdown renders with correct initial value from error response'); + .includesText('30', 'countdown renders with correct initial value from error response'); assert.dom('[data-test-mfa-validate]').isDisabled('Button is disabled during countdown'); assert.dom('[data-test-mfa-passcode]').isDisabled('Input is disabled during countdown'); assert.dom('[data-test-inline-error-message]').exists('Alert message renders'); From 3b57f9cc182bf9978d4e9b96affdac16e72308de Mon Sep 17 00:00:00 2001 From: Noelle Daley Date: Tue, 25 Jun 2024 16:27:26 -0700 Subject: [PATCH 3/3] chore: add comments --- ui/tests/integration/components/mfa-form-test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/tests/integration/components/mfa-form-test.js b/ui/tests/integration/components/mfa-form-test.js index 9877f0753fca..cc32103fd7c3 100644 --- a/ui/tests/integration/components/mfa-form-test.js +++ b/ui/tests/integration/components/mfa-form-test.js @@ -178,8 +178,7 @@ module('Integration | Component | mfa-form', function (hooks) { test('it should show countdown on passcode already used and rate limit errors', async function (assert) { const messages = { used: 'code already used; new code is available in 30 seconds', - // there an intentional typo in the error message (30s seconds) - // that is what the backend returns + // note: the backend returns a duplicate "s" in "30s seconds" in the limit message below. we have intentionally left it as is to ensure our regex for parsing the delay time can handle it limit: 'maximum TOTP validation attempts 4 exceeded the allowed attempts 3. Please try again in 30s seconds', };