]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/node/Certificates.js
ui: factor out not found rendering to common helper
[pve-manager.git] / www / manager6 / node / Certificates.js
1 Ext.define('PVE.node.CertificateView', {
2 extend: 'Ext.container.Container',
3 xtype: 'pveCertificatesView',
4
5 onlineHelp: 'sysadmin_certificate_management',
6
7 mixins: ['Proxmox.Mixin.CBind'],
8 scrollable: 'y',
9
10 items: [
11 {
12 xtype: 'pveCertView',
13 border: 0,
14 cbind: {
15 nodename: '{nodename}',
16 },
17 },
18 {
19 xtype: 'pveACMEView',
20 border: 0,
21 cbind: {
22 nodename: '{nodename}',
23 },
24 },
25 ],
26
27 });
28
29 Ext.define('PVE.node.CertificateViewer', {
30 extend: 'Proxmox.window.Edit',
31
32 title: gettext('Certificate'),
33
34 fieldDefaults: {
35 labelWidth: 120,
36 },
37 width: 800,
38
39 items: {
40 xtype: 'inputpanel',
41 maxHeight: 900,
42 scrollable: 'y',
43 columnT: [
44 {
45 xtype: 'displayfield',
46 fieldLabel: gettext('Name'),
47 name: 'filename',
48 },
49 {
50 xtype: 'displayfield',
51 fieldLabel: gettext('Fingerprint'),
52 name: 'fingerprint',
53 },
54 {
55 xtype: 'displayfield',
56 fieldLabel: gettext('Issuer'),
57 name: 'issuer',
58 },
59 {
60 xtype: 'displayfield',
61 fieldLabel: gettext('Subject'),
62 name: 'subject',
63 },
64 ],
65 column1: [
66 {
67 xtype: 'displayfield',
68 fieldLabel: gettext('Public Key Type'),
69 name: 'public-key-type',
70 },
71 {
72 xtype: 'displayfield',
73 fieldLabel: gettext('Public Key Size'),
74 name: 'public-key-bits',
75 },
76 ],
77 column2: [
78 {
79 xtype: 'displayfield',
80 fieldLabel: gettext('Valid Since'),
81 renderer: Proxmox.Utils.render_timestamp,
82 name: 'notbefore',
83 },
84 {
85 xtype: 'displayfield',
86 fieldLabel: gettext('Expires'),
87 renderer: Proxmox.Utils.render_timestamp,
88 name: 'notafter',
89 },
90 ],
91 columnB: [
92 {
93 xtype: 'displayfield',
94 fieldLabel: gettext('Subject Alternative Names'),
95 name: 'san',
96 renderer: PVE.Utils.render_san,
97 },
98 {
99 xtype: 'fieldset',
100 title: gettext('Raw Certificate'),
101 collapsible: true,
102 collapsed: true,
103 items: [{
104 xtype: 'textarea',
105 name: 'pem',
106 editable: false,
107 grow: true,
108 growMax: 350,
109 fieldStyle: {
110 'white-space': 'pre-wrap',
111 'font-family': 'monospace',
112 },
113 }],
114 },
115 ],
116 },
117
118 initComponent: function() {
119 let me = this;
120
121 if (!me.cert) {
122 throw "no cert given";
123 }
124 if (!me.nodename) {
125 throw "no nodename given";
126 }
127
128 me.url = `/nodes/${me.nodename}/certificates/info`;
129 me.callParent();
130
131 // hide OK/Reset button, because we just want to show data
132 me.down('toolbar[dock=bottom]').setVisible(false);
133
134 me.load({
135 success: function(response) {
136 if (Ext.isArray(response.result.data)) {
137 for (const item of response.result.data) {
138 if (item.filename === me.cert) {
139 me.setValues(item);
140 return;
141 }
142 }
143 }
144 },
145 });
146 },
147 });
148
149 Ext.define('PVE.node.CertUpload', {
150 extend: 'Proxmox.window.Edit',
151 xtype: 'pveCertUpload',
152
153 title: gettext('Upload Custom Certificate'),
154 resizable: false,
155 isCreate: true,
156 submitText: gettext('Upload'),
157 method: 'POST',
158 width: 600,
159
160 apiCallDone: function(success, response, options) {
161 if (!success) {
162 return;
163 }
164 let txt = gettext('API server will be restarted to use new certificates, please reload web-interface!');
165 Ext.getBody().mask(txt, ['pve-static-mask']);
166 Ext.defer(() => window.location.reload(true), 10000); // reload after 10 seconds automatically
167 },
168
169 items: [
170 {
171 fieldLabel: gettext('Private Key (Optional)'),
172 labelAlign: 'top',
173 emptyText: gettext('No change'),
174 name: 'key',
175 xtype: 'textarea',
176 },
177 {
178 xtype: 'filebutton',
179 text: gettext('From File'),
180 listeners: {
181 change: function(btn, e, value) {
182 let form = this.up('form');
183 for (const file of e.event.target.files) {
184 PVE.Utils.loadFile(file, res => form.down('field[name=key]').setValue(res));
185 }
186 btn.reset();
187 },
188 },
189 },
190 {
191 xtype: 'box',
192 autoEl: 'hr',
193 },
194 {
195 fieldLabel: gettext('Certificate Chain'),
196 labelAlign: 'top',
197 allowBlank: false,
198 name: 'certificates',
199 xtype: 'textarea',
200 },
201 {
202 xtype: 'filebutton',
203 text: gettext('From File'),
204 listeners: {
205 change: function(btn, e, value) {
206 let form = this.up('form');
207 for (const file of e.event.target.files) {
208 PVE.Utils.loadFile(file, res => form.down('field[name=certificates]').setValue(res));
209 }
210 btn.reset();
211 },
212 },
213 },
214 {
215 xtype: 'hidden',
216 name: 'restart',
217 value: '1',
218 },
219 {
220 xtype: 'hidden',
221 name: 'force',
222 value: '1',
223 },
224 ],
225
226 initComponent: function() {
227 let me = this;
228 if (!me.nodename) {
229 throw "no nodename given";
230 }
231 me.url = `/nodes/${me.nodename}/certificates/custom`;
232
233 me.callParent();
234 },
235 });
236
237 Ext.define('pve-certificate', {
238 extend: 'Ext.data.Model',
239 fields: ['filename', 'fingerprint', 'issuer', 'notafter', 'notbefore', 'subject', 'san', 'public-key-bits', 'public-key-type'],
240 idProperty: 'filename',
241 });
242
243 Ext.define('PVE.node.Certificates', {
244 extend: 'Ext.grid.Panel',
245 xtype: 'pveCertView',
246
247 tbar: [
248 {
249 xtype: 'button',
250 text: gettext('Upload Custom Certificate'),
251 handler: function() {
252 let view = this.up('grid');
253 Ext.create('PVE.node.CertUpload', {
254 nodename: view.nodename,
255 listeners: {
256 destroy: () => view.reload(),
257 },
258 autoShow: true,
259 });
260 },
261 },
262 {
263 xtype: 'proxmoxStdRemoveButton',
264 itemId: 'deletebtn',
265 text: gettext('Delete Custom Certificate'),
266 dangerous: true,
267 selModel: false,
268 getUrl: function(rec) {
269 let view = this.up('grid');
270 return `/nodes/${view.nodename}/certificates/custom?restart=1`;
271 },
272 confirmMsg: gettext('Delete custom certificate and switch to generated one?'),
273 callback: function(options, success, response) {
274 if (success) {
275 let txt = gettext('API server will be restarted to use new certificates, please reload web-interface!');
276 Ext.getBody().mask(txt, ['pve-static-mask']);
277 // reload after 10 seconds automatically
278 Ext.defer(() => window.location.reload(true), 10000);
279 }
280 },
281 },
282 '-',
283 {
284 xtype: 'proxmoxButton',
285 itemId: 'viewbtn',
286 disabled: true,
287 text: gettext('View Certificate'),
288 handler: function() {
289 this.up('grid').viewCertificate();
290 },
291 },
292 ],
293
294 columns: [
295 {
296 header: gettext('File'),
297 width: 150,
298 dataIndex: 'filename',
299 },
300 {
301 header: gettext('Issuer'),
302 flex: 1,
303 dataIndex: 'issuer',
304 },
305 {
306 header: gettext('Subject'),
307 flex: 1,
308 dataIndex: 'subject',
309 },
310 {
311 header: gettext('Public Key Alogrithm'),
312 flex: 1,
313 dataIndex: 'public-key-type',
314 hidden: true,
315 },
316 {
317 header: gettext('Public Key Size'),
318 flex: 1,
319 dataIndex: 'public-key-bits',
320 hidden: true,
321 },
322 {
323 header: gettext('Valid Since'),
324 width: 150,
325 dataIndex: 'notbefore',
326 renderer: Proxmox.Utils.render_timestamp,
327 },
328 {
329 header: gettext('Expires'),
330 width: 150,
331 dataIndex: 'notafter',
332 renderer: Proxmox.Utils.render_timestamp,
333 },
334 {
335 header: gettext('Subject Alternative Names'),
336 flex: 1,
337 dataIndex: 'san',
338 renderer: PVE.Utils.render_san,
339 },
340 {
341 header: gettext('Fingerprint'),
342 dataIndex: 'fingerprint',
343 hidden: true,
344 },
345 {
346 header: gettext('PEM'),
347 dataIndex: 'pem',
348 hidden: true,
349 },
350 ],
351
352 reload: function() {
353 this.rstore.load();
354 },
355
356 viewCertificate: function() {
357 let me = this;
358 let selection = me.getSelection();
359 if (!selection || selection.length < 1) {
360 return;
361 }
362 var win = Ext.create('PVE.node.CertificateViewer', {
363 cert: selection[0].data.filename,
364 nodename: me.nodename,
365 });
366 win.show();
367 },
368
369 listeners: {
370 itemdblclick: 'viewCertificate',
371 },
372
373 initComponent: function() {
374 var me = this;
375
376 if (!me.nodename) {
377 throw "no nodename given";
378 }
379
380 me.rstore = Ext.create('Proxmox.data.UpdateStore', {
381 storeid: 'certs-' + me.nodename,
382 model: 'pve-certificate',
383 proxy: {
384 type: 'proxmox',
385 url: '/api2/json/nodes/' + me.nodename + '/certificates/info',
386 },
387 });
388
389 me.store = {
390 type: 'diff',
391 rstore: me.rstore,
392 };
393
394 me.callParent();
395
396 me.mon(me.rstore, 'load', store => me.down('#deletebtn').setDisabled(!store.getById('pveproxy-ssl.pem')));
397 me.rstore.startUpdate();
398 me.on('destroy', me.rstore.stopUpdate, me.rstore);
399 },
400 });