From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 8C55A7252C for ; Tue, 15 Jun 2021 16:09:15 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 077D92F494 for ; Tue, 15 Jun 2021 16:09:15 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id D56242F2C3 for ; Tue, 15 Jun 2021 16:09:09 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id AEFCD43EA8 for ; Tue, 15 Jun 2021 16:09:09 +0200 (CEST) From: Lorenz Stechauner To: pve-devel@lists.proxmox.com Date: Tue, 15 Jun 2021 16:08:41 +0200 Message-Id: <20210615140841.117933-9-l.stechauner@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210615140841.117933-1-l.stechauner@proxmox.com> References: <20210615140841.117933-1-l.stechauner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.917 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [caps.storage] Subject: [pve-devel] [PATCH v8 manager 5/5] fix #1710: ui: storage: add download from url button X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Jun 2021 14:09:15 -0000 uses the common function PVE::Tools::download_file_from_url to download a iso image or container template. note: Only users with permissions `Sys.Audit` and `Sys.Modify` on `/` are permitted to use the api endpoints due to security reasons. (it is possible to download files from internal networks which would be not visible/accessible from outside) Signed-off-by: Lorenz Stechauner --- www/manager6/storage/Browser.js | 8 + www/manager6/storage/ContentView.js | 247 +++++++++++++++++++++++++--- 2 files changed, 231 insertions(+), 24 deletions(-) diff --git a/www/manager6/storage/Browser.js b/www/manager6/storage/Browser.js index 5fee94c7..fe5df3e2 100644 --- a/www/manager6/storage/Browser.js +++ b/www/manager6/storage/Browser.js @@ -53,6 +53,9 @@ Ext.define('PVE.storage.Browser', { let plugin = res.plugintype; let contents = res.content.split(','); + let enableUpload = !!caps.storage['Datastore.AllocateTemplate']; + let enableDownloadUrl = enableUpload && !!(caps.nodes['Sys.Audit'] && caps.nodes['Sys.Modify']); + if (contents.includes('backup')) { me.items.push({ xtype: 'pveStorageBackupView', @@ -91,6 +94,8 @@ Ext.define('PVE.storage.Browser', { itemId: 'contentIso', content: 'iso', pluginType: plugin, + enableUploadButton: enableUpload, + enableDownloadUrlButton: enableDownloadUrl, useUploadButton: true, }); } @@ -101,6 +106,9 @@ Ext.define('PVE.storage.Browser', { iconCls: 'fa fa-file-o lxc', itemId: 'contentVztmpl', pluginType: plugin, + enableUploadButton: enableUpload, + enableDownloadUrlButton: enableDownloadUrl, + useUploadButton: true, }); } if (contents.includes('snippets')) { diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js index dd6df4b1..6171d30c 100644 --- a/www/manager6/storage/ContentView.js +++ b/www/manager6/storage/ContentView.js @@ -191,6 +191,191 @@ Ext.define('PVE.storage.Upload', { }, }); +Ext.define('PVE.storage.DownloadUrl', { + extend: 'Proxmox.window.Edit', + alias: 'widget.pveStorageDownloadUrl', + mixins: ['Proxmox.Mixin.CBind'], + + isCreate: true, + + method: 'POST', + + showTaskViewer: true, + + title: gettext('Download from URL'), + submitText: gettext('Download'), + + cbindData: function(initialConfig) { + var me = this; + return { + nodename: me.nodename, + storage: me.storage, + contents: me.contents, + content: me.contents[0], + }; + }, + + cbind: { + url: '/nodes/{nodename}/storage/{storage}/download-url', + }, + + controller: { + xclass: 'Ext.app.ViewController', + + urlChange: function(field) { + let me = this; + let view = me.getView(); + field = view.down('[name=url]'); + field.setValidation("Waiting for response..."); + field.validate(); + view.setValues({ size: "" }); + Proxmox.Utils.API2Request({ + url: `/nodes/${view.nodename}/query-url-metadata`, + method: 'GET', + params: { + url: field.getValue(), + 'verify-certificates': view.getValues()['verify-certificates'], + }, + failure: function(res, opt) { + field.setValidation(res.result.message); + field.validate(); + view.setValues({ + size: "", + mimetype: "", + }); + }, + success: function(res, opt) { + field.setValidation(); + field.validate(); + + let data = res.result.data; + view.setValues({ + filename: data.filename || "", + size: (data.size && Proxmox.Utils.format_size(data.size)) || "", + mimetype: data.mimetype || "", + }); + }, + }); + }, + + hashChange: function(field) { + let checksum = Ext.getCmp('downloadUrlChecksum'); + if (field.getValue() === '__default__') { + checksum.setDisabled(true); + checksum.setValue(""); + checksum.allowBlank = true; + } else { + checksum.setDisabled(false); + checksum.allowBlank = false; + } + }, + }, + + items: [ + { + xtype: 'inputpanel', + waitMsgTarget: true, + border: false, + columnT: [ + { + xtype: 'textfield', + name: 'url', + allowBlank: false, + fieldLabel: gettext('URL'), + listeners: { + change: { + buffer: 500, + fn: 'urlChange', + }, + }, + }, + { + xtype: 'textfield', + name: 'filename', + allowBlank: false, + fieldLabel: gettext('File name'), + }, + ], + column1: [ + { + xtype: 'pveContentTypeSelector', + fieldLabel: gettext('Content'), + name: 'content', + allowBlank: false, + cbind: { + cts: '{contents}', + value: '{content}', + }, + }, + ], + column2: [ + { + xtype: 'textfield', + name: 'size', + disabled: true, + fieldLabel: gettext('File size'), + emptyText: gettext('unknown'), + }, + ], + advancedColumn1: [ + { + xtype: 'pveHashAlgorithmSelector', + name: 'checksum-algorithm', + fieldLabel: gettext('Hash algorithm'), + allowBlank: true, + hasNoneOption: true, + value: '__default__', + listeners: { + change: 'hashChange', + }, + }, + { + xtype: 'textfield', + name: 'checksum', + fieldLabel: gettext('Checksum'), + allowBlank: true, + disabled: true, + emptyText: gettext('none'), + id: 'downloadUrlChecksum', + }, + ], + advancedColumn2: [ + { + xtype: 'textfield', + fieldLabel: gettext('MIME type'), + name: 'mimetype', + disabled: true, + editable: false, + emptyText: gettext('unknown'), + }, + { + xtype: 'proxmoxcheckbox', + name: 'verify-certificates', + fieldLabel: gettext('Verify certificates'), + uncheckedValue: 0, + checked: true, + listeners: { + change: 'urlChange', + }, + }, + ], + }, + ], + + initComponent: function() { + var me = this; + + if (!me.nodename) { + throw "no node name specified"; + } + if (!me.storage) { + throw "no storage ID specified"; + } + + me.callParent(); + }, +}); + Ext.define('PVE.storage.ContentView', { extend: 'Ext.grid.GridPanel', @@ -249,36 +434,50 @@ Ext.define('PVE.storage.ContentView', { Proxmox.Utils.monStoreErrors(me, store); - let uploadButton = Ext.create('Proxmox.button.Button', { - text: gettext('Upload'), - handler: function() { - let win = Ext.create('PVE.storage.Upload', { - nodename: nodename, - storage: storage, - contents: [content], - }); - win.show(); - win.on('destroy', reload); - }, - }); - - let removeButton = Ext.create('Proxmox.button.StdRemoveButton', { - selModel: sm, - delay: 5, - callback: function() { - reload(); - }, - baseurl: baseurl + '/', - }); - if (!me.tbar) { me.tbar = []; } if (me.useUploadButton) { - me.tbar.push(uploadButton); + me.tbar.unshift( + { + xtype: 'button', + text: gettext('Upload'), + disabled: !me.enableUploadButton, + handler: function() { + Ext.create('PVE.storage.Upload', { + nodename: nodename, + storage: storage, + contents: [content], + autoShow: true, + taskDone: () => reload(), + }); + }, + }, + { + xtype: 'button', + text: gettext('Download from URL'), + disabled: !me.enableDownloadUrlButton, + handler: function() { + Ext.create('PVE.storage.DownloadUrl', { + nodename: nodename, + storage: storage, + contents: [content], + autoShow: true, + taskDone: () => reload(), + }); + }, + }, + '-', + ); } if (!me.useCustomRemoveButton) { - me.tbar.push(removeButton); + me.tbar.push({ + xtype: 'proxmoxStdRemoveButton', + selModel: sm, + delay: 5, + callback: () => reload(), + baseurl: baseurl + '/', + }); } me.tbar.push( '->', -- 2.20.1