]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/node/Certificates.js
ui: cert upload: use inputpanel for certificate upload
[pve-manager.git] / www / manager6 / node / Certificates.js
CommitLineData
c287e233
DC
1Ext.define('PVE.node.CertificateView', {
2 extend: 'Ext.container.Container',
3 xtype: 'pveCertificatesView',
4
16dedd0f
DC
5 onlineHelp: 'sysadmin_certificate_management',
6
8058410f 7 mixins: ['Proxmox.Mixin.CBind'],
d3d48736 8 scrollable: 'y',
c287e233
DC
9
10 items: [
11 {
12 xtype: 'pveCertView',
13 border: 0,
14 cbind: {
f6710aac
TL
15 nodename: '{nodename}',
16 },
c287e233
DC
17 },
18 {
19 xtype: 'pveACMEView',
20 border: 0,
21 cbind: {
f6710aac
TL
22 nodename: '{nodename}',
23 },
24 },
25 ],
c287e233
DC
26
27});
28
29Ext.define('PVE.node.CertificateViewer', {
30 extend: 'Proxmox.window.Edit',
31
32 title: gettext('Certificate'),
33
34 fieldDefaults: {
f6710aac 35 labelWidth: 120,
c287e233
DC
36 },
37 width: 800,
c287e233 38
2f9fc811
TL
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 },
c287e233
DC
117
118 initComponent: function() {
48bbb009 119 let me = this;
c287e233
DC
120
121 if (!me.cert) {
122 throw "no cert given";
123 }
c287e233
DC
124 if (!me.nodename) {
125 throw "no nodename given";
126 }
127
48bbb009 128 me.url = `/nodes/${me.nodename}/certificates/info`;
c287e233
DC
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)) {
48bbb009 137 for (const item of response.result.data) {
c287e233
DC
138 if (item.filename === me.cert) {
139 me.setValues(item);
48bbb009 140 return;
c287e233 141 }
48bbb009 142 }
c287e233 143 }
f6710aac 144 },
c287e233 145 });
f6710aac 146 },
c287e233
DC
147});
148
149Ext.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 }
48bbb009 164 let txt = gettext('API server will be restarted to use new certificates, please reload web-interface!');
c287e233 165 Ext.getBody().mask(txt, ['pve-static-mask']);
48bbb009 166 Ext.defer(() => window.location.reload(true), 10000); // reload after 10 seconds automatically
c287e233
DC
167 },
168
1904262b
MC
169 items: {
170 xtype: 'inputpanel',
171 onGetValues: function(values) {
172 values.restart = 1;
173 values.force = 1;
174 return values;
c287e233 175 },
1904262b
MC
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 },
f6710aac
TL
195 },
196 },
1904262b
MC
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 },
f6710aac
TL
215 },
216 },
1904262b
MC
217 ],
218 },
c287e233
DC
219
220 initComponent: function() {
48bbb009 221 let me = this;
c287e233
DC
222 if (!me.nodename) {
223 throw "no nodename given";
224 }
48bbb009 225 me.url = `/nodes/${me.nodename}/certificates/custom`;
c287e233
DC
226
227 me.callParent();
f6710aac 228 },
c287e233
DC
229});
230
231Ext.define('pve-certificate', {
232 extend: 'Ext.data.Model',
8058410f 233 fields: ['filename', 'fingerprint', 'issuer', 'notafter', 'notbefore', 'subject', 'san', 'public-key-bits', 'public-key-type'],
f6710aac 234 idProperty: 'filename',
c287e233
DC
235});
236
237Ext.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() {
48bbb009
TL
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,
c287e233 253 });
f6710aac 254 },
c287e233
DC
255 },
256 {
028e4cd3 257 xtype: 'proxmoxStdRemoveButton',
c287e233
DC
258 itemId: 'deletebtn',
259 text: gettext('Delete Custom Certificate'),
028e4cd3
TL
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 }
f6710aac 274 },
c287e233
DC
275 },
276 '-',
277 {
278 xtype: 'proxmoxButton',
279 itemId: 'viewbtn',
280 disabled: true,
281 text: gettext('View Certificate'),
282 handler: function() {
48bbb009 283 this.up('grid').viewCertificate();
f6710aac
TL
284 },
285 },
c287e233
DC
286 ],
287
288 columns: [
289 {
290 header: gettext('File'),
291 width: 150,
f6710aac 292 dataIndex: 'filename',
c287e233
DC
293 },
294 {
295 header: gettext('Issuer'),
296 flex: 1,
f6710aac 297 dataIndex: 'issuer',
c287e233
DC
298 },
299 {
300 header: gettext('Subject'),
301 flex: 1,
f6710aac 302 dataIndex: 'subject',
c287e233 303 },
e81645f5
AA
304 {
305 header: gettext('Public Key Alogrithm'),
306 flex: 1,
307 dataIndex: 'public-key-type',
f6710aac 308 hidden: true,
e81645f5
AA
309 },
310 {
311 header: gettext('Public Key Size'),
312 flex: 1,
313 dataIndex: 'public-key-bits',
f6710aac 314 hidden: true,
e81645f5 315 },
c287e233
DC
316 {
317 header: gettext('Valid Since'),
318 width: 150,
319 dataIndex: 'notbefore',
f6710aac 320 renderer: Proxmox.Utils.render_timestamp,
c287e233
DC
321 },
322 {
323 header: gettext('Expires'),
324 width: 150,
325 dataIndex: 'notafter',
f6710aac 326 renderer: Proxmox.Utils.render_timestamp,
c287e233
DC
327 },
328 {
329 header: gettext('Subject Alternative Names'),
330 flex: 1,
331 dataIndex: 'san',
f6710aac 332 renderer: PVE.Utils.render_san,
c287e233
DC
333 },
334 {
335 header: gettext('Fingerprint'),
336 dataIndex: 'fingerprint',
f6710aac 337 hidden: true,
c287e233
DC
338 },
339 {
340 header: gettext('PEM'),
341 dataIndex: 'pem',
f6710aac
TL
342 hidden: true,
343 },
c287e233
DC
344 ],
345
346 reload: function() {
48bbb009 347 this.rstore.load();
c287e233
DC
348 },
349
48bbb009
TL
350 viewCertificate: function() {
351 let me = this;
352 let selection = me.getSelection();
c287e233
DC
353 if (!selection || selection.length < 1) {
354 return;
355 }
356 var win = Ext.create('PVE.node.CertificateViewer', {
357 cert: selection[0].data.filename,
8058410f 358 nodename: me.nodename,
c287e233
DC
359 });
360 win.show();
361 },
362
363 listeners: {
48bbb009 364 itemdblclick: 'viewCertificate',
c287e233
DC
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',
f6710aac
TL
379 url: '/api2/json/nodes/' + me.nodename + '/certificates/info',
380 },
c287e233
DC
381 });
382
383 me.store = {
384 type: 'diff',
f6710aac 385 rstore: me.rstore,
c287e233
DC
386 };
387
388 me.callParent();
389
48bbb009 390 me.mon(me.rstore, 'load', store => me.down('#deletebtn').setDisabled(!store.getById('pveproxy-ssl.pem')));
c287e233 391 me.rstore.startUpdate();
1f249769 392 me.on('destroy', me.rstore.stopUpdate, me.rstore);
f6710aac 393 },
c287e233 394});