]> git.proxmox.com Git - proxmox-widget-toolkit.git/blob - src/panel/Certificates.js
Buttons: add AltText
[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 Ext.getBody().mask(
90 gettext('API server will be restarted to use new certificates, please reload web-interface!'),
91 ['pve-static-mask'],
92 );
93 // try to reload after 10 seconds automatically
94 Ext.defer(() => window.location.reload(true), 10000);
95 }
96 },
97 failure: function(response, opt) {
98 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
99 },
100 });
101 },
102
103 controller: {
104 xclass: 'Ext.app.ViewController',
105 view_certificate: function() {
106 let me = this;
107 let view = me.getView();
108
109 let selection = view.getSelection();
110 if (!selection || selection.length < 1) {
111 return;
112 }
113 let win = Ext.create('Proxmox.window.CertificateViewer', {
114 cert: selection[0].data.filename,
115 url: `/api2/extjs/${view.infoUrl}`,
116 });
117 win.show();
118 },
119 },
120
121 listeners: {
122 itemdblclick: 'view_certificate',
123 },
124
125 initComponent: function() {
126 let me = this;
127
128 if (!me.nodename) {
129 // only used for the store name
130 me.nodename = "_all";
131 }
132
133 if (!me.uploadButtons) {
134 throw "no upload buttons defined";
135 }
136
137 if (!me.infoUrl) {
138 throw "no certificate store url given";
139 }
140
141 me.rstore = Ext.create('Proxmox.data.UpdateStore', {
142 storeid: 'certs-' + me.nodename,
143 model: 'proxmox-certificate',
144 proxy: {
145 type: 'proxmox',
146 url: `/api2/extjs/${me.infoUrl}`,
147 },
148 });
149
150 me.store = {
151 type: 'diff',
152 rstore: me.rstore,
153 };
154
155 let tbar = [];
156
157 me.deletableCertIds = {};
158 me.certById = {};
159 if (me.uploadButtons.length === 1) {
160 let cert = me.uploadButtons[0];
161
162 if (!cert.url) {
163 throw "missing certificate url";
164 }
165
166 me.certById[cert.id] = cert;
167
168 if (cert.deletable) {
169 me.deletableCertIds[cert.id] = true;
170 }
171
172 tbar.push(
173 {
174 xtype: 'button',
175 text: gettext('Upload Custom Certificate'),
176 handler: function() {
177 let grid = this.up('grid');
178 let win = Ext.create('Proxmox.window.CertificateUpload', {
179 url: `/api2/extjs/${cert.url}`,
180 reloadUi: cert.reloadUi,
181 });
182 win.show();
183 win.on('destroy', grid.reload, grid);
184 },
185 },
186 );
187 } else {
188 let items = [];
189
190 me.selModel = Ext.create('Ext.selection.RowModel', {});
191
192 for (const cert of me.uploadButtons) {
193 if (!cert.id) {
194 throw "missing id in certificate entry";
195 }
196
197 if (!cert.url) {
198 throw "missing url in certificate entry";
199 }
200
201 if (!cert.name) {
202 throw "missing name in certificate entry";
203 }
204
205 me.certById[cert.id] = cert;
206
207 if (cert.deletable) {
208 me.deletableCertIds[cert.id] = true;
209 }
210
211 items.push({
212 text: Ext.String.format('Upload {0} Certificate', cert.name),
213 handler: function() {
214 let grid = this.up('grid');
215 let win = Ext.create('Proxmox.window.CertificateUpload', {
216 url: `/api2/extjs/${cert.url}`,
217 reloadUi: cert.reloadUi,
218 });
219 win.show();
220 win.on('destroy', grid.reload, grid);
221 },
222 });
223 }
224
225 tbar.push(
226 {
227 text: gettext('Upload Custom Certificate'),
228 menu: {
229 xtype: 'menu',
230 items,
231 },
232 },
233 );
234 }
235
236 tbar.push(
237 {
238 xtype: 'proxmoxButton',
239 text: gettext('Delete Custom Certificate'),
240 confirmMsg: rec => Ext.String.format(
241 gettext('Are you sure you want to remove the certificate used for {0}'),
242 me.certById[rec.id].name,
243 ),
244 callback: () => me.reload(),
245 selModel: me.selModel,
246 disabled: true,
247 enableFn: rec => !!me.deletableCertIds[rec.id],
248 handler: function() { me.delete_certificate(); },
249 },
250 '-',
251 {
252 xtype: 'proxmoxButton',
253 itemId: 'viewbtn',
254 disabled: true,
255 text: gettext('View Certificate'),
256 handler: 'view_certificate',
257 },
258 );
259 Ext.apply(me, { tbar });
260
261 me.callParent();
262
263 me.rstore.startUpdate();
264 me.on('destroy', me.rstore.stopUpdate, me.rstore);
265 },
266 });