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.bumil...@proxmox.com>
---
Changes to v1 address Dominik's remarks:
  - Fix typos
  - Make generated ID list format string right-to-left compatible
  - Replace the pair of `hasAny2nd` and `hasNonRecovery2nd` with a
    counter and a `hasRecovery` boolean which allows expressing the
    condition that "either no 2nd factors, or only an already used up set of
    recovery keys exists" with less cognitive overhead.

 src/window/TfaWindow.js | 74 ++++++++++++++++++++++++++++++++---------
 1 file changed, 58 insertions(+), 16 deletions(-)

diff --git a/src/window/TfaWindow.js b/src/window/TfaWindow.js
index 22ac50d..a622ce1 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,31 @@ 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);
+               } 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 +387,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 +415,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.30.2



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to