[pve-devel] [PATCH manager 7/7] www: redirect user TFA button to TFA view

Wolfgang Bumiller w.bumiller at proxmox.com
Tue Nov 9 12:27:14 CET 2021


Signed-off-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
---
 www/manager6/Makefile         |   1 -
 www/manager6/StateProvider.js |   1 +
 www/manager6/Workspace.js     |   6 +-
 www/manager6/dc/TFAEdit.js    | 545 ----------------------------------
 www/manager6/dc/UserView.js   |  27 --
 5 files changed, 3 insertions(+), 577 deletions(-)
 delete mode 100644 www/manager6/dc/TFAEdit.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 4011d4e5..584c1f2a 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -149,7 +149,6 @@ JSSRC= 							\
 	dc/Summary.js					\
 	dc/Support.js					\
 	dc/SyncWindow.js				\
-	dc/TFAEdit.js					\
 	dc/Tasks.js					\
 	dc/TokenEdit.js					\
 	dc/TokenView.js					\
diff --git a/www/manager6/StateProvider.js b/www/manager6/StateProvider.js
index e835f402..fafbb112 100644
--- a/www/manager6/StateProvider.js
+++ b/www/manager6/StateProvider.js
@@ -47,6 +47,7 @@ Ext.define('PVE.StateProvider', {
     hprefix: 'v1',
 
     compDict: {
+        tfa: 54,
 	sdn: 53,
 	cloudinit: 52,
 	replication: 51,
diff --git a/www/manager6/Workspace.js b/www/manager6/Workspace.js
index 0e2a750b..37d772b8 100644
--- a/www/manager6/Workspace.js
+++ b/www/manager6/Workspace.js
@@ -386,10 +386,8 @@ Ext.define('PVE.StdWorkspace', {
 				    itemId: 'tfaitem',
 				    iconCls: 'fa fa-fw fa-lock',
 				    handler: function(btn, event, rec) {
-					var win = Ext.create('PVE.window.TFAEdit', {
-					    userid: Proxmox.UserName,
-					});
-					win.show();
+					Ext.state.Manager.getProvider().set('dctab', { value: 'tfa' }, true);
+					me.selectById('root');
 				    },
 				},
 				{
diff --git a/www/manager6/dc/TFAEdit.js b/www/manager6/dc/TFAEdit.js
deleted file mode 100644
index 57a73b39..00000000
--- a/www/manager6/dc/TFAEdit.js
+++ /dev/null
@@ -1,545 +0,0 @@
-/*global u2f,QRCode*/
-Ext.define('PVE.window.TFAEdit', {
-    extend: 'Ext.window.Window',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    onlineHelp: 'pveum_tfa_auth', // fake to ensure this gets a link target
-
-    modal: true,
-    resizable: false,
-    title: gettext('Two Factor Authentication'),
-    subject: 'TFA',
-    url: '/api2/extjs/access/tfa',
-    width: 512,
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch',
-    },
-
-    updateQrCode: function() {
-	var me = this;
-	var values = me.lookup('totp_form').getValues();
-	var algorithm = values.algorithm;
-	if (!algorithm) {
-	    algorithm = 'SHA1';
-	}
-
-	me.qrcode.makeCode(
-	    'otpauth://totp/' +
-	    encodeURIComponent(values.issuer) +
-	    ':' +
-	    encodeURIComponent(me.userid) +
-	    '?secret=' + values.secret +
-	    '&period=' + values.step +
-	    '&digits=' + values.digits +
-	    '&algorithm=' + algorithm +
-	    '&issuer=' + encodeURIComponent(values.issuer),
-	);
-
-	me.lookup('challenge').setVisible(true);
-	me.down('#qrbox').setVisible(true);
-    },
-
-    showError: function(error) {
-	Ext.Msg.alert(
-	    gettext('Error'),
-	    Proxmox.Utils.render_u2f_error(error),
-	);
-    },
-
-    doU2FChallenge: function(res) {
-	let me = this;
-
-	let challenge = res.result.data;
-	me.lookup('password').setDisabled(true);
-	let msg = Ext.Msg.show({
-	    title: 'U2F: ' + gettext('Setup'),
-	    message: gettext('Please press the button on your U2F Device'),
-	    buttons: [],
-	});
-	Ext.Function.defer(function() {
-	    u2f.register(challenge.appId, [challenge], [], function(response) {
-		msg.close();
-		if (response.errorCode) {
-		    me.showError(response.errorCode);
-		} else {
-		    me.respondToU2FChallenge(response);
-		}
-	    });
-	}, 500, me);
-    },
-
-    respondToU2FChallenge: function(data) {
-	var me = this;
-	var params = {
-	    userid: me.userid,
-	    action: 'confirm',
-	    response: JSON.stringify(data),
-	};
-	if (Proxmox.UserName !== 'root at pam') {
-	    params.password = me.lookup('password').value;
-	}
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/access/tfa',
-	    params: params,
-	    method: 'PUT',
-	    success: function() {
-		me.close();
-		Ext.Msg.show({
-		    title: gettext('Success'),
-		    message: gettext('U2F Device successfully connected.'),
-		    buttons: Ext.Msg.OK,
-		});
-	    },
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	});
-    },
-
-    viewModel: {
-	data: {
-	    in_totp_tab: true,
-	    tfa_required: false,
-	    tfa_type: null, // dependencies of formulas should not be undefined
-	    valid: false,
-	    u2f_available: true,
-	    secret: "",
-	},
-	formulas: {
-	    showTOTPVerifiction: function(get) {
-		return get('secret').length > 0 && get('canSetupTOTP');
-	    },
-	    canDeleteTFA: function(get) {
-		return get('tfa_type') !== null && !get('tfa_required');
-	    },
-	    canSetupTOTP: function(get) {
-		var tfa = get('tfa_type');
-		return tfa === null || tfa === 'totp' || tfa === 1;
-	    },
-	    canSetupU2F: function(get) {
-		var tfa = get('tfa_type');
-		return get('u2f_available') && (tfa === null || tfa === 'u2f' || tfa === 1);
-	    },
-	    secretEmpty: function(get) {
-		return get('secret').length === 0;
-	    },
-	    selectedTab: function(get) {
-		return (get('tfa_type') || 'totp') + '-panel';
-	    },
-	},
-    },
-
-    afterLoading: function(realm_tfa_type, user_tfa_type) {
-	var me = this;
-	var viewmodel = me.getViewModel();
-	if (user_tfa_type === 'oath') {
-	    user_tfa_type = 'totp';
-	    viewmodel.set('secret', '');
-	}
-
-	// if the user has no tfa, generate a secret for him
-	if (!user_tfa_type) {
-	    me.getController().randomizeSecret();
-	}
-
-	viewmodel.set('tfa_type', user_tfa_type || null);
-	if (!realm_tfa_type) {
-	    // There's no TFA enforced by the realm, everything works.
-	    viewmodel.set('u2f_available', true);
-	    viewmodel.set('tfa_required', false);
-	} else if (realm_tfa_type === 'oath') {
-	    // The realm explicitly requires TOTP
-	    if (user_tfa_type !== 'totp' && user_tfa_type !== null) {
-		// user had a different tfa method, so
-		// we have to change back to the totp tab and
-		// generate a secret
-		viewmodel.set('tfa_type', 'totp');
-		me.getController().randomizeSecret();
-	    }
-	    viewmodel.set('tfa_required', true);
-	    viewmodel.set('u2f_available', false);
-	} else {
-	    // The realm enforces some other TFA type (yubico)
-	    me.close();
-	    Ext.Msg.alert(
-		gettext('Error'),
-		Ext.String.format(
-		    gettext("Custom 2nd factor configuration is not supported on realms with '{0}' TFA."),
-		    realm_tfa_type,
-		),
-	    );
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[qrupdate=true]': {
-		change: function() {
-		    this.getView().updateQrCode();
-		},
-	    },
-	    'field': {
-		validitychange: function(field, valid) {
-		    var me = this;
-		    var viewModel = me.getViewModel();
-		    var form = me.lookup('totp_form');
-		    var challenge = me.lookup('challenge');
-		    var password = me.lookup('password');
-		    viewModel.set('valid', form.isValid() && challenge.isValid() && password.isValid());
-		},
-	    },
-	    '#': {
-		show: function() {
-		    let view = this.getView();
-
-		    Proxmox.Utils.API2Request({
-			url: '/access/users/' + encodeURIComponent(view.userid) + '/tfa',
-			waitMsgTarget: view.down('#tfatabs'),
-			method: 'GET',
-			success: function(response, opts) {
-			    let data = response.result.data;
-			    view.afterLoading(data.realm, data.user);
-			},
-			failure: function(response, opts) {
-			    view.close();
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			},
-		    });
-
-		    view.qrdiv = document.createElement('center');
-		    view.qrcode = new QRCode(view.qrdiv, {
-			width: 256,
-			height: 256,
-			correctLevel: QRCode.CorrectLevel.M,
-		    });
-		    view.down('#qrbox').getEl().appendChild(view.qrdiv);
-
-		    if (Proxmox.UserName === 'root at pam') {
-			view.lookup('password').setVisible(false);
-			view.lookup('password').setDisabled(true);
-		    }
-		},
-	    },
-	    '#tfatabs': {
-		tabchange: function(panel, newcard) {
-		    this.getViewModel().set('in_totp_tab', newcard.itemId === 'totp-panel');
-		},
-	    },
-	},
-
-	applySettings: function() {
-	    let me = this;
-	    let values = me.lookup('totp_form').getValues();
-	    let params = {
-		userid: me.getView().userid,
-		action: 'new',
-		key: 'v2-' + values.secret,
-		config: PVE.Parser.printPropertyString({
-		    type: 'oath',
-		    digits: values.digits,
-		    step: values.step,
-		}),
-		// this is used to verify that the client generates the correct codes:
-		response: me.lookup('challenge').value,
-	    };
-
-	    if (Proxmox.UserName !== 'root at pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-	    });
-	},
-
-	deleteTFA: function() {
-	    let me = this;
-	    let params = {
-		userid: me.getView().userid,
-		action: 'delete',
-	    };
-
-	    if (Proxmox.UserName !== 'root at pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-	    });
-	},
-
-	randomizeSecret: function() {
-	    let me = this;
-	    let rnd = new Uint8Array(32);
-	    window.crypto.getRandomValues(rnd);
-	    let data = '';
-	    rnd.forEach(function(b) {
-		// secret must be base32, so just use the first 5 bits
-		b = b & 0x1f;
-		if (b < 26) {
-		    data += String.fromCharCode(b + 0x41); // A..Z
-		} else {
-		    data += String.fromCharCode(b-26 + 0x32); // 2..7
-		}
-	    });
-	    me.getViewModel().set('secret', data);
-	},
-
-	startU2FRegistration: function() {
-	    let me = this;
-
-	    let params = {
-		userid: me.getView().userid,
-		action: 'new',
-	    };
-
-	    if (Proxmox.UserName !== 'root at pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response) {
-		    me.getView().doU2FChallenge(response);
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-	    });
-	},
-    },
-
-    items: [
-	{
-	    xtype: 'tabpanel',
-	    itemId: 'tfatabs',
-	    reference: 'tfatabs',
-	    border: false,
-	    bind: {
-		activeTab: '{selectedTab}',
-	    },
-	    items: [
-		{
-		    xtype: 'panel',
-		    title: 'TOTP',
-		    itemId: 'totp-panel',
-		    reference: 'totp_panel',
-		    tfa_type: 'totp',
-		    border: false,
-		    bind: {
-			disabled: '{!canSetupTOTP}',
-		    },
-		    layout: {
-			type: 'vbox',
-			align: 'stretch',
-		    },
-		    items: [
-			{
-			    xtype: 'form',
-			    layout: 'anchor',
-			    border: false,
-			    reference: 'totp_form',
-			    fieldDefaults: {
-				anchor: '100%',
-				padding: '0 5',
-			    },
-			    items: [
-				{
-				    xtype: 'displayfield',
-				    fieldLabel: gettext('User name'),
-				    renderer: Ext.String.htmlEncode,
-				    cbind: {
-					value: '{userid}',
-				    },
-				},
-				{
-				    layout: 'hbox',
-				    border: false,
-				    padding: '0 0 5 0',
-				    items: [{
-					xtype: 'textfield',
-					fieldLabel: gettext('Secret'),
-					emptyText: gettext('Unchanged'),
-					name: 'secret',
-					reference: 'tfa_secret',
-					regex: /^[A-Z2-7=]+$/,
-					regexText: 'Must be base32 [A-Z2-7=]',
-					maskRe: /[A-Z2-7=]/,
-					qrupdate: true,
-					bind: {
-					    value: "{secret}",
-					},
-					flex: 4,
-				    },
-				    {
-					xtype: 'button',
-					text: gettext('Randomize'),
-					reference: 'randomize_button',
-					handler: 'randomizeSecret',
-					flex: 1,
-				    }],
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Time period'),
-				    name: 'step',
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    value: 30,
-				    minValue: 10,
-				    qrupdate: true,
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Digits'),
-				    name: 'digits',
-				    value: 6,
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    minValue: 6,
-				    maxValue: 8,
-				    qrupdate: true,
-				},
-				{
-				    xtype: 'textfield',
-				    fieldLabel: gettext('Issuer Name'),
-				    name: 'issuer',
-				    value: 'Proxmox Web UI',
-				    qrupdate: true,
-				},
-			    ],
-			},
-			{
-			    xtype: 'box',
-			    itemId: 'qrbox',
-			    visible: false, // will be enabled when generating a qr code
-			    bind: {
-				visible: '{!secretEmpty}',
-			    },
-			    style: {
-				'background-color': 'white',
-				padding: '5px',
-				width: '266px',
-				height: '266px',
-			    },
-			},
-			{
-			    xtype: 'textfield',
-			    fieldLabel: gettext('Verification Code'),
-			    allowBlank: false,
-			    reference: 'challenge',
-			    bind: {
-				disabled: '{!showTOTPVerifiction}',
-				visible: '{showTOTPVerifiction}',
-			    },
-			    padding: '0 5',
-			    emptyText: gettext('Scan QR code and enter TOTP auth. code to verify'),
-			},
-		    ],
-		},
-		{
-		    title: 'U2F',
-		    itemId: 'u2f-panel',
-		    reference: 'u2f_panel',
-		    tfa_type: 'u2f',
-		    border: false,
-		    padding: '5 5',
-		    layout: {
-			type: 'vbox',
-			align: 'middle',
-		    },
-		    bind: {
-			disabled: '{!canSetupU2F}',
-		    },
-		    items: [
-			{
-			    xtype: 'label',
-			    width: 500,
-			    text: gettext('To register a U2F device, connect the device, then click the button and follow the instructions.'),
-			},
-		    ],
-		},
-	    ],
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    reference: 'password',
-	    allowBlank: false,
-	    validateBlank: true,
-	    padding: '0 0 5 5',
-	    emptyText: gettext('verify current password'),
-	},
-    ],
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	},
-	'->',
-	{
-	    text: gettext('Apply'),
-	    handler: 'applySettings',
-	    bind: {
-		hidden: '{!in_totp_tab}',
-		disabled: '{!valid}',
-	    },
-	},
-	{
-	    xtype: 'button',
-	    text: gettext('Register U2F Device'),
-	    handler: 'startU2FRegistration',
-	    bind: {
-		hidden: '{in_totp_tab}',
-		disabled: '{tfa_type}',
-	    },
-	},
-	{
-	    text: gettext('Delete'),
-	    reference: 'delete_button',
-	    disabled: true,
-	    handler: 'deleteTFA',
-	    bind: {
-		disabled: '{!canDeleteTFA}',
-	    },
-	},
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid given";
-	}
-
-	me.callParent();
-
-	Ext.GlobalEvents.fireEvent('proxmoxShowHelp', 'pveum_tfa_auth');
-    },
-});
diff --git a/www/manager6/dc/UserView.js b/www/manager6/dc/UserView.js
index 9c84bf7d..f397731d 100644
--- a/www/manager6/dc/UserView.js
+++ b/www/manager6/dc/UserView.js
@@ -77,32 +77,6 @@ Ext.define('PVE.dc.UserView', {
 		});
 	    },
 	});
-	let tfachange_btn = new Proxmox.button.Button({
-	    text: 'TFA',
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(record) {
-		let type = record.data['realm-type'];
-		if (type) {
-		    if (PVE.Utils.authSchema[type]) {
-			return !!PVE.Utils.authSchema[type].tfa;
-		    }
-		}
-		return false;
-	    },
-	    handler: function(btn, event, rec) {
-		var d = rec.data;
-		var tfa_type = PVE.Parser.parseTfaType(d.keys);
-		Ext.create('PVE.window.TFAEdit', {
-		    tfa_type: tfa_type,
-		    userid: d.userid,
-		    autoShow: true,
-		    listeners: {
-			destroy: () => reload(),
-		    },
-		});
-	    },
-	});
 
 	var perm_btn = new Proxmox.button.Button({
 	    text: gettext('Permissions'),
@@ -140,7 +114,6 @@ Ext.define('PVE.dc.UserView', {
 		remove_btn,
 		'-',
 		pwchange_btn,
-		tfachange_btn,
 		'-',
 		perm_btn,
 	    ],
-- 
2.30.2






More information about the pve-devel mailing list