]>
Commit | Line | Data |
---|---|---|
488be4c2 DC |
1 | Ext.define('PVE.node.ACMEAccountCreate', { |
2 | extend: 'Proxmox.window.Edit', | |
fc40915c | 3 | mixins: ['Proxmox.Mixin.CBind'], |
488be4c2 | 4 | |
04a8058e | 5 | width: 450, |
488be4c2 DC |
6 | title: gettext('Register Account'), |
7 | isCreate: true, | |
8 | method: 'POST', | |
9 | submitText: gettext('Register'), | |
10 | url: '/cluster/acme/account', | |
11 | showTaskViewer: true, | |
fc40915c | 12 | defaultExists: false, |
fdc4c229 FG |
13 | referenceHolder: true, |
14 | onlineHelp: "sysadmin_certs_acme_account", | |
15 | ||
16 | viewModel: { | |
17 | data: { | |
18 | customDirectory: false, | |
c18a2db2 FG |
19 | eabRequired: false, |
20 | }, | |
21 | formulas: { | |
22 | eabEmptyText: function(get) { | |
23 | return get('eabRequired') ? gettext("required") : gettext("optional"); | |
24 | }, | |
fdc4c229 FG |
25 | }, |
26 | }, | |
488be4c2 DC |
27 | |
28 | items: [ | |
c0afd5cc DC |
29 | { |
30 | xtype: 'proxmoxtextfield', | |
e023535e | 31 | fieldLabel: gettext('Account Name'), |
c0afd5cc | 32 | name: 'name', |
fc40915c DC |
33 | cbind: { |
34 | emptyText: (get) => get('defaultExists') ? '' : 'default', | |
35 | allowBlank: (get) => !get('defaultExists'), | |
36 | }, | |
c0afd5cc | 37 | }, |
04a8058e DC |
38 | { |
39 | xtype: 'textfield', | |
40 | name: 'contact', | |
41 | vtype: 'email', | |
42 | allowBlank: false, | |
f6710aac | 43 | fieldLabel: gettext('E-Mail'), |
04a8058e | 44 | }, |
488be4c2 DC |
45 | { |
46 | xtype: 'proxmoxComboGrid', | |
fdc4c229 FG |
47 | notFoundIsValid: true, |
48 | isFormField: false, | |
488be4c2 DC |
49 | allowBlank: false, |
50 | valueField: 'url', | |
51 | displayField: 'name', | |
52 | fieldLabel: gettext('ACME Directory'), | |
53 | store: { | |
fdc4c229 FG |
54 | listeners: { |
55 | 'load': function() { | |
56 | this.add({ name: gettext("Custom"), url: '' }); | |
57 | }, | |
58 | }, | |
488be4c2 DC |
59 | autoLoad: true, |
60 | fields: ['name', 'url'], | |
61 | idProperty: ['name'], | |
62 | proxy: { | |
63 | type: 'proxmox', | |
f6710aac | 64 | url: '/api2/json/cluster/acme/directories', |
488be4c2 | 65 | }, |
488be4c2 DC |
66 | }, |
67 | listConfig: { | |
68 | columns: [ | |
69 | { | |
70 | header: gettext('Name'), | |
71 | dataIndex: 'name', | |
f6710aac | 72 | flex: 1, |
488be4c2 DC |
73 | }, |
74 | { | |
75 | header: gettext('URL'), | |
76 | dataIndex: 'url', | |
f6710aac TL |
77 | flex: 1, |
78 | }, | |
79 | ], | |
488be4c2 DC |
80 | }, |
81 | listeners: { | |
82 | change: function(combogrid, value) { | |
fdc4c229 | 83 | let me = this; |
488be4c2 | 84 | |
fdc4c229 FG |
85 | let vm = me.up('window').getViewModel(); |
86 | let dirField = me.up('window').lookupReference('directoryInput'); | |
87 | let tosButton = me.up('window').lookupReference('queryTos'); | |
488be4c2 | 88 | |
fdc4c229 FG |
89 | let isCustom = combogrid.getSelection().get('name') === gettext("Custom"); |
90 | vm.set('customDirectory', isCustom); | |
488be4c2 | 91 | |
fdc4c229 FG |
92 | dirField.setValue(value); |
93 | ||
94 | if (!isCustom) { | |
95 | tosButton.click(); | |
96 | } else { | |
97 | me.up('window').clearToSFields(); | |
98 | } | |
99 | }, | |
100 | }, | |
101 | }, | |
102 | { | |
103 | xtype: 'fieldcontainer', | |
104 | layout: 'hbox', | |
105 | fieldLabel: gettext('URL'), | |
106 | bind: { | |
107 | hidden: '{!customDirectory}', | |
108 | }, | |
109 | items: [ | |
110 | { | |
111 | xtype: 'proxmoxtextfield', | |
112 | name: 'directory', | |
113 | reference: 'directoryInput', | |
114 | flex: 1, | |
115 | allowBlank: false, | |
116 | listeners: { | |
117 | change: function(textbox, value) { | |
118 | let me = this; | |
119 | me.up('window').clearToSFields(); | |
488be4c2 | 120 | }, |
fdc4c229 FG |
121 | }, |
122 | }, | |
123 | { | |
124 | xtype: 'proxmoxButton', | |
125 | margin: '0 0 0 5', | |
126 | reference: 'queryTos', | |
127 | text: gettext('Query URL'), | |
128 | listeners: { | |
129 | click: function(button) { | |
130 | let me = this; | |
131 | ||
132 | let w = me.up('window'); | |
c18a2db2 | 133 | let vm = w.getViewModel(); |
fdc4c229 FG |
134 | let disp = w.down('#tos_url_display'); |
135 | let field = w.down('#tos_url'); | |
136 | let checkbox = w.down('#tos_checkbox'); | |
137 | let value = w.lookupReference('directoryInput').getValue(); | |
138 | w.clearToSFields(); | |
139 | ||
140 | if (!value) { | |
141 | return; | |
7fb70c3b | 142 | } else { |
fdc4c229 | 143 | disp.setValue(gettext("Loading")); |
7fb70c3b | 144 | } |
fdc4c229 FG |
145 | |
146 | Proxmox.Utils.API2Request({ | |
147 | url: '/cluster/acme/meta', | |
148 | method: 'GET', | |
149 | params: { | |
150 | directory: value, | |
151 | }, | |
152 | success: function(response, opt) { | |
b3779821 | 153 | if (response.result.data && response.result.data.termsOfService) { |
fdc4c229 FG |
154 | field.setValue(response.result.data.termsOfService); |
155 | disp.setValue(response.result.data.termsOfService); | |
156 | checkbox.setHidden(false); | |
157 | } else { | |
b3779821 FG |
158 | // Needed to pass input verification and enable register button |
159 | // has no influence on the submitted form | |
160 | checkbox.setValue(true); | |
fdc4c229 FG |
161 | disp.setValue("No terms of service agreement required"); |
162 | } | |
b3779821 FG |
163 | vm.set('eabRequired', !!(response.result.data && |
164 | response.result.data.externalAccountRequired)); | |
fdc4c229 FG |
165 | }, |
166 | failure: function(response, opt) { | |
167 | disp.setValue(undefined); | |
168 | Ext.Msg.alert(gettext('Error'), response.htmlStatus); | |
169 | }, | |
170 | }); | |
488be4c2 | 171 | }, |
fdc4c229 | 172 | }, |
f6710aac | 173 | }, |
fdc4c229 | 174 | ], |
488be4c2 DC |
175 | }, |
176 | { | |
177 | xtype: 'displayfield', | |
178 | itemId: 'tos_url_display', | |
488be4c2 | 179 | renderer: PVE.Utils.render_optional_url, |
f6710aac | 180 | name: 'tos_url_display', |
488be4c2 DC |
181 | }, |
182 | { | |
183 | xtype: 'hidden', | |
184 | itemId: 'tos_url', | |
f6710aac | 185 | name: 'tos_url', |
488be4c2 DC |
186 | }, |
187 | { | |
188 | xtype: 'proxmoxcheckbox', | |
189 | itemId: 'tos_checkbox', | |
04a8058e | 190 | boxLabel: gettext('Accept TOS'), |
488be4c2 DC |
191 | submitValue: false, |
192 | validateValue: function(value) { | |
193 | if (value && this.checked) { | |
194 | return true; | |
195 | } | |
196 | return false; | |
f6710aac | 197 | }, |
488be4c2 | 198 | }, |
c18a2db2 FG |
199 | { |
200 | xtype: 'proxmoxtextfield', | |
201 | name: 'eab-kid', | |
202 | fieldLabel: gettext('EAB Key ID'), | |
203 | bind: { | |
204 | hidden: '{!customDirectory}', | |
205 | allowBlank: '{!eabRequired}', | |
206 | emptyText: '{eabEmptyText}', | |
207 | }, | |
208 | }, | |
209 | { | |
210 | xtype: 'proxmoxtextfield', | |
211 | name: 'eab-hmac-key', | |
212 | fieldLabel: gettext('EAB Key'), | |
213 | bind: { | |
214 | hidden: '{!customDirectory}', | |
215 | allowBlank: '{!eabRequired}', | |
216 | emptyText: '{eabEmptyText}', | |
217 | }, | |
218 | }, | |
f6710aac | 219 | ], |
488be4c2 | 220 | |
fdc4c229 FG |
221 | clearToSFields: function() { |
222 | let me = this; | |
223 | ||
224 | let disp = me.down('#tos_url_display'); | |
225 | let field = me.down('#tos_url'); | |
226 | let checkbox = me.down('#tos_checkbox'); | |
227 | ||
228 | disp.setValue("Terms of service not fetched yet"); | |
229 | field.setValue(undefined); | |
230 | checkbox.setValue(undefined); | |
231 | checkbox.setHidden(true); | |
232 | }, | |
233 | ||
488be4c2 DC |
234 | }); |
235 | ||
236 | Ext.define('PVE.node.ACMEAccountView', { | |
237 | extend: 'Proxmox.window.Edit', | |
238 | ||
239 | width: 600, | |
240 | fieldDefaults: { | |
f6710aac | 241 | labelWidth: 140, |
488be4c2 DC |
242 | }, |
243 | ||
244 | title: gettext('Account'), | |
245 | ||
246 | items: [ | |
247 | { | |
248 | xtype: 'displayfield', | |
249 | fieldLabel: gettext('E-Mail'), | |
f6710aac | 250 | name: 'email', |
488be4c2 DC |
251 | }, |
252 | { | |
253 | xtype: 'displayfield', | |
254 | fieldLabel: gettext('Created'), | |
f6710aac | 255 | name: 'createdAt', |
488be4c2 DC |
256 | }, |
257 | { | |
258 | xtype: 'displayfield', | |
259 | fieldLabel: gettext('Status'), | |
f6710aac | 260 | name: 'status', |
488be4c2 DC |
261 | }, |
262 | { | |
263 | xtype: 'displayfield', | |
264 | fieldLabel: gettext('Directory'), | |
265 | renderer: PVE.Utils.render_optional_url, | |
f6710aac | 266 | name: 'directory', |
488be4c2 DC |
267 | }, |
268 | { | |
269 | xtype: 'displayfield', | |
270 | fieldLabel: gettext('Terms of Services'), | |
271 | renderer: PVE.Utils.render_optional_url, | |
f6710aac TL |
272 | name: 'tos', |
273 | }, | |
488be4c2 DC |
274 | ], |
275 | ||
276 | initComponent: function() { | |
277 | var me = this; | |
278 | ||
279 | if (!me.accountname) { | |
280 | throw "no account name defined"; | |
281 | } | |
282 | ||
283 | me.url = '/cluster/acme/account/' + me.accountname; | |
284 | ||
285 | me.callParent(); | |
286 | ||
287 | // hide OK/Reset button, because we just want to show data | |
288 | me.down('toolbar[dock=bottom]').setVisible(false); | |
289 | ||
290 | me.load({ | |
291 | success: function(response) { | |
292 | var data = response.result.data; | |
293 | data.email = data.account.contact[0]; | |
294 | data.createdAt = data.account.createdAt; | |
295 | data.status = data.account.status; | |
296 | me.setValues(data); | |
f6710aac | 297 | }, |
488be4c2 | 298 | }); |
f6710aac | 299 | }, |
488be4c2 DC |
300 | }); |
301 | ||
8e49a93f DC |
302 | Ext.define('PVE.node.ACMEDomainEdit', { |
303 | extend: 'Proxmox.window.Edit', | |
304 | alias: 'widget.pveACMEDomainEdit', | |
305 | ||
306 | subject: gettext('Domain'), | |
307 | isCreate: false, | |
3c6b4c80 | 308 | width: 450, |
eff602d8 | 309 | onlineHelp: 'sysadmin_certificate_management', |
8e49a93f DC |
310 | |
311 | items: [ | |
312 | { | |
313 | xtype: 'inputpanel', | |
314 | onGetValues: function(values) { | |
315 | let me = this; | |
316 | let win = me.up('pveACMEDomainEdit'); | |
317 | let nodeconfig = win.nodeconfig; | |
318 | let olddomain = win.domain || {}; | |
319 | ||
320 | let params = { | |
321 | digest: nodeconfig.digest, | |
322 | }; | |
323 | ||
324 | let configkey = olddomain.configkey; | |
6ac64c3a | 325 | let acmeObj = PVE.Parser.parseACME(nodeconfig.acme); |
8e49a93f DC |
326 | |
327 | if (values.type === 'dns') { | |
328 | if (!olddomain.configkey || olddomain.configkey === 'acme') { | |
329 | // look for first free slot | |
330 | for (let i = 0; i < PVE.Utils.acmedomain_count; i++) { | |
331 | if (nodeconfig[`acmedomain${i}`] === undefined) { | |
332 | configkey = `acmedomain${i}`; | |
333 | break; | |
334 | } | |
335 | } | |
336 | if (olddomain.domain) { | |
337 | // we have to remove the domain from the acme domainlist | |
338 | PVE.Utils.remove_domain_from_acme(acmeObj, olddomain.domain); | |
339 | params.acme = PVE.Parser.printACME(acmeObj); | |
340 | } | |
341 | } | |
342 | ||
343 | delete values.type; | |
344 | params[configkey] = PVE.Parser.printPropertyString(values, 'domain'); | |
345 | } else { | |
346 | if (olddomain.configkey && olddomain.configkey !== 'acme') { | |
347 | // delete the old dns entry | |
348 | params.delete = [olddomain.configkey]; | |
349 | } | |
350 | ||
351 | // add new, remove old and make entries unique | |
352 | PVE.Utils.add_domain_to_acme(acmeObj, values.domain); | |
353 | PVE.Utils.remove_domain_from_acme(acmeObj, olddomain.domain); | |
354 | params.acme = PVE.Parser.printACME(acmeObj); | |
355 | } | |
356 | ||
357 | return params; | |
358 | }, | |
359 | items: [ | |
360 | { | |
361 | xtype: 'proxmoxKVComboBox', | |
362 | name: 'type', | |
3c6b4c80 | 363 | fieldLabel: gettext('Challenge Type'), |
8e49a93f | 364 | allowBlank: false, |
3c6b4c80 | 365 | value: 'standalone', |
8e49a93f | 366 | comboItems: [ |
9c164224 | 367 | ['standalone', 'HTTP'], |
8e49a93f DC |
368 | ['dns', 'DNS'], |
369 | ], | |
370 | validator: function(value) { | |
371 | let me = this; | |
372 | let win = me.up('pveACMEDomainEdit'); | |
373 | let oldconfigkey = win.domain ? win.domain.configkey : undefined; | |
374 | let val = me.getValue(); | |
375 | if (val === 'dns' && (!oldconfigkey || oldconfigkey === 'acme')) { | |
376 | // we have to check if there is a 'acmedomain' slot left | |
377 | let found = false; | |
378 | for (let i = 0; i < PVE.Utils.acmedomain_count; i++) { | |
379 | if (!win.nodeconfig[`acmedomain${i}`]) { | |
380 | found = true; | |
381 | } | |
382 | } | |
383 | if (!found) { | |
384 | return gettext('Only 5 Domains with type DNS can be configured'); | |
385 | } | |
386 | } | |
387 | ||
388 | return true; | |
389 | }, | |
390 | listeners: { | |
391 | change: function(cb, value) { | |
392 | let me = this; | |
393 | let view = me.up('pveACMEDomainEdit'); | |
a94b71fb TL |
394 | let pluginField = view.down('field[name=plugin]'); |
395 | pluginField.setDisabled(value !== 'dns'); | |
396 | pluginField.setHidden(value !== 'dns'); | |
8e49a93f DC |
397 | }, |
398 | }, | |
399 | }, | |
400 | { | |
401 | xtype: 'hidden', | |
402 | name: 'alias', | |
403 | }, | |
8e49a93f DC |
404 | { |
405 | xtype: 'pveACMEPluginSelector', | |
406 | name: 'plugin', | |
407 | disabled: true, | |
a94b71fb | 408 | hidden: true, |
8e49a93f DC |
409 | allowBlank: false, |
410 | }, | |
a94b71fb TL |
411 | { |
412 | xtype: 'proxmoxtextfield', | |
413 | name: 'domain', | |
414 | allowBlank: false, | |
415 | vtype: 'DnsName', | |
416 | value: '', | |
417 | fieldLabel: gettext('Domain'), | |
418 | }, | |
8e49a93f DC |
419 | ], |
420 | }, | |
421 | ], | |
422 | ||
423 | initComponent: function() { | |
424 | let me = this; | |
425 | ||
426 | if (!me.nodename) { | |
427 | throw 'no nodename given'; | |
428 | } | |
429 | ||
430 | if (!me.nodeconfig) { | |
431 | throw 'no nodeconfig given'; | |
432 | } | |
433 | ||
434 | me.isCreate = !me.domain; | |
8b779b4a TL |
435 | if (me.isCreate) { |
436 | me.domain = `${me.nodename}.`; // TODO: FQDN of node | |
437 | } | |
8e49a93f DC |
438 | |
439 | me.url = `/api2/extjs/nodes/${me.nodename}/config`; | |
440 | ||
441 | me.callParent(); | |
442 | ||
443 | if (!me.isCreate) { | |
444 | me.setValues(me.domain); | |
8b779b4a TL |
445 | } else { |
446 | me.setValues({ domain: me.domain }); | |
8e49a93f DC |
447 | } |
448 | }, | |
449 | }); | |
450 | ||
fd254233 DC |
451 | Ext.define('pve-acme-domains', { |
452 | extend: 'Ext.data.Model', | |
453 | fields: ['domain', 'type', 'alias', 'plugin', 'configkey'], | |
454 | idProperty: 'domain', | |
455 | }); | |
456 | ||
488be4c2 | 457 | Ext.define('PVE.node.ACME', { |
fd254233 DC |
458 | extend: 'Ext.grid.Panel', |
459 | alias: 'widget.pveACMEView', | |
488be4c2 DC |
460 | |
461 | margin: '10 0 0 0', | |
462 | title: 'ACME', | |
463 | ||
e666f688 DC |
464 | emptyText: gettext('No Domains configured'), |
465 | ||
fd254233 DC |
466 | viewModel: { |
467 | data: { | |
1580b605 | 468 | domaincount: 0, |
3071cc5b DC |
469 | account: undefined, // the account we display |
470 | configaccount: undefined, // the account set in the config | |
fd254233 | 471 | accountEditable: false, |
a8b6a80a | 472 | accountsAvailable: false, |
fd254233 DC |
473 | }, |
474 | ||
475 | formulas: { | |
1580b605 | 476 | canOrder: (get) => !!get('account') && get('domaincount') > 0, |
80bd3209 | 477 | editBtnIcon: (get) => 'fa black fa-' + (get('accountEditable') ? 'check' : 'pencil'), |
8fc2d938 | 478 | editBtnText: (get) => get('accountEditable') ? gettext('Apply') : gettext('Edit'), |
a8b6a80a TL |
479 | accountTextHidden: (get) => get('accountEditable') || !get('accountsAvailable'), |
480 | accountValueHidden: (get) => !get('accountEditable') || !get('accountsAvailable'), | |
fd254233 DC |
481 | }, |
482 | }, | |
483 | ||
484 | controller: { | |
485 | xclass: 'Ext.app.ViewController', | |
486 | ||
a8b6a80a | 487 | init: function(view) { |
a8b6a80a TL |
488 | let accountSelector = this.lookup('accountselector'); |
489 | accountSelector.store.on('load', this.onAccountsLoad, this); | |
490 | }, | |
491 | ||
492 | onAccountsLoad: function(store, records, success) { | |
80bd3209 DC |
493 | let me = this; |
494 | let vm = me.getViewModel(); | |
3071cc5b | 495 | let configaccount = vm.get('configaccount'); |
a8b6a80a | 496 | vm.set('accountsAvailable', records.length > 0); |
80bd3209 DC |
497 | if (me.autoChangeAccount && records.length > 0) { |
498 | me.changeAccount(records[0].data.name, () => { | |
31c9edc8 | 499 | vm.set('accountEditable', false); |
80bd3209 | 500 | me.reload(); |
31c9edc8 TL |
501 | }); |
502 | me.autoChangeAccount = false; | |
3071cc5b DC |
503 | } else if (configaccount) { |
504 | if (store.findExact('name', configaccount) !== -1) { | |
505 | vm.set('account', configaccount); | |
506 | } else { | |
507 | vm.set('account', null); | |
508 | } | |
31c9edc8 | 509 | } |
a8b6a80a TL |
510 | }, |
511 | ||
fd254233 DC |
512 | addDomain: function() { |
513 | let me = this; | |
514 | let view = me.getView(); | |
515 | ||
516 | Ext.create('PVE.node.ACMEDomainEdit', { | |
517 | nodename: view.nodename, | |
518 | nodeconfig: view.nodeconfig, | |
519 | apiCallDone: function() { | |
520 | me.reload(); | |
521 | }, | |
522 | }).show(); | |
523 | }, | |
524 | ||
525 | editDomain: function() { | |
526 | let me = this; | |
527 | let view = me.getView(); | |
528 | ||
529 | let selection = view.getSelection(); | |
530 | if (selection.length < 1) return; | |
531 | ||
532 | Ext.create('PVE.node.ACMEDomainEdit', { | |
533 | nodename: view.nodename, | |
534 | nodeconfig: view.nodeconfig, | |
535 | domain: selection[0].data, | |
536 | apiCallDone: function() { | |
537 | me.reload(); | |
538 | }, | |
539 | }).show(); | |
540 | }, | |
541 | ||
542 | removeDomain: function() { | |
543 | let me = this; | |
544 | let view = me.getView(); | |
545 | let selection = view.getSelection(); | |
546 | if (selection.length < 1) return; | |
547 | ||
548 | let rec = selection[0].data; | |
549 | let params = {}; | |
550 | if (rec.configkey !== 'acme') { | |
551 | params.delete = rec.configkey; | |
552 | } else { | |
553 | let acme = PVE.Parser.parseACME(view.nodeconfig.acme); | |
554 | PVE.Utils.remove_domain_from_acme(acme, rec.domain); | |
555 | params.acme = PVE.Parser.printACME(acme); | |
556 | } | |
557 | ||
558 | Proxmox.Utils.API2Request({ | |
559 | method: 'PUT', | |
560 | url: `/nodes/${view.nodename}/config`, | |
561 | params, | |
562 | success: function(response, opt) { | |
563 | me.reload(); | |
564 | }, | |
565 | failure: function(response, opt) { | |
566 | Ext.Msg.alert(gettext('Error'), response.htmlStatus); | |
567 | }, | |
568 | }); | |
569 | }, | |
570 | ||
571 | toggleEditAccount: function() { | |
572 | let me = this; | |
573 | let vm = me.getViewModel(); | |
574 | let editable = vm.get('accountEditable'); | |
575 | if (editable) { | |
576 | me.changeAccount(vm.get('account'), function() { | |
577 | vm.set('accountEditable', false); | |
578 | me.reload(); | |
579 | }); | |
580 | } else { | |
581 | vm.set('accountEditable', true); | |
582 | } | |
583 | }, | |
584 | ||
585 | changeAccount: function(account, callback) { | |
586 | let me = this; | |
587 | let view = me.getView(); | |
588 | let params = {}; | |
589 | ||
590 | let acme = PVE.Parser.parseACME(view.nodeconfig.acme); | |
591 | acme.account = account; | |
592 | params.acme = PVE.Parser.printACME(acme); | |
593 | ||
594 | Proxmox.Utils.API2Request({ | |
595 | method: 'PUT', | |
596 | waitMsgTarget: view, | |
597 | url: `/nodes/${view.nodename}/config`, | |
598 | params, | |
599 | success: function(response, opt) { | |
600 | if (Ext.isFunction(callback)) { | |
601 | callback(); | |
602 | } | |
603 | }, | |
604 | failure: function(response, opt) { | |
605 | Ext.Msg.alert(gettext('Error'), response.htmlStatus); | |
606 | }, | |
607 | }); | |
608 | }, | |
609 | ||
610 | order: function() { | |
611 | let me = this; | |
612 | let view = me.getView(); | |
613 | ||
614 | Proxmox.Utils.API2Request({ | |
615 | method: 'POST', | |
616 | params: { | |
617 | force: 1, | |
618 | }, | |
619 | url: `/nodes/${view.nodename}/certificates/acme/certificate`, | |
620 | success: function(response, opt) { | |
621 | Ext.create('Proxmox.window.TaskViewer', { | |
622 | upid: response.result.data, | |
623 | taskDone: function(success) { | |
624 | me.orderFinished(success); | |
625 | }, | |
626 | }).show(); | |
627 | }, | |
628 | failure: function(response, opt) { | |
629 | Ext.Msg.alert(gettext('Error'), response.htmlStatus); | |
630 | }, | |
631 | }); | |
632 | }, | |
633 | ||
634 | orderFinished: function(success) { | |
635 | if (!success) return; | |
72cfb3d4 FS |
636 | // reload only if the Web UI is open on the same node that the cert was ordered for |
637 | if (this.getView().nodename !== Proxmox.NodeName) { | |
638 | return; | |
639 | } | |
fd254233 DC |
640 | var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!'); |
641 | Ext.getBody().mask(txt, ['pve-static-mask']); | |
642 | // reload after 10 seconds automatically | |
643 | Ext.defer(function() { | |
644 | window.location.reload(true); | |
645 | }, 10000); | |
646 | }, | |
647 | ||
648 | reload: function() { | |
649 | let me = this; | |
650 | let view = me.getView(); | |
651 | view.rstore.load(); | |
652 | }, | |
653 | ||
31c9edc8 TL |
654 | addAccount: function() { |
655 | let me = this; | |
656 | Ext.create('PVE.node.ACMEAccountCreate', { | |
657 | autoShow: true, | |
658 | taskDone: function() { | |
659 | me.reload(); | |
660 | let accountSelector = me.lookup('accountselector'); | |
661 | me.autoChangeAccount = true; | |
662 | accountSelector.store.load(); | |
663 | }, | |
664 | }); | |
fd254233 DC |
665 | }, |
666 | }, | |
667 | ||
488be4c2 DC |
668 | tbar: [ |
669 | { | |
fd254233 DC |
670 | xtype: 'proxmoxButton', |
671 | text: gettext('Add'), | |
672 | handler: 'addDomain', | |
673 | selModel: false, | |
674 | }, | |
675 | { | |
676 | xtype: 'proxmoxButton', | |
677 | text: gettext('Edit'), | |
678 | disabled: true, | |
679 | handler: 'editDomain', | |
680 | }, | |
681 | { | |
682 | xtype: 'proxmoxStdRemoveButton', | |
683 | handler: 'removeDomain', | |
488be4c2 | 684 | }, |
fd254233 | 685 | '-', |
488be4c2 DC |
686 | { |
687 | xtype: 'button', | |
fd254233 | 688 | reference: 'order', |
a8b6a80a | 689 | text: gettext('Order Certificates Now'), |
31c9edc8 | 690 | bind: { |
1580b605 | 691 | disabled: '{!canOrder}', |
31c9edc8 | 692 | }, |
fd254233 DC |
693 | handler: 'order', |
694 | }, | |
695 | '-', | |
696 | { | |
697 | xtype: 'displayfield', | |
a8b6a80a TL |
698 | value: gettext('Using Account') + ':', |
699 | bind: { | |
700 | hidden: '{!accountsAvailable}', | |
701 | }, | |
fd254233 DC |
702 | }, |
703 | { | |
704 | xtype: 'displayfield', | |
705 | reference: 'accounttext', | |
3071cc5b | 706 | renderer: (val) => val || Proxmox.Utils.NoneText, |
fd254233 DC |
707 | bind: { |
708 | value: '{account}', | |
a8b6a80a | 709 | hidden: '{accountTextHidden}', |
fd254233 DC |
710 | }, |
711 | }, | |
712 | { | |
713 | xtype: 'pveACMEAccountSelector', | |
714 | hidden: true, | |
715 | reference: 'accountselector', | |
716 | bind: { | |
717 | value: '{account}', | |
a8b6a80a | 718 | hidden: '{accountValueHidden}', |
fd254233 | 719 | }, |
488be4c2 DC |
720 | }, |
721 | { | |
722 | xtype: 'button', | |
fd254233 | 723 | iconCls: 'fa black fa-pencil', |
fd254233 | 724 | bind: { |
a8b6a80a | 725 | iconCls: '{editBtnIcon}', |
8fc2d938 | 726 | text: '{editBtnText}', |
a8b6a80a | 727 | hidden: '{!accountsAvailable}', |
fd254233 DC |
728 | }, |
729 | handler: 'toggleEditAccount', | |
488be4c2 | 730 | }, |
a8b6a80a TL |
731 | { |
732 | xtype: 'displayfield', | |
733 | value: gettext('No Account available.'), | |
734 | bind: { | |
735 | hidden: '{accountsAvailable}', | |
736 | }, | |
737 | }, | |
488be4c2 DC |
738 | { |
739 | xtype: 'button', | |
fd254233 DC |
740 | hidden: true, |
741 | reference: 'accountlink', | |
31c9edc8 | 742 | text: gettext('Add ACME Account'), |
a8b6a80a TL |
743 | bind: { |
744 | hidden: '{accountsAvailable}', | |
745 | }, | |
31c9edc8 | 746 | handler: 'addAccount', |
80bd3209 | 747 | }, |
488be4c2 DC |
748 | ], |
749 | ||
fd254233 DC |
750 | updateStore: function(store, records, success) { |
751 | let me = this; | |
752 | let data = []; | |
753 | let rec; | |
754 | if (success && records.length > 0) { | |
755 | rec = records[0]; | |
756 | } else { | |
757 | rec = { | |
80bd3209 | 758 | data: {}, |
fd254233 | 759 | }; |
488be4c2 | 760 | } |
488be4c2 | 761 | |
fd254233 | 762 | me.nodeconfig = rec.data; // save nodeconfig for updates |
488be4c2 | 763 | |
fd254233 | 764 | let account = 'default'; |
488be4c2 | 765 | |
fd254233 DC |
766 | if (rec.data.acme) { |
767 | let obj = PVE.Parser.parseACME(rec.data.acme); | |
768 | (obj.domains || []).forEach(domain => { | |
769 | if (domain === '') return; | |
770 | let record = { | |
771 | domain, | |
772 | type: 'standalone', | |
773 | configkey: 'acme', | |
774 | }; | |
775 | data.push(record); | |
776 | }); | |
488be4c2 | 777 | |
fd254233 DC |
778 | if (obj.account) { |
779 | account = obj.account; | |
780 | } | |
781 | } | |
488be4c2 | 782 | |
fd254233 DC |
783 | let vm = me.getViewModel(); |
784 | let oldaccount = vm.get('account'); | |
785 | ||
786 | // account changed, and we do not edit currently, load again to verify | |
787 | if (oldaccount !== account && !vm.get('accountEditable')) { | |
3071cc5b DC |
788 | vm.set('configaccount', account); |
789 | me.lookup('accountselector').store.load(); | |
fd254233 | 790 | } |
488be4c2 | 791 | |
fd254233 DC |
792 | for (let i = 0; i < PVE.Utils.acmedomain_count; i++) { |
793 | let acmedomain = rec.data[`acmedomain${i}`]; | |
794 | if (!acmedomain) continue; | |
488be4c2 | 795 | |
fd254233 DC |
796 | let record = PVE.Parser.parsePropertyString(acmedomain, 'domain'); |
797 | record.type = 'dns'; | |
798 | record.configkey = `acmedomain${i}`; | |
799 | data.push(record); | |
800 | } | |
801 | ||
1580b605 | 802 | vm.set('domaincount', data.length); |
fd254233 | 803 | me.store.loadData(data, false); |
488be4c2 DC |
804 | }, |
805 | ||
806 | listeners: { | |
fd254233 | 807 | itemdblclick: 'editDomain', |
488be4c2 DC |
808 | }, |
809 | ||
fd254233 DC |
810 | columns: [ |
811 | { | |
812 | dataIndex: 'domain', | |
3c6b4c80 | 813 | flex: 5, |
fd254233 DC |
814 | text: gettext('Domain'), |
815 | }, | |
816 | { | |
817 | dataIndex: 'type', | |
3c6b4c80 | 818 | flex: 1, |
fd254233 DC |
819 | text: gettext('Type'), |
820 | }, | |
821 | { | |
822 | dataIndex: 'plugin', | |
3c6b4c80 | 823 | flex: 1, |
fd254233 DC |
824 | text: gettext('Plugin'), |
825 | }, | |
826 | ], | |
488be4c2 DC |
827 | |
828 | initComponent: function() { | |
829 | var me = this; | |
830 | ||
831 | if (!me.nodename) { | |
832 | throw "no nodename given"; | |
833 | } | |
834 | ||
fd254233 | 835 | me.rstore = Ext.create('Proxmox.data.UpdateStore', { |
1b90cfc6 | 836 | interval: 10 * 1000, |
fd254233 DC |
837 | autoStart: true, |
838 | storeid: `pve-node-domains-${me.nodename}`, | |
839 | proxy: { | |
840 | type: 'proxmox', | |
841 | url: `/api2/json/nodes/${me.nodename}/config`, | |
842 | }, | |
843 | }); | |
844 | ||
845 | me.store = Ext.create('Ext.data.Store', { | |
846 | model: 'pve-acme-domains', | |
847 | sorters: 'domain', | |
848 | }); | |
488be4c2 DC |
849 | |
850 | me.callParent(); | |
fd254233 DC |
851 | me.mon(me.rstore, 'load', 'updateStore', me); |
852 | Proxmox.Utils.monStoreErrors(me, me.rstore); | |
1f249769 | 853 | me.on('destroy', me.rstore.stopUpdate, me.rstore); |
fd254233 | 854 | }, |
488be4c2 | 855 | }); |