]> git.proxmox.com Git - pve-manager.git/blobdiff - www/manager6/storage/PBSEdit.js
ui: storage/PBS: allow to download/print new encryption key
[pve-manager.git] / www / manager6 / storage / PBSEdit.js
index c471c65a63445dc8a3704e897c5152889879743d..ce72fd1a2a44b965787b4bcd31fc50967bdcb882 100644 (file)
@@ -1,3 +1,4 @@
+/*global QRCode*/
 Ext.define('Proxmox.form.PBSEncryptionCheckbox', {
     extend: 'Ext.form.field.Checkbox',
     xtype: 'pbsEncryptionCheckbox',
@@ -60,11 +61,203 @@ Ext.define('Proxmox.form.PBSEncryptionCheckbox', {
        vm.set('isCreate', me.isCreate);
     },
 });
+
+Ext.define('PVE.Storage.PBSKeyShow', {
+    extend: 'Ext.window.Window',
+    alias: ['widget.pveKeyShow'],
+    mixins: ['Proxmox.Mixin.CBind'],
+
+    width: 600,
+    modal: true,
+    resizable: false,
+    title: gettext('Important: Save your Encryption Key'),
+
+    // avoid that esc closes this by mistake, force user to more manual action
+    onEsc: Ext.emptyFn,
+    closable: false,
+
+    items: [
+       {
+           xtype: 'form',
+           layout: {
+               type: 'vbox',
+               align: 'stretch',
+           },
+           bodyPadding: 10,
+           border: false,
+           defaults: {
+               anchor: '100%',
+               border: false,
+               padding: '10 0 0 0',
+            },
+           items: [
+               {
+                   xtype: 'textfield',
+                   fieldLabel: gettext('Key'),
+                   labelWidth: 30,
+                   inputId: 'encryption-key-value',
+                   cbind: {
+                       value: '{key}',
+                   },
+                   editable: false,
+               },
+               {
+                   xtype: 'component',
+                   html: gettext('Keep your master key safe, but easily accessible for disaster recovery.')
+                       + '<br>' + gettext('We recommend the following safe-keeping strategy:'),
+               },
+               {
+                   xtyp: 'container',
+                   layout: 'hbox',
+                   items: [
+                       {
+                           xtype: 'component',
+                           html: '1. ' + gettext('Save the key in your password manager.'),
+                           flex: 1,
+                       },
+                       {
+                           xtype: 'button',
+                           text: gettext('Copy Key'),
+                           iconCls: 'fa fa-clipboard x-btn-icon-el-default-toolbar-small',
+                           cls: 'x-btn-default-toolbar-small proxmox-inline-button',
+                           width: 110,
+                           handler: function(b) {
+                               document.getElementById('encryption-key-value').select();
+                               document.execCommand("copy");
+                           },
+                       },
+                   ],
+               },
+               {
+                   xtype: 'container',
+                   layout: 'hbox',
+                   items: [
+                       {
+                           xtype: 'component',
+                           html: '2. ' + gettext('Download the key to a USB (pen) drive, placed in secure vault.'),
+                           flex: 1,
+                       },
+                       {
+                           xtype: 'button',
+                           text: gettext('Download'),
+                           iconCls: 'fa fa-download x-btn-icon-el-default-toolbar-small',
+                           cls: 'x-btn-default-toolbar-small proxmox-inline-button',
+                           width: 110,
+                           handler: function(b) {
+                               let win = this.up('window');
+
+                               let pveID = PVE.ClusterName || window.location.hostname;
+                               let name = `pve-${pveID}-storage-${win.sid}.enc`;
+
+                               let hiddenElement = document.createElement('a');
+                               hiddenElement.href = 'data:attachment/text,' + encodeURI(win.key);
+                               hiddenElement.target = '_blank';
+                               hiddenElement.download = name;
+                               hiddenElement.click();
+                           },
+                       },
+                   ],
+               },
+               {
+                   xtype: 'container',
+                   layout: 'hbox',
+                   items: [
+                       {
+                           xtype: 'component',
+                           html: '3. ' + gettext('Print as paperkey, laminated and placed in secure vault.'),
+                           flex: 1,
+                       },
+                       {
+                           xtype: 'button',
+                           text: gettext('Print Key'),
+                           iconCls: 'fa fa-print x-btn-icon-el-default-toolbar-small',
+                           cls: 'x-btn-default-toolbar-small proxmox-inline-button',
+                           width: 110,
+                           handler: function(b) {
+                               let win = this.up('window');
+                               win.paperkey(win.key);
+                           },
+                       },
+                   ],
+               },
+           ],
+       },
+       {
+           xtype: 'component',
+           border: false,
+           padding: '10 10 10 10',
+           userCls: 'pmx-hint',
+           html: gettext('Please save the encryption key - loosing it will render any backup created with it unuseable'),
+       },
+    ],
+    buttons: [
+       {
+           text: gettext('Close'),
+           handler: function(b) {
+               let win = this.up('window');
+               win.close();
+           },
+       },
+    ],
+    paperkey: function(key) {
+       let me = this;
+
+       const qrwidth = 500;
+       let qrdiv = document.createElement('div');
+       let qrcode = new QRCode(qrdiv, {
+           width: qrwidth,
+           height: qrwidth,
+           correctLevel: QRCode.CorrectLevel.H,
+       });
+       qrcode.makeCode(key);
+
+       let printFrame = document.createElement("iframe");
+       Object.assign(printFrame.style, {
+           position: "fixed",
+           right: "0",
+           bottom: "0",
+           width: "0",
+           height: "0",
+           border: "0",
+       });
+       const prettifiedKey = JSON.stringify(JSON.parse(key), null, 2);
+       const keyQrBase64 = qrdiv.children[0].toDataURL("image/png");
+       const html = `<html><head><script>
+           window.addEventListener('DOMContentLoaded', (ev) => window.print());
+       </script><style>@media print and (max-height: 150mm) {
+         h4, p { margin: 0; font-size: 1em; }
+       }</style></head><body style="padding: 5px;">
+       <h4>Encryption Key - Storage '${me.sid}'</h4>
+<p style="font-size: 1.2em; font-family: monospace; white-space: pre-wrap;">
+-----BEGIN PROXMOX BACKUP KEY-----
+${prettifiedKey}
+-----END PROXMOX BACKUP KEY-----</p>
+       <center><img style="width: 100%; max-width: ${qrwidth}px;" src="${keyQrBase64}"></center>
+       </body></html>`;
+
+       printFrame.src = "data:text/html;base64," + btoa(html);
+       document.body.appendChild(printFrame);
+    },
+});
+
 Ext.define('PVE.storage.PBSInputPanel', {
     extend: 'PVE.panel.StorageBase',
 
     //onlineHelp: 'storage_pbs',
 
+    apiCallDone: function(success, response, options) {
+       let res = response.result.data;
+       if (!(res && res.config && res.config['encryption-key'])) {
+           return;
+       }
+       let key = res.config['encryption-key'];
+       Ext.create('PVE.Storage.PBSKeyShow', {
+           autoShow: true,
+           sid: res.storage,
+           key: key,
+       });
+    },
+
     initComponent: function() {
        var me = this;