From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 1C4F01FF140 for ; Fri, 10 Apr 2026 18:55:35 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id E477D24350; Fri, 10 Apr 2026 18:56:13 +0200 (CEST) From: Christian Ebner To: pbs-devel@lists.proxmox.com Subject: [PATCH proxmox-backup v2 20/27] ui: expose assigning encryption key to sync jobs Date: Fri, 10 Apr 2026 18:54:47 +0200 Message-ID: <20260410165454.1578501-21-c.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260410165454.1578501-1-c.ebner@proxmox.com> References: <20260410165454.1578501-1-c.ebner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1775840040073 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.070 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy 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 Message-ID-Hash: PXXKMJ7OMBARFBVIRLQZGHUDV3EVDRS7 X-Message-ID-Hash: PXXKMJ7OMBARFBVIRLQZGHUDV3EVDRS7 X-MailFrom: c.ebner@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox Backup Server development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This allows to select pre-defined encryption keys and assign them to the sync job configuration. Sync keys can be either assigned as active encryption key to sync jobs in push direction, to be used when pushing new contents or associated to a sync job in pull direction, then used to decrypt contents with matching key fingerprint. As active encryption key only ones with are not archived can be used, while associations can be made also with archived keys, to still be able do decrypt contents on pull and to avoid key deletion if associated to either push or pull sync jobs. Signed-off-by: Christian Ebner --- www/Makefile | 1 + www/form/EncryptionKeySelector.js | 96 +++++++++++++++++++++++++++++++ www/window/SyncJobEdit.js | 30 ++++++++++ 3 files changed, 127 insertions(+) create mode 100644 www/form/EncryptionKeySelector.js diff --git a/www/Makefile b/www/Makefile index 08ad50846..51da9d74e 100644 --- a/www/Makefile +++ b/www/Makefile @@ -55,6 +55,7 @@ JSSRC= \ form/GroupSelector.js \ form/GroupFilter.js \ form/VerifyOutdatedAfter.js \ + form/EncryptionKeySelector.js \ data/RunningTasksStore.js \ button/TaskButton.js \ panel/PrunePanel.js \ diff --git a/www/form/EncryptionKeySelector.js b/www/form/EncryptionKeySelector.js new file mode 100644 index 000000000..e0390e56a --- /dev/null +++ b/www/form/EncryptionKeySelector.js @@ -0,0 +1,96 @@ +Ext.define('PBS.form.EncryptionKeySelector', { + extend: 'Ext.form.field.ComboBox', + alias: 'widget.pbsEncryptionKeySelector', + + queryMode: 'local', + + valueField: 'id', + displayField: 'id', + + emptyText: gettext('None'), + + listConfig: { + columns: [ + { + dataIndex: 'id', + header: gettext('Key ID'), + sortable: true, + flex: 1, + }, + { + dataIndex: 'created', + header: gettext('Created'), + sortable: true, + renderer: Proxmox.Utils.render_timestamp, + flex: 1, + }, + { + dataIndex: 'archived-at', + header: gettext('Archived'), + renderer: (val) => (val ? Proxmox.Utils.render_timestamp(val) : ''), + sortable: true, + flex: 1, + }, + ], + emptyText: `
${gettext('No key accessible.')}
`, + }, + + config: { + deleteEmpty: true, + extraRequestParams: {}, + }, + // override framework function to implement deleteEmpty behaviour + getSubmitData: function () { + let me = this; + + let data = null; + if (!me.disabled && me.submitValue) { + let val = me.getSubmitValue(); + if (val !== null && val !== '') { + data = {}; + data[me.getName()] = val; + } else if (me.getDeleteEmpty()) { + data = {}; + data.delete = me.getName(); + } + } + + return data; + }, + + triggers: { + clear: { + cls: 'pmx-clear-trigger', + weight: -1, + hidden: true, + handler: function () { + this.triggers.clear.setVisible(false); + this.setValue(''); + }, + }, + }, + + listeners: { + change: function (field, value) { + let canClear = (value ?? '') !== ''; + field.triggers.clear.setVisible(canClear); + }, + }, + + initComponent: function () { + let me = this; + + me.store = Ext.create('Ext.data.Store', { + model: 'pbs-encryption-keys', + autoLoad: true, + proxy: { + type: 'proxmox', + timeout: 30 * 1000, + url: `/api2/json/config/encryption-keys`, + extraParams: me.extraRequestParams, + }, + }); + + me.callParent(); + }, +}); diff --git a/www/window/SyncJobEdit.js b/www/window/SyncJobEdit.js index 074c7855a..9994f14e8 100644 --- a/www/window/SyncJobEdit.js +++ b/www/window/SyncJobEdit.js @@ -34,6 +34,7 @@ Ext.define('PBS.window.SyncJobEdit', { if (me.syncDirection === 'push') { me.subject = gettext('Sync Job - Push Direction'); me.syncDirectionPush = true; + me.syncCryptKeyMultiSelect = false; me.syncRemoteLabel = gettext('Target Remote'); me.syncRemoteDatastore = gettext('Target Datastore'); me.syncRemoteNamespace = gettext('Target Namespace'); @@ -560,6 +561,35 @@ Ext.define('PBS.window.SyncJobEdit', { }, ], }, + { + xtype: 'inputpanel', + title: gettext('Encryption'), + column1: [ + { + xtype: 'pbsEncryptionKeySelector', + name: 'active-encryption-key', + fieldLabel: gettext('Active Encryption Key'), + multiSelect: false, + cbind: { + deleteEmpty: '{!isCreate}', + disabled: '{!syncDirectionPush}', + hidden: '{!syncDirectionPush}', + }, + }, + { + xtype: 'pbsEncryptionKeySelector', + name: 'associated-key', + fieldLabel: gettext('Associated Keys'), + multiSelect: true, + cbind: { + deleteEmpty: '{!isCreate}', + }, + extraRequestParams: { + 'include-archived': true, + }, + }, + ], + }, ], }, }); -- 2.47.3