From: Wolfgang Bumiller <w.bumiller@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v3 widget-toolkit 1/2] tfa: improve UX for recovery keys and when none are left
Date: Tue, 6 Jun 2023 12:03:17 +0200 [thread overview]
Message-ID: <20230606100318.110005-1-w.bumiller@proxmox.com> (raw)
If we get an empty challenge, tell the user to contact an
administrator as it means no 2nd factors and no recovery
keys are available.
Currently if only 1 key was available and it had a high ID,
we'd show something like: "Recovery keys available: 9,
Warning, less than 4 keys available."
Let's start off with the warning, and then be explicit about
the IDs.
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
---
changes since v2:
- fix wrong tfa type comparison
- hide recovery input field when no recovery keys are left
src/window/TfaWindow.js | 75 ++++++++++++++++++++++++++++++++---------
1 file changed, 59 insertions(+), 16 deletions(-)
diff --git a/src/window/TfaWindow.js b/src/window/TfaWindow.js
index 22ac50d..3646e0e 100644
--- a/src/window/TfaWindow.js
+++ b/src/window/TfaWindow.js
@@ -45,11 +45,17 @@ Ext.define('Proxmox.window.TfaLoginWindow', {
let lastTabId = me.getLastTabUsed();
let initialTab = -1, i = 0;
+ let count2nd = 0;
+ let hasRecovery = false;
for (const k of ['webauthn', 'totp', 'recovery', 'u2f', 'yubico']) {
const available = !!challenge[k];
vm.set(`availableChallenge.${k}`, available);
if (available) {
+ count2nd++;
+ if (k === 'recovery') {
+ hasRecovery = true;
+ }
if (i === lastTabId) {
initialTab = i;
} else if (initialTab < 0) {
@@ -58,15 +64,32 @@ Ext.define('Proxmox.window.TfaLoginWindow', {
}
i++;
}
+ if (!count2nd || (count2nd === 1 && hasRecovery && !challenge.recovery.length)) {
+ // no 2nd factors available (and if recovery keys are configured they're empty)
+ me.lookup('cannotLogin').setVisible(true);
+ me.lookup('recoveryKey').setVisible(false);
+ view.down('tabpanel').setActiveTab(2); // recovery
+ return;
+ }
view.down('tabpanel').setActiveTab(initialTab);
if (challenge.recovery) {
- me.lookup('availableRecovery').update(Ext.String.htmlEncode(
- gettext('Available recovery keys: ') + view.challenge.recovery.join(', '),
- ));
- me.lookup('availableRecovery').setVisible(true);
- if (view.challenge.recovery.length <= 3) {
- me.lookup('recoveryLow').setVisible(true);
+ if (!view.challenge.recovery.length) {
+ me.lookup('recoveryEmpty').setVisible(true);
+ me.lookup('recoveryKey').setVisible(false);
+ } else {
+ let idList = view
+ .challenge
+ .recovery
+ .map((id) => Ext.String.format(gettext('ID {0}'), id))
+ .join(', ');
+ me.lookup('availableRecovery').update(Ext.String.htmlEncode(
+ Ext.String.format(gettext('Available recovery keys: {0}'), idList),
+ ));
+ me.lookup('availableRecovery').setVisible(true);
+ if (view.challenge.recovery.length <= 3) {
+ me.lookup('recoveryLow').setVisible(true);
+ }
}
}
@@ -365,19 +388,23 @@ Ext.define('Proxmox.window.TfaLoginWindow', {
items: [
{
xtype: 'box',
- reference: 'availableRecovery',
+ reference: 'cannotLogin',
hidden: true,
+ html: '<i class="fa fa-exclamation-triangle warning"></i>'
+ + Ext.String.format(
+ gettext('No second factor left! Please contact an administrator!'),
+ 4,
+ ),
},
{
- xtype: 'textfield',
- fieldLabel: gettext('Please enter one of your single-use recovery keys'),
- labelWidth: 300,
- name: 'recoveryKey',
- disabled: true,
- reference: 'recoveryKey',
- allowBlank: false,
- regex: /^[0-9a-f]{4}(-[0-9a-f]{4}){3}$/,
- regexText: gettext('Does not look like a valid recovery key'),
+ xtype: 'box',
+ reference: 'recoveryEmpty',
+ hidden: true,
+ html: '<i class="fa fa-exclamation-triangle warning"></i>'
+ + Ext.String.format(
+ gettext('No more recovery keys left! Please generate a new set!'),
+ 4,
+ ),
},
{
xtype: 'box',
@@ -389,6 +416,22 @@ Ext.define('Proxmox.window.TfaLoginWindow', {
4,
),
},
+ {
+ xtype: 'box',
+ reference: 'availableRecovery',
+ hidden: true,
+ },
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('Please enter one of your single-use recovery keys'),
+ labelWidth: 300,
+ name: 'recoveryKey',
+ disabled: true,
+ reference: 'recoveryKey',
+ allowBlank: false,
+ regex: /^[0-9a-f]{4}(-[0-9a-f]{4}){3}$/,
+ regexText: gettext('Does not look like a valid recovery key'),
+ },
],
},
{
--
2.39.2
next reply other threads:[~2023-06-06 10:03 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-06 10:03 Wolfgang Bumiller [this message]
2023-06-06 10:03 ` [pve-devel] [PATCH widget-toolkit 2/2] tfa: show 'Locked' in 'Enabled' column if tfa is locked Wolfgang Bumiller
2023-06-07 16:07 ` [pve-devel] applied: " Thomas Lamprecht
2023-06-07 16:07 ` [pve-devel] applied: [PATCH v3 widget-toolkit 1/2] tfa: improve UX for recovery keys and when none are left Thomas Lamprecht
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230606100318.110005-1-w.bumiller@proxmox.com \
--to=w.bumiller@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox