]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/node/ACME.js
1 Ext
.define('PVE.node.ACMEAccountCreate', {
2 extend
: 'Proxmox.window.Edit',
5 title
: gettext('Register Account'),
8 submitText
: gettext('Register'),
9 url
: '/cluster/acme/account',
14 xtype
: 'proxmoxtextfield',
15 fieldLabel
: gettext('Name'),
21 xtype
: 'proxmoxComboGrid',
26 fieldLabel
: gettext('ACME Directory'),
29 fields
: ['name', 'url'],
33 url
: '/api2/json/cluster/acme/directories'
43 header
: gettext('Name'),
48 header
: gettext('URL'),
55 change: function(combogrid
, value
) {
61 var disp
= me
.up('window').down('#tos_url_display');
62 var field
= me
.up('window').down('#tos_url');
63 var checkbox
= me
.up('window').down('#tos_checkbox');
65 disp
.setValue(gettext('Loading'));
66 field
.setValue(undefined);
67 checkbox
.setValue(undefined);
69 Proxmox
.Utils
.API2Request({
70 url
: '/cluster/acme/tos',
75 success: function(response
, opt
) {
76 me
.up('window').down('#tos_url').setValue(response
.result
.data
);
77 me
.up('window').down('#tos_url_display').setValue(response
.result
.data
);
79 failure: function(response
, opt
) {
80 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
87 xtype
: 'displayfield',
88 itemId
: 'tos_url_display',
89 fieldLabel
: gettext('Terms of Service'),
90 renderer
: PVE
.Utils
.render_optional_url
,
91 name
: 'tos_url_display'
99 xtype
: 'proxmoxcheckbox',
100 itemId
: 'tos_checkbox',
101 fieldLabel
: gettext('Accept TOS'),
103 validateValue: function(value
) {
104 if (value
&& this.checked
) {
115 fieldLabel
: gettext('E-Mail')
121 Ext
.define('PVE.node.ACMEAccountView', {
122 extend
: 'Proxmox.window.Edit',
129 title
: gettext('Account'),
133 xtype
: 'displayfield',
134 fieldLabel
: gettext('E-Mail'),
138 xtype
: 'displayfield',
139 fieldLabel
: gettext('Created'),
143 xtype
: 'displayfield',
144 fieldLabel
: gettext('Status'),
148 xtype
: 'displayfield',
149 fieldLabel
: gettext('Directory'),
150 renderer
: PVE
.Utils
.render_optional_url
,
154 xtype
: 'displayfield',
155 fieldLabel
: gettext('Terms of Services'),
156 renderer
: PVE
.Utils
.render_optional_url
,
161 initComponent: function() {
164 if (!me
.accountname
) {
165 throw "no account name defined";
168 me
.url
= '/cluster/acme/account/' + me
.accountname
;
172 // hide OK/Reset button, because we just want to show data
173 me
.down('toolbar[dock=bottom]').setVisible(false);
176 success: function(response
) {
177 var data
= response
.result
.data
;
178 data
.email
= data
.account
.contact
[0];
179 data
.createdAt
= data
.account
.createdAt
;
180 data
.status
= data
.account
.status
;
187 Ext
.define('PVE.node.ACMEDomainEdit', {
188 extend
: 'Proxmox.window.Edit',
189 alias
: 'widget.pveACMEDomainEdit',
191 subject
: gettext('Domain'),
198 onGetValues: function(values
) {
200 let win
= me
.up('pveACMEDomainEdit');
201 let nodeconfig
= win
.nodeconfig
;
202 let olddomain
= win
.domain
|| {};
205 digest
: nodeconfig
.digest
,
208 let configkey
= olddomain
.configkey
;
209 let acmeObj
= PVE
.Parser
.parseACME(nodeconfig
.acme
);
211 if (values
.type
=== 'dns') {
212 if (!olddomain
.configkey
|| olddomain
.configkey
=== 'acme') {
213 // look for first free slot
214 for (let i
= 0; i
< PVE
.Utils
.acmedomain_count
; i
++) {
215 if (nodeconfig
[`acmedomain${i}`] === undefined) {
216 configkey
= `acmedomain${i}`;
220 if (olddomain
.domain
) {
221 // we have to remove the domain from the acme domainlist
222 PVE
.Utils
.remove_domain_from_acme(acmeObj
, olddomain
.domain
);
223 params
.acme
= PVE
.Parser
.printACME(acmeObj
);
228 params
[configkey
] = PVE
.Parser
.printPropertyString(values
, 'domain');
230 if (olddomain
.configkey
&& olddomain
.configkey
!== 'acme') {
231 // delete the old dns entry
232 params
.delete = [olddomain
.configkey
];
235 // add new, remove old and make entries unique
236 PVE
.Utils
.add_domain_to_acme(acmeObj
, values
.domain
);
237 PVE
.Utils
.remove_domain_from_acme(acmeObj
, olddomain
.domain
);
238 params
.acme
= PVE
.Parser
.printACME(acmeObj
);
245 xtype
: 'proxmoxKVComboBox',
247 fieldLabel
: gettext('Challenge Type'),
251 ['standalone', 'HTTP'],
254 validator: function(value
) {
256 let win
= me
.up('pveACMEDomainEdit');
257 let oldconfigkey
= win
.domain
? win
.domain
.configkey
: undefined;
258 let val
= me
.getValue();
259 if (val
=== 'dns' && (!oldconfigkey
|| oldconfigkey
=== 'acme')) {
260 // we have to check if there is a 'acmedomain' slot left
262 for (let i
= 0; i
< PVE
.Utils
.acmedomain_count
; i
++) {
263 if (!win
.nodeconfig
[`acmedomain${i}`]) {
268 return gettext('Only 5 Domains with type DNS can be configured');
275 change: function(cb
, value
) {
277 let view
= me
.up('pveACMEDomainEdit');
278 let pluginField
= view
.down('field[name=plugin]');
279 pluginField
.setDisabled(value
!== 'dns');
280 pluginField
.setHidden(value
!== 'dns');
289 xtype
: 'pveACMEPluginSelector',
296 xtype
: 'proxmoxtextfield',
301 fieldLabel
: gettext('Domain'),
307 initComponent: function() {
311 throw 'no nodename given';
314 if (!me
.nodeconfig
) {
315 throw 'no nodeconfig given';
318 me
.isCreate
= !me
.domain
;
320 me
.url
= `/api2/extjs/nodes/${me.nodename}/config`;
325 me
.setValues(me
.domain
);
330 Ext
.define('pve-acme-domains', {
331 extend
: 'Ext.data.Model',
332 fields
: ['domain', 'type', 'alias', 'plugin', 'configkey'],
333 idProperty
: 'domain',
336 Ext
.define('PVE.node.ACME', {
337 extend
: 'Ext.grid.Panel',
338 alias
: 'widget.pveACMEView',
346 accountEditable
: false,
347 accountsAvailable
: false,
351 editBtnIcon
: (get) => {
352 return 'fa black fa-' + (get('accountEditable') ? 'check' : 'pencil');
354 accountTextHidden
: (get) => get('accountEditable') || !get('accountsAvailable'),
355 accountValueHidden
: (get) => !get('accountEditable') || !get('accountsAvailable'),
360 xclass
: 'Ext.app.ViewController',
362 init: function(view
) {
363 let vm
= this.getViewModel();
364 let accountSelector
= this.lookup('accountselector');
365 accountSelector
.store
.on('load', this.onAccountsLoad
, this);
368 onAccountsLoad: function(store
, records
, success
) {
369 let vm
= this.getViewModel();
370 vm
.set('accountsAvailable', records
.length
> 0);
373 addDomain: function() {
375 let view
= me
.getView();
377 Ext
.create('PVE.node.ACMEDomainEdit', {
378 nodename
: view
.nodename
,
379 nodeconfig
: view
.nodeconfig
,
380 apiCallDone: function() {
386 editDomain: function() {
388 let view
= me
.getView();
390 let selection
= view
.getSelection();
391 if (selection
.length
< 1) return;
393 Ext
.create('PVE.node.ACMEDomainEdit', {
394 nodename
: view
.nodename
,
395 nodeconfig
: view
.nodeconfig
,
396 domain
: selection
[0].data
,
397 apiCallDone: function() {
403 removeDomain: function() {
405 let view
= me
.getView();
406 let selection
= view
.getSelection();
407 if (selection
.length
< 1) return;
409 let rec
= selection
[0].data
;
411 if (rec
.configkey
!== 'acme') {
412 params
.delete = rec
.configkey
;
414 let acme
= PVE
.Parser
.parseACME(view
.nodeconfig
.acme
);
415 PVE
.Utils
.remove_domain_from_acme(acme
, rec
.domain
);
416 params
.acme
= PVE
.Parser
.printACME(acme
);
419 Proxmox
.Utils
.API2Request({
421 url
: `/nodes/${view.nodename}/config`,
423 success: function(response
, opt
) {
426 failure: function(response
, opt
) {
427 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
432 toggleEditAccount: function() {
434 let vm
= me
.getViewModel();
435 let editable
= vm
.get('accountEditable');
437 me
.changeAccount(vm
.get('account'), function() {
438 vm
.set('accountEditable', false);
442 vm
.set('accountEditable', true);
446 changeAccount: function(account
, callback
) {
448 let view
= me
.getView();
451 let acme
= PVE
.Parser
.parseACME(view
.nodeconfig
.acme
);
452 acme
.account
= account
;
453 params
.acme
= PVE
.Parser
.printACME(acme
);
455 Proxmox
.Utils
.API2Request({
458 url
: `/nodes/${view.nodename}/config`,
460 success: function(response
, opt
) {
461 if (Ext
.isFunction(callback
)) {
465 failure: function(response
, opt
) {
466 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
473 let view
= me
.getView();
475 Proxmox
.Utils
.API2Request({
480 url
: `/nodes/${view.nodename}/certificates/acme/certificate`,
481 success: function(response
, opt
) {
482 Ext
.create('Proxmox.window.TaskViewer', {
483 upid
: response
.result
.data
,
484 taskDone: function(success
) {
485 me
.orderFinished(success
);
489 failure: function(response
, opt
) {
490 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
495 orderFinished: function(success
) {
496 if (!success
) return;
497 var txt
= gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
498 Ext
.getBody().mask(txt
, ['pve-static-mask']);
499 // reload after 10 seconds automatically
500 Ext
.defer(function() {
501 window
.location
.reload(true);
507 let view
= me
.getView();
511 gotoAccounts: function() {
512 let sp
= Ext
.state
.Manager
.getProvider();
513 sp
.set('dctab', { value
: 'acme' }, true);
514 Ext
.ComponentQuery
.query('pveResourceTree')[0].selectById('root');
520 xtype
: 'proxmoxButton',
521 text
: gettext('Add'),
522 handler
: 'addDomain',
526 xtype
: 'proxmoxButton',
527 text
: gettext('Edit'),
529 handler
: 'editDomain',
532 xtype
: 'proxmoxStdRemoveButton',
533 handler
: 'removeDomain',
539 text
: gettext('Order Certificates Now'),
544 xtype
: 'displayfield',
545 value
: gettext('Using Account') + ':',
547 hidden
: '{!accountsAvailable}',
551 xtype
: 'displayfield',
552 reference
: 'accounttext',
555 hidden
: '{accountTextHidden}',
559 xtype
: 'pveACMEAccountSelector',
561 reference
: 'accountselector',
564 hidden
: '{accountValueHidden}',
569 iconCls
: 'fa black fa-pencil',
573 iconCls
: '{editBtnIcon}',
574 hidden
: '{!accountsAvailable}',
576 handler
: 'toggleEditAccount',
579 xtype
: 'displayfield',
580 value
: gettext('No Account available.'),
582 hidden
: '{accountsAvailable}',
588 reference
: 'accountlink',
589 text
: gettext('Go to ACME Accounts'),
591 hidden
: '{accountsAvailable}',
593 handler
: 'gotoAccounts',
597 updateStore: function(store
, records
, success
) {
601 if (success
&& records
.length
> 0) {
609 me
.nodeconfig
= rec
.data
; // save nodeconfig for updates
611 let account
= 'default';
614 let obj
= PVE
.Parser
.parseACME(rec
.data
.acme
);
615 (obj
.domains
|| []).forEach(domain
=> {
616 if (domain
=== '') return;
626 account
= obj
.account
;
630 let accounttext
= me
.lookup('accounttext');
631 let vm
= me
.getViewModel();
632 let oldaccount
= vm
.get('account');
634 // account changed, and we do not edit currently, load again to verify
635 if (oldaccount
!== account
&& !vm
.get('accountEditable')) {
636 Proxmox
.Utils
.API2Request({
637 url
: `/cluster/acme/account/${account}`,
639 success: function(response
, opt
) {
640 vm
.set('account', account
);
642 failure: function(response
, opt
) {
643 vm
.set('account', Proxmox
.Utils
.NoneText
);
648 for (let i
= 0; i
< PVE
.Utils
.acmedomain_count
; i
++) {
649 let acmedomain
= rec
.data
[`acmedomain${i}`];
650 if (!acmedomain
) continue;
652 let record
= PVE
.Parser
.parsePropertyString(acmedomain
, 'domain');
654 record
.configkey
= `acmedomain${i}`;
658 me
.store
.loadData(data
, false);
662 itemdblclick
: 'editDomain',
669 text
: gettext('Domain'),
674 text
: gettext('Type'),
679 text
: gettext('Plugin'),
683 initComponent: function() {
687 throw "no nodename given";
690 me
.rstore
= Ext
.create('Proxmox.data.UpdateStore', {
693 storeid
: `pve-node-domains-${me.nodename}`,
696 url
: `/api2/json/nodes/${me.nodename}/config`,
700 me
.store
= Ext
.create('Ext.data.Store', {
701 model
: 'pve-acme-domains',
706 me
.mon(me
.rstore
, 'load', 'updateStore', me
);
707 Proxmox
.Utils
.monStoreErrors(me
, me
.rstore
);