mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 19:17:58 +00:00
UI: allow retries for MFA form errors (#27574)
* mfa-form: fix regex matching so error msg displays * changelog * chore: add comments
This commit is contained in:
3
changelog/27574.txt
Normal file
3
changelog/27574.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:bug
|
||||
ui: Display an error and force a timeout when TOTP passcode is incorrect
|
||||
```
|
||||
@@ -102,10 +102,20 @@ export default class MfaForm extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
@task *newCodeDelay(message) {
|
||||
// parse validity period from error string to initialize countdown
|
||||
this.countdown = parseInt(message.match(/(\d\w seconds)/)[0].split(' ')[0]);
|
||||
@task *newCodeDelay(errorMessage) {
|
||||
let delay;
|
||||
|
||||
// parse validity period from error string to initialize countdown
|
||||
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) {
|
||||
|
||||
@@ -177,9 +177,10 @@ 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',
|
||||
// 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 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,25 +189,46 @@ module('Integration | Component | mfa-form', function (hooks) {
|
||||
throw { errors: [messages[code]] };
|
||||
},
|
||||
});
|
||||
const expectedTime = code === 'used' ? 45 : 15;
|
||||
|
||||
await render(hbs`<Mfa::MfaForm @clusterId={{this.clusterId}} @authData={{this.mfaAuthData}} />`);
|
||||
|
||||
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]');
|
||||
|
||||
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');
|
||||
}
|
||||
});
|
||||
|
||||
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`<Mfa::MfaForm @clusterId={{this.clusterId}} @authData={{this.mfaAuthData}} />`);
|
||||
|
||||
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() {
|
||||
|
||||
Reference in New Issue
Block a user