mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-08-15 03:58:26 +00:00
ui: storage/PBS: allow to download/print new encryption key
note that the key is really important, add our recommended backup strategy (copy to PW manager, save onto secured USB drive, print paperkey and secure it) with the respective buttons to do so. Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
71dec88f99
commit
d1a7c6ee15
@ -1,3 +1,4 @@
|
|||||||
|
/*global QRCode*/
|
||||||
Ext.define('Proxmox.form.PBSEncryptionCheckbox', {
|
Ext.define('Proxmox.form.PBSEncryptionCheckbox', {
|
||||||
extend: 'Ext.form.field.Checkbox',
|
extend: 'Ext.form.field.Checkbox',
|
||||||
xtype: 'pbsEncryptionCheckbox',
|
xtype: 'pbsEncryptionCheckbox',
|
||||||
@ -60,11 +61,203 @@ Ext.define('Proxmox.form.PBSEncryptionCheckbox', {
|
|||||||
vm.set('isCreate', me.isCreate);
|
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', {
|
Ext.define('PVE.storage.PBSInputPanel', {
|
||||||
extend: 'PVE.panel.StorageBase',
|
extend: 'PVE.panel.StorageBase',
|
||||||
|
|
||||||
//onlineHelp: 'storage_pbs',
|
//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() {
|
initComponent: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user