From b1339314b698aadeb63b9eb65a00f8f0be5fb195 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 10 Aug 2016 12:13:19 +0200 Subject: [PATCH] lxc: wizard: ssh key --- www/manager6/Parser.js | 30 ++++++ www/manager6/lxc/CreateWizard.js | 163 +++++++++++++++++++++++-------- 2 files changed, 154 insertions(+), 39 deletions(-) diff --git a/www/manager6/Parser.js b/www/manager6/Parser.js index c049d062..c796d35b 100644 --- a/www/manager6/Parser.js +++ b/www/manager6/Parser.js @@ -493,5 +493,35 @@ Ext.define('PVE.Parser', { statics: { } return cpustr + optstr; + }, + + parseSSHKey: function(key) { + // |--- options can have quotes--| type key comment + var keyre = /^(?:((?:[^\s"]|\"(?:\\.|[^"\\])*")+)\s+)?(\S+)\s+(\S+)(?:\s+(.*))?$/; + var typere = /^(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)$/; + + var m = key.match(keyre); + if (!m) { + return null; + } + if (m.length < 3 || !m[2]) { // [2] is always either type or key + return null; + } + if (m[1] && m[1].match(typere)) { + return { + type: m[1], + key: m[2], + comment: m[3] + }; + } + if (m[2].match(typere)) { + return { + options: m[1], + type: m[2], + key: m[3], + comment: m[4] + }; + } + return null; } }}); diff --git a/www/manager6/lxc/CreateWizard.js b/www/manager6/lxc/CreateWizard.js index b0df9989..a6cb59d9 100644 --- a/www/manager6/lxc/CreateWizard.js +++ b/www/manager6/lxc/CreateWizard.js @@ -2,6 +2,23 @@ Ext.define('PVE.lxc.CreateWizard', { extend: 'PVE.window.Wizard', + loadSSHKeyFromFile: function(file) { + var me = this; + // ssh-keygen produces 740 bytes for an average 4096 bit rsa key, with + // a user@host comment, 1420 for 8192 bits; current max is 16kbit + // assume: 740*8 for max. 32kbit (5920 byte file) + // round upwards to nearest nice number => 8192 bytes, leaves lots of comment space + if (file.size > 8192) { + Ext.Msg.alert(gettext('Error'), gettext("Invalid file size: ") + file.size); + return; + } + var reader = new FileReader(); + reader.onload = function(evt) { + me.sshkeyfield.setValue(evt.target.result); + }; + reader.readAsText(file); + }, + initComponent: function() { var me = this; @@ -50,6 +67,106 @@ Ext.define('PVE.lxc.CreateWizard', { create: true }); + var passwordfield = Ext.createWidget('textfield', { + inputType: 'password', + name: 'password', + value: '', + fieldLabel: gettext('Password'), + allowBlank: false, + minLength: 5, + change: function(f, value) { + if (!me.rendered) { + return; + } + me.down('field[name=confirmpw]').validate(); + } + }); + + me.sshkeyfield = Ext.createWidget('textfield', { + xtype: 'textfield', + name: 'ssh-public-keys', + value: '', + fieldLabel: gettext('SSH public key'), + allowBlank: true, + validator: function(value) { + if (value.length) { + var key = PVE.Parser.parseSSHKey(value); + if (!key) { + return "Failed to recognize ssh key"; + } + me.down('field[name=password]').allowBlank = true; + } else { + me.down('field[name=password]').allowBlank = false; + } + me.down('field[name=password]').validate(); + return true; + }, + afterRender: function() { + if (!window.FileReader) { + // No FileReader support in this browser + return; + } + var cancel = function(ev) { + ev = ev.event; + if (ev.preventDefault) { + ev.preventDefault(); + } + }; + me.sshkeyfield.inputEl.on('dragover', cancel); + me.sshkeyfield.inputEl.on('dragenter', cancel); + me.sshkeyfield.inputEl.on('drop', function(ev) { + ev = ev.event; + if (ev.preventDefault) { + ev.preventDefault(); + } + var files = ev.dataTransfer.files; + me.loadSSHKeyFromFile(files[0]); + }); + }, + }); + + var column2 = [ + { + xtype: 'pvePoolSelector', + fieldLabel: gettext('Resource Pool'), + name: 'pool', + value: '', + allowBlank: true + }, + passwordfield, + { + xtype: 'textfield', + inputType: 'password', + name: 'confirmpw', + value: '', + fieldLabel: gettext('Confirm password'), + allowBlank: true, + validator: function(value) { + var pw = me.down('field[name=password]').getValue(); + if (pw !== value) { + return "Passwords does not match!"; + } + return true; + } + }, + me.sshkeyfield + ]; + + if (window.FileReader) { + column2.push({ + xtype: 'filebutton', + name: 'file', + text: gettext('Load SSH Key File'), + listeners: { + change: function(btn, e, value) { + e = e.event; + me.loadSSHKeyFromFile(e.target.files[0]); + btn.reset(); + } + } + }); + } + Ext.applyIf(me, { subject: gettext('LXC Container'), items: [ @@ -90,45 +207,7 @@ Ext.define('PVE.lxc.CreateWizard', { allowBlank: true } ], - column2: [ - { - xtype: 'pvePoolSelector', - fieldLabel: gettext('Resource Pool'), - name: 'pool', - value: '', - allowBlank: true - }, - { - xtype: 'textfield', - inputType: 'password', - name: 'password', - value: '', - fieldLabel: gettext('Password'), - allowBlank: false, - minLength: 5, - change: function(f, value) { - if (!me.rendered) { - return; - } - me.down('field[name=confirmpw]').validate(); - } - }, - { - xtype: 'textfield', - inputType: 'password', - name: 'confirmpw', - value: '', - fieldLabel: gettext('Confirm password'), - allowBlank: false, - validator: function(value) { - var pw = me.down('field[name=password]').getValue(); - if (pw !== value) { - return "Passwords does not match!"; - } - return true; - } - } - ], + column2: column2, onGetValues: function(values) { delete values.confirmpw; if (!values.pool) { @@ -204,6 +283,12 @@ Ext.define('PVE.lxc.CreateWizard', { delete kv.nodename; delete kv.tmplstorage; + if (!kv['ssh-public-keys'].length) { + delete kv['ssh-public-keys']; + } else if (!kv['password'].length) { + delete kv['password']; + } + PVE.Utils.API2Request({ url: '/nodes/' + nodename + '/lxc', waitMsgTarget: me,