]> git.proxmox.com Git - pmg-gui.git/blobdiff - js/UserView.js
spam detector: custom rules: move apply/revert buttons to pending section
[pmg-gui.git] / js / UserView.js
index 5588be038ccc7d5ca5bc1da2e1d21bb8c3425325..d82b49e2b96ea76ee2834cbc61f3eaf01c2a0035 100644 (file)
@@ -1,17 +1,16 @@
-/*global Proxmox*/
 Ext.define('pmg-users', {
     extend: 'Ext.data.Model',
     fields: [
-       'userid', 'firstname', 'lastname' , 'email', 'comment',
-       'role', 'keys', 'realm',
+       'userid', 'firstname', 'lastname', 'email', 'comment',
+       'role', 'keys', 'realm', 'totp-lock',
        { type: 'boolean', name: 'enable' },
-       { type: 'date', dateFormat: 'timestamp', name: 'expire' }
+       { type: 'date', dateFormat: 'timestamp', name: 'expire' },
     ],
     proxy: {
         type: 'proxmox',
-       url: "/api2/json/access/users"
+       url: "/api2/json/access/users",
     },
-    idProperty: 'userid'
+    idProperty: 'userid',
 });
 
 Ext.define('PMG.UserView', {
@@ -24,13 +23,13 @@ Ext.define('PMG.UserView', {
        sorters: [
            {
                property: 'realm',
-               direction: 'ASC'
+               direction: 'ASC',
            },
            {
                property: 'userid',
-               direction: 'ASC'
-           }
-       ]
+               direction: 'ASC',
+           },
+       ],
     },
 
     controller: {
@@ -55,7 +54,7 @@ Ext.define('PMG.UserView', {
            var view = this.getView();
 
             var win = Ext.create('PMG.UserEdit', {});
-            win.on('destroy', function() { view.reload() });
+            win.on('destroy', function() { view.reload(); });
             win.show();
        },
 
@@ -65,26 +64,50 @@ Ext.define('PMG.UserView', {
            var rec = view.selModel.getSelection()[0];
 
             var win = Ext.create('PMG.UserEdit', {
-               userid: rec.data.userid
+               userid: rec.data.userid,
             });
-            win.on('destroy', function() { view.reload() });
+            win.on('destroy', function() { view.reload(); });
             win.show();
        },
 
        onPassword: function(btn, event, rec) {
            var view = this.getView();
 
-           var win = Ext.create('Proxmox.window.PasswordEdit',{
-                userid: rec.data.userid
+           var win = Ext.create('Proxmox.window.PasswordEdit', {
+                userid: rec.data.userid,
            });
-            win.on('destroy', function() { view.reload() });
+            win.on('destroy', function() { view.reload(); });
            win.show();
        },
 
        onAfterRemove: function(btn, res) {
            var view = this.getView();
            view.reload();
-       }
+       },
+
+       onUnlockTfa: function(btn, event, rec) {
+           let me = this;
+           let view = me.getView();
+           Ext.Msg.confirm(
+               Ext.String.format(gettext('Unlock TFA authentication for {0}'), rec.data.userid),
+               gettext("Locked 2nd factors can happen if the user's password was leaked. Are you sure you want to unlock the user?"),
+               function(btn_response) {
+                   if (btn_response === 'yes') {
+                       Proxmox.Utils.API2Request({
+                           url: `/access/users/${rec.data.userid}/unlock-tfa`,
+                           waitMsgTarget: view,
+                           method: 'PUT',
+                           failure: function(response, options) {
+                               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                           },
+                           success: function(response, options) {
+                               view.reload();
+                           },
+                       });
+                   }
+               },
+           );
+       },
     },
 
     listeners: {
@@ -96,27 +119,36 @@ Ext.define('PMG.UserView', {
         {
            text: gettext('Add'),
            reference: 'addBtn',
-           handler: 'onAdd'
+           handler: 'onAdd',
        },
        {
            xtype: 'proxmoxButton',
            text: gettext('Edit'),
            disabled: true,
-           handler: 'onEdit'
+           handler: 'onEdit',
        },
        {
            xtype: 'proxmoxStdRemoveButton',
            baseurl: '/access/users',
            reference: 'removeBtn',
            callback: 'onAfterRemove',
-           waitMsgTarget: true
+           waitMsgTarget: true,
        },
        {
            xtype: 'proxmoxButton',
            text: gettext('Password'),
            disabled: true,
-           handler: 'onPassword'
-       }
+           handler: 'onPassword',
+       },
+       '-',
+       {
+           xtype: 'proxmoxButton',
+           text: gettext('Unlock TFA'),
+           handler: 'onUnlockTfa',
+           disabled: true,
+           enableFn: ({ data }) =>
+               data['totp-locked'] || (data['tfa-locked-until'] > (new Date().getTime() / 1000)),
+       },
     ],
 
     columns: [
@@ -125,54 +157,75 @@ Ext.define('PMG.UserView', {
            width: 200,
            sortable: true,
            renderer: 'renderUsername',
-           dataIndex: 'userid'
+           dataIndex: 'userid',
        },
        {
            header: gettext('Realm'),
            width: 100,
            sortable: true,
-           dataIndex: 'realm'
+           dataIndex: 'realm',
        },
        {
            header: gettext('Role'),
            width: 150,
            sortable: true,
            renderer: PMG.Utils.format_user_role,
-           dataIndex: 'role'
+           dataIndex: 'role',
        },
        {
            header: gettext('Enabled'),
            width: 80,
            sortable: true,
            renderer: Proxmox.Utils.format_boolean,
-           dataIndex: 'enable'
+           dataIndex: 'enable',
        },
        {
            header: gettext('Expire'),
            width: 80,
            sortable: true,
            renderer: Proxmox.Utils.format_expire,
-           dataIndex: 'expire'
+           dataIndex: 'expire',
        },
        {
            header: gettext('Name'),
            width: 150,
            sortable: true,
            renderer: 'renderFullName',
-           dataIndex: 'firstname'
+           dataIndex: 'firstname',
+       },
+       {
+           header: gettext('TFA Lock'),
+           width: 120,
+           sortable: true,
+           dataIndex: 'totp-locked',
+           renderer: function(v, metaData, record) {
+               let locked_until = record.data['tfa-locked-until'];
+               if (locked_until !== undefined) {
+                   let now = new Date().getTime() / 1000;
+                   if (locked_until > now) {
+                       return gettext('Locked');
+                   }
+               }
+
+               if (record.data['totp-locked']) {
+                   return gettext('TOTP Locked');
+               }
+
+               return Proxmox.Utils.noText;
+           },
        },
        {
            header: gettext('Comment'),
            sortable: false,
            renderer: Ext.String.htmlEncode,
            dataIndex: 'comment',
-           flex: 1
-       }
+           flex: 1,
+       },
     ],
 
     reload: function() {
        var me = this;
 
        me.store.load();
-    }
+    },
 });