]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/node/ACME.js
1 Ext
.define('PVE.node.ACMEAccountCreate', {
2 extend
: 'Proxmox.window.Edit',
3 mixins
: ['Proxmox.Mixin.CBind'],
6 title
: gettext('Register Account'),
9 submitText
: gettext('Register'),
10 url
: '/cluster/acme/account',
16 xtype
: 'proxmoxtextfield',
17 fieldLabel
: gettext('Account Name'),
20 emptyText
: (get) => get('defaultExists') ? '' : 'default',
21 allowBlank
: (get) => !get('defaultExists'),
29 fieldLabel
: gettext('E-Mail')
32 xtype
: 'proxmoxComboGrid',
37 fieldLabel
: gettext('ACME Directory'),
40 fields
: ['name', 'url'],
44 url
: '/api2/json/cluster/acme/directories'
54 header
: gettext('Name'),
59 header
: gettext('URL'),
66 change: function(combogrid
, value
) {
72 var disp
= me
.up('window').down('#tos_url_display');
73 var field
= me
.up('window').down('#tos_url');
74 var checkbox
= me
.up('window').down('#tos_checkbox');
76 disp
.setValue(gettext('Loading'));
77 field
.setValue(undefined);
78 checkbox
.setValue(undefined);
79 checkbox
.setHidden(true);
81 Proxmox
.Utils
.API2Request({
82 url
: '/cluster/acme/tos',
87 success: function(response
, opt
) {
88 field
.setValue(response
.result
.data
);
89 disp
.setValue(response
.result
.data
);
90 checkbox
.setHidden(false);
92 failure: function(response
, opt
) {
93 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
100 xtype
: 'displayfield',
101 itemId
: 'tos_url_display',
102 renderer
: PVE
.Utils
.render_optional_url
,
103 name
: 'tos_url_display'
111 xtype
: 'proxmoxcheckbox',
112 itemId
: 'tos_checkbox',
113 boxLabel
: gettext('Accept TOS'),
115 validateValue: function(value
) {
116 if (value
&& this.checked
) {
126 Ext
.define('PVE.node.ACMEAccountView', {
127 extend
: 'Proxmox.window.Edit',
134 title
: gettext('Account'),
138 xtype
: 'displayfield',
139 fieldLabel
: gettext('E-Mail'),
143 xtype
: 'displayfield',
144 fieldLabel
: gettext('Created'),
148 xtype
: 'displayfield',
149 fieldLabel
: gettext('Status'),
153 xtype
: 'displayfield',
154 fieldLabel
: gettext('Directory'),
155 renderer
: PVE
.Utils
.render_optional_url
,
159 xtype
: 'displayfield',
160 fieldLabel
: gettext('Terms of Services'),
161 renderer
: PVE
.Utils
.render_optional_url
,
166 initComponent: function() {
169 if (!me
.accountname
) {
170 throw "no account name defined";
173 me
.url
= '/cluster/acme/account/' + me
.accountname
;
177 // hide OK/Reset button, because we just want to show data
178 me
.down('toolbar[dock=bottom]').setVisible(false);
181 success: function(response
) {
182 var data
= response
.result
.data
;
183 data
.email
= data
.account
.contact
[0];
184 data
.createdAt
= data
.account
.createdAt
;
185 data
.status
= data
.account
.status
;
192 Ext
.define('PVE.node.ACMEDomainEdit', {
193 extend
: 'Proxmox.window.Edit',
194 alias
: 'widget.pveACMEDomainEdit',
196 subject
: gettext('Domain'),
199 onlineHelp
: 'sysadmin_certificate_management',
204 onGetValues: function(values
) {
206 let win
= me
.up('pveACMEDomainEdit');
207 let nodeconfig
= win
.nodeconfig
;
208 let olddomain
= win
.domain
|| {};
211 digest
: nodeconfig
.digest
,
214 let configkey
= olddomain
.configkey
;
215 let acmeObj
= PVE
.Parser
.parseACME(nodeconfig
.acme
);
217 if (values
.type
=== 'dns') {
218 if (!olddomain
.configkey
|| olddomain
.configkey
=== 'acme') {
219 // look for first free slot
220 for (let i
= 0; i
< PVE
.Utils
.acmedomain_count
; i
++) {
221 if (nodeconfig
[`acmedomain${i}`] === undefined) {
222 configkey
= `acmedomain${i}`;
226 if (olddomain
.domain
) {
227 // we have to remove the domain from the acme domainlist
228 PVE
.Utils
.remove_domain_from_acme(acmeObj
, olddomain
.domain
);
229 params
.acme
= PVE
.Parser
.printACME(acmeObj
);
234 params
[configkey
] = PVE
.Parser
.printPropertyString(values
, 'domain');
236 if (olddomain
.configkey
&& olddomain
.configkey
!== 'acme') {
237 // delete the old dns entry
238 params
.delete = [olddomain
.configkey
];
241 // add new, remove old and make entries unique
242 PVE
.Utils
.add_domain_to_acme(acmeObj
, values
.domain
);
243 PVE
.Utils
.remove_domain_from_acme(acmeObj
, olddomain
.domain
);
244 params
.acme
= PVE
.Parser
.printACME(acmeObj
);
251 xtype
: 'proxmoxKVComboBox',
253 fieldLabel
: gettext('Challenge Type'),
257 ['standalone', 'HTTP'],
260 validator: function(value
) {
262 let win
= me
.up('pveACMEDomainEdit');
263 let oldconfigkey
= win
.domain
? win
.domain
.configkey
: undefined;
264 let val
= me
.getValue();
265 if (val
=== 'dns' && (!oldconfigkey
|| oldconfigkey
=== 'acme')) {
266 // we have to check if there is a 'acmedomain' slot left
268 for (let i
= 0; i
< PVE
.Utils
.acmedomain_count
; i
++) {
269 if (!win
.nodeconfig
[`acmedomain${i}`]) {
274 return gettext('Only 5 Domains with type DNS can be configured');
281 change: function(cb
, value
) {
283 let view
= me
.up('pveACMEDomainEdit');
284 let pluginField
= view
.down('field[name=plugin]');
285 pluginField
.setDisabled(value
!== 'dns');
286 pluginField
.setHidden(value
!== 'dns');
295 xtype
: 'pveACMEPluginSelector',
302 xtype
: 'proxmoxtextfield',
307 fieldLabel
: gettext('Domain'),
313 initComponent: function() {
317 throw 'no nodename given';
320 if (!me
.nodeconfig
) {
321 throw 'no nodeconfig given';
324 me
.isCreate
= !me
.domain
;
326 me
.domain
= `${me.nodename}.`; // TODO: FQDN of node
329 me
.url
= `/api2/extjs/nodes/${me.nodename}/config`;
334 me
.setValues(me
.domain
);
336 me
.setValues({ domain
: me
.domain
});
341 Ext
.define('pve-acme-domains', {
342 extend
: 'Ext.data.Model',
343 fields
: ['domain', 'type', 'alias', 'plugin', 'configkey'],
344 idProperty
: 'domain',
347 Ext
.define('PVE.node.ACME', {
348 extend
: 'Ext.grid.Panel',
349 alias
: 'widget.pveACMEView',
354 emptyText
: gettext('No Domains configured'),
359 account
: undefined, // the account we display
360 configaccount
: undefined, // the account set in the config
361 accountEditable
: false,
362 accountsAvailable
: false,
366 canOrder
: (get) => !!get('account') && get('domaincount') > 0,
367 editBtnIcon
: (get) => 'fa black fa-' + (get('accountEditable') ? 'check' : 'pencil'),
368 accountTextHidden
: (get) => get('accountEditable') || !get('accountsAvailable'),
369 accountValueHidden
: (get) => !get('accountEditable') || !get('accountsAvailable'),
374 xclass
: 'Ext.app.ViewController',
376 init: function(view
) {
377 let accountSelector
= this.lookup('accountselector');
378 accountSelector
.store
.on('load', this.onAccountsLoad
, this);
381 onAccountsLoad: function(store
, records
, success
) {
383 let vm
= me
.getViewModel();
384 let configaccount
= vm
.get('configaccount');
385 vm
.set('accountsAvailable', records
.length
> 0);
386 if (me
.autoChangeAccount
&& records
.length
> 0) {
387 me
.changeAccount(records
[0].data
.name
, () => {
388 vm
.set('accountEditable', false);
391 me
.autoChangeAccount
= false;
392 } else if (configaccount
) {
393 if (store
.findExact('name', configaccount
) !== -1) {
394 vm
.set('account', configaccount
);
396 vm
.set('account', null);
401 addDomain: function() {
403 let view
= me
.getView();
405 Ext
.create('PVE.node.ACMEDomainEdit', {
406 nodename
: view
.nodename
,
407 nodeconfig
: view
.nodeconfig
,
408 apiCallDone: function() {
414 editDomain: function() {
416 let view
= me
.getView();
418 let selection
= view
.getSelection();
419 if (selection
.length
< 1) return;
421 Ext
.create('PVE.node.ACMEDomainEdit', {
422 nodename
: view
.nodename
,
423 nodeconfig
: view
.nodeconfig
,
424 domain
: selection
[0].data
,
425 apiCallDone: function() {
431 removeDomain: function() {
433 let view
= me
.getView();
434 let selection
= view
.getSelection();
435 if (selection
.length
< 1) return;
437 let rec
= selection
[0].data
;
439 if (rec
.configkey
!== 'acme') {
440 params
.delete = rec
.configkey
;
442 let acme
= PVE
.Parser
.parseACME(view
.nodeconfig
.acme
);
443 PVE
.Utils
.remove_domain_from_acme(acme
, rec
.domain
);
444 params
.acme
= PVE
.Parser
.printACME(acme
);
447 Proxmox
.Utils
.API2Request({
449 url
: `/nodes/${view.nodename}/config`,
451 success: function(response
, opt
) {
454 failure: function(response
, opt
) {
455 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
460 toggleEditAccount: function() {
462 let vm
= me
.getViewModel();
463 let editable
= vm
.get('accountEditable');
465 me
.changeAccount(vm
.get('account'), function() {
466 vm
.set('accountEditable', false);
470 vm
.set('accountEditable', true);
474 changeAccount: function(account
, callback
) {
476 let view
= me
.getView();
479 let acme
= PVE
.Parser
.parseACME(view
.nodeconfig
.acme
);
480 acme
.account
= account
;
481 params
.acme
= PVE
.Parser
.printACME(acme
);
483 Proxmox
.Utils
.API2Request({
486 url
: `/nodes/${view.nodename}/config`,
488 success: function(response
, opt
) {
489 if (Ext
.isFunction(callback
)) {
493 failure: function(response
, opt
) {
494 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
501 let view
= me
.getView();
503 Proxmox
.Utils
.API2Request({
508 url
: `/nodes/${view.nodename}/certificates/acme/certificate`,
509 success: function(response
, opt
) {
510 Ext
.create('Proxmox.window.TaskViewer', {
511 upid
: response
.result
.data
,
512 taskDone: function(success
) {
513 me
.orderFinished(success
);
517 failure: function(response
, opt
) {
518 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
523 orderFinished: function(success
) {
524 if (!success
) return;
525 var txt
= gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
526 Ext
.getBody().mask(txt
, ['pve-static-mask']);
527 // reload after 10 seconds automatically
528 Ext
.defer(function() {
529 window
.location
.reload(true);
535 let view
= me
.getView();
539 addAccount: function() {
541 Ext
.create('PVE.node.ACMEAccountCreate', {
543 taskDone: function() {
545 let accountSelector
= me
.lookup('accountselector');
546 me
.autoChangeAccount
= true;
547 accountSelector
.store
.load();
555 xtype
: 'proxmoxButton',
556 text
: gettext('Add'),
557 handler
: 'addDomain',
561 xtype
: 'proxmoxButton',
562 text
: gettext('Edit'),
564 handler
: 'editDomain',
567 xtype
: 'proxmoxStdRemoveButton',
568 handler
: 'removeDomain',
574 text
: gettext('Order Certificates Now'),
576 disabled
: '{!canOrder}',
582 xtype
: 'displayfield',
583 value
: gettext('Using Account') + ':',
585 hidden
: '{!accountsAvailable}',
589 xtype
: 'displayfield',
590 reference
: 'accounttext',
591 renderer
: (val
) => val
|| Proxmox
.Utils
.NoneText
,
594 hidden
: '{accountTextHidden}',
598 xtype
: 'pveACMEAccountSelector',
600 reference
: 'accountselector',
603 hidden
: '{accountValueHidden}',
608 iconCls
: 'fa black fa-pencil',
612 iconCls
: '{editBtnIcon}',
613 hidden
: '{!accountsAvailable}',
615 handler
: 'toggleEditAccount',
618 xtype
: 'displayfield',
619 value
: gettext('No Account available.'),
621 hidden
: '{accountsAvailable}',
627 reference
: 'accountlink',
628 text
: gettext('Add ACME Account'),
630 hidden
: '{accountsAvailable}',
632 handler
: 'addAccount',
636 updateStore: function(store
, records
, success
) {
640 if (success
&& records
.length
> 0) {
648 me
.nodeconfig
= rec
.data
; // save nodeconfig for updates
650 let account
= 'default';
653 let obj
= PVE
.Parser
.parseACME(rec
.data
.acme
);
654 (obj
.domains
|| []).forEach(domain
=> {
655 if (domain
=== '') return;
665 account
= obj
.account
;
669 let vm
= me
.getViewModel();
670 let oldaccount
= vm
.get('account');
672 // account changed, and we do not edit currently, load again to verify
673 if (oldaccount
!== account
&& !vm
.get('accountEditable')) {
674 vm
.set('configaccount', account
);
675 me
.lookup('accountselector').store
.load();
678 for (let i
= 0; i
< PVE
.Utils
.acmedomain_count
; i
++) {
679 let acmedomain
= rec
.data
[`acmedomain${i}`];
680 if (!acmedomain
) continue;
682 let record
= PVE
.Parser
.parsePropertyString(acmedomain
, 'domain');
684 record
.configkey
= `acmedomain${i}`;
688 vm
.set('domaincount', data
.length
);
689 me
.store
.loadData(data
, false);
693 itemdblclick
: 'editDomain',
700 text
: gettext('Domain'),
705 text
: gettext('Type'),
710 text
: gettext('Plugin'),
714 initComponent: function() {
718 throw "no nodename given";
721 me
.rstore
= Ext
.create('Proxmox.data.UpdateStore', {
724 storeid
: `pve-node-domains-${me.nodename}`,
727 url
: `/api2/json/nodes/${me.nodename}/config`,
731 me
.store
= Ext
.create('Ext.data.Store', {
732 model
: 'pve-acme-domains',
737 me
.mon(me
.rstore
, 'load', 'updateStore', me
);
738 Proxmox
.Utils
.monStoreErrors(me
, me
.rstore
);
739 me
.on('destroy', me
.rstore
.stopUpdate
, me
.rstore
);