]> git.proxmox.com Git - proxmox-widget-toolkit.git/blob - src/panel/Certificates.js
add certificate panel
[proxmox-widget-toolkit.git] / src / panel / Certificates.js
1 Ext.define('Proxmox.panel.Certificates', {
2 extend: 'Ext.grid.Panel',
3 xtype: 'pmxCertificates',
4
5 // array of { name, id (=filename), url, deletable, reloadUi }
6 uploadButtons: undefined,
7
8 // The /info path for the current node.
9 infoUrl: undefined,
10
11 columns: [
12 {
13 header: gettext('File'),
14 width: 150,
15 dataIndex: 'filename',
16 },
17 {
18 header: gettext('Issuer'),
19 flex: 1,
20 dataIndex: 'issuer',
21 },
22 {
23 header: gettext('Subject'),
24 flex: 1,
25 dataIndex: 'subject',
26 },
27 {
28 header: gettext('Public Key Alogrithm'),
29 flex: 1,
30 dataIndex: 'public-key-type',
31 hidden: true,
32 },
33 {
34 header: gettext('Public Key Size'),
35 flex: 1,
36 dataIndex: 'public-key-bits',
37 hidden: true,
38 },
39 {
40 header: gettext('Valid Since'),
41 width: 150,
42 dataIndex: 'notbefore',
43 renderer: Proxmox.Utils.render_timestamp,
44 },
45 {
46 header: gettext('Expires'),
47 width: 150,
48 dataIndex: 'notafter',
49 renderer: Proxmox.Utils.render_timestamp,
50 },
51 {
52 header: gettext('Subject Alternative Names'),
53 flex: 1,
54 dataIndex: 'san',
55 renderer: Proxmox.Utils.render_san,
56 },
57 {
58 header: gettext('Fingerprint'),
59 dataIndex: 'fingerprint',
60 hidden: true,
61 },
62 {
63 header: gettext('PEM'),
64 dataIndex: 'pem',
65 hidden: true,
66 },
67 ],
68
69 reload: function() {
70 let me = this;
71 me.rstore.load();
72 },
73
74 delete_certificate: function() {
75 let me = this;
76
77 let rec = me.selModel.getSelection()[0];
78 if (!rec) {
79 return;
80 }
81
82 let cert = me.certById[rec.id];
83 let url = cert.url;
84 Proxmox.Utils.API2Request({
85 url: `/api2/extjs/${url}?restart=1`,
86 method: 'DELETE',
87 success: function(response, opt) {
88 if (cert.reloadUid) {
89 let txt =
90 gettext('GUI will be restarted with new certificates, please reload!');
91 Ext.getBody().mask(txt, ['x-mask-loading']);
92 // reload after 10 seconds automatically
93 Ext.defer(function() {
94 window.location.reload(true);
95 }, 10000);
96 }
97 },
98 failure: function(response, opt) {
99 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
100 },
101 });
102 },
103
104 controller: {
105 xclass: 'Ext.app.ViewController',
106 view_certificate: function() {
107 let me = this;
108 let view = me.getView();
109
110 let selection = view.getSelection();
111 if (!selection || selection.length < 1) {
112 return;
113 }
114 let win = Ext.create('Proxmox.window.CertificateViewer', {
115 cert: selection[0].data.filename,
116 url: `/api2/extjs/${view.infoUrl}`,
117 });
118 win.show();
119 },
120 },
121
122 listeners: {
123 itemdblclick: 'view_certificate',
124 },
125
126 initComponent: function() {
127 let me = this;
128
129 if (!me.nodename) {
130 // only used for the store name
131 me.nodename = "_all";
132 }
133
134 if (!me.uploadButtons) {
135 throw "no upload buttons defined";
136 }
137
138 if (!me.infoUrl) {
139 throw "no certificate store url given";
140 }
141
142 me.rstore = Ext.create('Proxmox.data.UpdateStore', {
143 storeid: 'certs-' + me.nodename,
144 model: 'proxmox-certificate',
145 proxy: {
146 type: 'proxmox',
147 url: `/api2/extjs/${me.infoUrl}`,
148 },
149 });
150
151 me.store = {
152 type: 'diff',
153 rstore: me.rstore,
154 };
155
156 let tbar = [];
157
158 me.deletableCertIds = {};
159 me.certById = {};
160 if (me.uploadButtons.length === 1) {
161 let cert = me.uploadButtons[0];
162
163 if (!cert.url) {
164 throw "missing certificate url";
165 }
166
167 me.certById[cert.id] = cert;
168
169 if (cert.deletable) {
170 me.deletableCertIds[cert.id] = true;
171 }
172
173 tbar.push(
174 {
175 xtype: 'button',
176 text: gettext('Upload Custom Certificate'),
177 handler: function() {
178 let grid = this.up('grid');
179 let win = Ext.create('Proxmox.window.CertificateUpload', {
180 url: `/api2/extjs/${cert.url}`,
181 reloadUi: cert.reloadUi,
182 });
183 win.show();
184 win.on('destroy', grid.reload, grid);
185 },
186 },
187 );
188 } else {
189 let items = [];
190
191 me.selModel = Ext.create('Ext.selection.RowModel', {});
192
193 for (const cert of me.uploadButtons) {
194 if (!cert.id) {
195 throw "missing id in certificate entry";
196 }
197
198 if (!cert.url) {
199 throw "missing url in certificate entry";
200 }
201
202 if (!cert.name) {
203 throw "missing name in certificate entry";
204 }
205
206 me.certById[cert.id] = cert;
207
208 if (cert.deletable) {
209 me.deletableCertIds[cert.id] = true;
210 }
211
212 items.push({
213 text: Ext.String.format('Upload {0} Certificate', cert.name),
214 handler: function() {
215 let grid = this.up('grid');
216 let win = Ext.create('Proxmox.window.CertificateUpload', {
217 url: `/api2/extjs/${cert.url}`,
218 reloadUi: cert.reloadUi,
219 });
220 win.show();
221 win.on('destroy', grid.reload, grid);
222 },
223 });
224 }
225
226 tbar.push(
227 {
228 text: gettext('Upload Custom Certificate'),
229 menu: {
230 xtype: 'menu',
231 items,
232 },
233 },
234 );
235 }
236
237 tbar.push(
238 {
239 xtype: 'proxmoxButton',
240 text: gettext('Delete Custom Certificate'),
241 confirmMsg: rec => Ext.String.format(
242 gettext('Are you sure you want to remove the certificate used for {0}'),
243 me.certById[rec.id].name,
244 ),
245 callback: () => me.reload(),
246 selModel: me.selModel,
247 disabled: true,
248 enableFn: rec => !!me.deletableCertIds[rec.id],
249 handler: function() { me.delete_certificate(); },
250 },
251 '-',
252 {
253 xtype: 'proxmoxButton',
254 itemId: 'viewbtn',
255 disabled: true,
256 text: gettext('View Certificate'),
257 handler: 'view_certificate',
258 },
259 );
260 Ext.apply(me, { tbar });
261
262 me.callParent();
263
264 me.rstore.startUpdate();
265 me.on('destroy', me.rstore.stopUpdate, me.rstore);
266 },
267 });