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