]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/node/Certificates.js
29c173595d7cb5e5275bc97b8790641a19215564
[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 xtype: 'inputpanel',
171 onGetValues: function(values) {
172 values.restart = 1;
173 values.force = 1;
174 return values;
175 },
176 items: [
177 {
178 fieldLabel: gettext('Private Key (Optional)'),
179 labelAlign: 'top',
180 emptyText: gettext('No change'),
181 name: 'key',
182 xtype: 'textarea',
183 },
184 {
185 xtype: 'filebutton',
186 text: gettext('From File'),
187 listeners: {
188 change: function(btn, e, value) {
189 let form = this.up('form');
190 for (const file of e.event.target.files) {
191 PVE.Utils.loadFile(file, res => form.down('field[name=key]').setValue(res));
192 }
193 btn.reset();
194 },
195 },
196 },
197 {
198 fieldLabel: gettext('Certificate Chain'),
199 labelAlign: 'top',
200 allowBlank: false,
201 name: 'certificates',
202 xtype: 'textarea',
203 },
204 {
205 xtype: 'filebutton',
206 text: gettext('From File'),
207 listeners: {
208 change: function(btn, e, value) {
209 let form = this.up('form');
210 for (const file of e.event.target.files) {
211 PVE.Utils.loadFile(file, res => form.down('field[name=certificates]').setValue(res));
212 }
213 btn.reset();
214 },
215 },
216 },
217 ],
218 },
219
220 initComponent: function() {
221 let me = this;
222 if (!me.nodename) {
223 throw "no nodename given";
224 }
225 me.url = `/nodes/${me.nodename}/certificates/custom`;
226
227 me.callParent();
228 },
229 });
230
231 Ext.define('pve-certificate', {
232 extend: 'Ext.data.Model',
233 fields: ['filename', 'fingerprint', 'issuer', 'notafter', 'notbefore', 'subject', 'san', 'public-key-bits', 'public-key-type'],
234 idProperty: 'filename',
235 });
236
237 Ext.define('PVE.node.Certificates', {
238 extend: 'Ext.grid.Panel',
239 xtype: 'pveCertView',
240
241 tbar: [
242 {
243 xtype: 'button',
244 text: gettext('Upload Custom Certificate'),
245 handler: function() {
246 let view = this.up('grid');
247 Ext.create('PVE.node.CertUpload', {
248 nodename: view.nodename,
249 listeners: {
250 destroy: () => view.reload(),
251 },
252 autoShow: true,
253 });
254 },
255 },
256 {
257 xtype: 'proxmoxStdRemoveButton',
258 itemId: 'deletebtn',
259 text: gettext('Delete Custom Certificate'),
260 dangerous: true,
261 selModel: false,
262 getUrl: function(rec) {
263 let view = this.up('grid');
264 return `/nodes/${view.nodename}/certificates/custom?restart=1`;
265 },
266 confirmMsg: gettext('Delete custom certificate and switch to generated one?'),
267 callback: function(options, success, response) {
268 if (success) {
269 let txt = gettext('API server will be restarted to use new certificates, please reload web-interface!');
270 Ext.getBody().mask(txt, ['pve-static-mask']);
271 // reload after 10 seconds automatically
272 Ext.defer(() => window.location.reload(true), 10000);
273 }
274 },
275 },
276 '-',
277 {
278 xtype: 'proxmoxButton',
279 itemId: 'viewbtn',
280 disabled: true,
281 text: gettext('View Certificate'),
282 handler: function() {
283 this.up('grid').viewCertificate();
284 },
285 },
286 ],
287
288 columns: [
289 {
290 header: gettext('File'),
291 width: 150,
292 dataIndex: 'filename',
293 },
294 {
295 header: gettext('Issuer'),
296 flex: 1,
297 dataIndex: 'issuer',
298 },
299 {
300 header: gettext('Subject'),
301 flex: 1,
302 dataIndex: 'subject',
303 },
304 {
305 header: gettext('Public Key Alogrithm'),
306 flex: 1,
307 dataIndex: 'public-key-type',
308 hidden: true,
309 },
310 {
311 header: gettext('Public Key Size'),
312 flex: 1,
313 dataIndex: 'public-key-bits',
314 hidden: true,
315 },
316 {
317 header: gettext('Valid Since'),
318 width: 150,
319 dataIndex: 'notbefore',
320 renderer: Proxmox.Utils.render_timestamp,
321 },
322 {
323 header: gettext('Expires'),
324 width: 150,
325 dataIndex: 'notafter',
326 renderer: Proxmox.Utils.render_timestamp,
327 },
328 {
329 header: gettext('Subject Alternative Names'),
330 flex: 1,
331 dataIndex: 'san',
332 renderer: PVE.Utils.render_san,
333 },
334 {
335 header: gettext('Fingerprint'),
336 dataIndex: 'fingerprint',
337 hidden: true,
338 },
339 {
340 header: gettext('PEM'),
341 dataIndex: 'pem',
342 hidden: true,
343 },
344 ],
345
346 reload: function() {
347 this.rstore.load();
348 },
349
350 viewCertificate: function() {
351 let me = this;
352 let selection = me.getSelection();
353 if (!selection || selection.length < 1) {
354 return;
355 }
356 var win = Ext.create('PVE.node.CertificateViewer', {
357 cert: selection[0].data.filename,
358 nodename: me.nodename,
359 });
360 win.show();
361 },
362
363 listeners: {
364 itemdblclick: 'viewCertificate',
365 },
366
367 initComponent: function() {
368 var me = this;
369
370 if (!me.nodename) {
371 throw "no nodename given";
372 }
373
374 me.rstore = Ext.create('Proxmox.data.UpdateStore', {
375 storeid: 'certs-' + me.nodename,
376 model: 'pve-certificate',
377 proxy: {
378 type: 'proxmox',
379 url: '/api2/json/nodes/' + me.nodename + '/certificates/info',
380 },
381 });
382
383 me.store = {
384 type: 'diff',
385 rstore: me.rstore,
386 };
387
388 me.callParent();
389
390 me.mon(me.rstore, 'load', store => me.down('#deletebtn').setDisabled(!store.getById('pveproxy-ssl.pem')));
391 me.rstore.startUpdate();
392 me.on('destroy', me.rstore.stopUpdate, me.rstore);
393 },
394 });