5 |
5 |
6 """ |
6 """ |
7 Module implementing a dialog to show and edit all certificates. |
7 Module implementing a dialog to show and edit all certificates. |
8 """ |
8 """ |
9 |
9 |
10 from PyQt4.QtCore import pyqtSlot, Qt, QByteArray, QFile, QFileInfo, QIODevice, \ |
10 from PyQt4.QtCore import pyqtSlot, Qt, QByteArray, QFile, QFileInfo, \ |
11 qVersion |
11 QIODevice, qVersion |
12 from PyQt4.QtGui import QDialog, QTreeWidgetItem |
12 from PyQt4.QtGui import QDialog, QTreeWidgetItem |
13 try: |
13 try: |
14 from PyQt4.QtNetwork import QSslCertificate, QSslSocket, QSslConfiguration, QSsl |
14 from PyQt4.QtNetwork import QSslCertificate, QSslSocket, \ |
|
15 QSslConfiguration, QSsl |
15 except ImportError: |
16 except ImportError: |
16 pass |
17 pass |
17 |
18 |
18 from E5Gui import E5MessageBox, E5FileDialog |
19 from E5Gui import E5MessageBox, E5FileDialog |
19 |
20 |
37 @param parent reference to the parent widget (QWidget) |
38 @param parent reference to the parent widget (QWidget) |
38 """ |
39 """ |
39 super().__init__(parent) |
40 super().__init__(parent) |
40 self.setupUi(self) |
41 self.setupUi(self) |
41 |
42 |
42 self.serversViewButton.setIcon(UI.PixmapCache.getIcon("certificates.png")) |
43 self.serversViewButton.setIcon( |
43 self.serversDeleteButton.setIcon(UI.PixmapCache.getIcon("certificateDelete.png")) |
44 UI.PixmapCache.getIcon("certificates.png")) |
44 self.serversExportButton.setIcon(UI.PixmapCache.getIcon("certificateExport.png")) |
45 self.serversDeleteButton.setIcon( |
45 self.serversImportButton.setIcon(UI.PixmapCache.getIcon("certificateImport.png")) |
46 UI.PixmapCache.getIcon("certificateDelete.png")) |
46 |
47 self.serversExportButton.setIcon( |
47 self.caViewButton.setIcon(UI.PixmapCache.getIcon("certificates.png")) |
48 UI.PixmapCache.getIcon("certificateExport.png")) |
48 self.caDeleteButton.setIcon(UI.PixmapCache.getIcon("certificateDelete.png")) |
49 self.serversImportButton.setIcon( |
49 self.caExportButton.setIcon(UI.PixmapCache.getIcon("certificateExport.png")) |
50 UI.PixmapCache.getIcon("certificateImport.png")) |
50 self.caImportButton.setIcon(UI.PixmapCache.getIcon("certificateImport.png")) |
51 |
|
52 self.caViewButton.setIcon( |
|
53 UI.PixmapCache.getIcon("certificates.png")) |
|
54 self.caDeleteButton.setIcon( |
|
55 UI.PixmapCache.getIcon("certificateDelete.png")) |
|
56 self.caExportButton.setIcon( |
|
57 UI.PixmapCache.getIcon("certificateExport.png")) |
|
58 self.caImportButton.setIcon( |
|
59 UI.PixmapCache.getIcon("certificateImport.png")) |
51 |
60 |
52 self.__populateServerCertificatesTree() |
61 self.__populateServerCertificatesTree() |
53 self.__populateCaCertificatesTree() |
62 self.__populateCaCertificatesTree() |
54 |
63 |
55 def __populateServerCertificatesTree(self): |
64 def __populateServerCertificatesTree(self): |
92 |
101 |
93 # step 2: create the entry |
102 # step 2: create the entry |
94 items = self.serversCertificatesTree.findItems(organisation, |
103 items = self.serversCertificatesTree.findItems(organisation, |
95 Qt.MatchFixedString | Qt.MatchCaseSensitive) |
104 Qt.MatchFixedString | Qt.MatchCaseSensitive) |
96 if len(items) == 0: |
105 if len(items) == 0: |
97 parent = QTreeWidgetItem(self.serversCertificatesTree, [organisation]) |
106 parent = QTreeWidgetItem( |
|
107 self.serversCertificatesTree, [organisation]) |
98 else: |
108 else: |
99 parent = items[0] |
109 parent = items[0] |
100 |
110 |
101 itm = QTreeWidgetItem(parent, [commonName, server, expiryDate]) |
111 itm = QTreeWidgetItem(parent, [commonName, server, expiryDate]) |
102 itm.setData(0, self.CertRole, cert.toPem()) |
112 itm.setData(0, self.CertRole, cert.toPem()) |
119 def on_serversViewButton_clicked(self): |
129 def on_serversViewButton_clicked(self): |
120 """ |
130 """ |
121 Private slot to show data of the selected server certificate. |
131 Private slot to show data of the selected server certificate. |
122 """ |
132 """ |
123 try: |
133 try: |
124 from E5Network.E5SslCertificatesInfoDialog import E5SslCertificatesInfoDialog |
134 from E5Network.E5SslCertificatesInfoDialog import \ |
|
135 E5SslCertificatesInfoDialog |
125 cert = QSslCertificate.fromData( |
136 cert = QSslCertificate.fromData( |
126 self.serversCertificatesTree.currentItem().data(0, self.CertRole)) |
137 self.serversCertificatesTree.currentItem().data( |
|
138 0, self.CertRole)) |
127 dlg = E5SslCertificatesInfoDialog(cert, self) |
139 dlg = E5SslCertificatesInfoDialog(cert, self) |
128 dlg.exec_() |
140 dlg.exec_() |
129 except ImportError: |
141 except ImportError: |
130 pass |
142 pass |
131 |
143 |
135 Private slot to delete the selected server certificate. |
147 Private slot to delete the selected server certificate. |
136 """ |
148 """ |
137 itm = self.serversCertificatesTree.currentItem() |
149 itm = self.serversCertificatesTree.currentItem() |
138 res = E5MessageBox.yesNo(self, |
150 res = E5MessageBox.yesNo(self, |
139 self.trUtf8("Delete Server Certificate"), |
151 self.trUtf8("Delete Server Certificate"), |
140 self.trUtf8("""<p>Shall the server certificate really be deleted?</p>""" |
152 self.trUtf8("""<p>Shall the server certificate really be""" |
141 """<p>{0}</p>""" |
153 """ deleted?</p><p>{0}</p>""" |
142 """<p>If the server certificate is deleted, the normal security""" |
154 """<p>If the server certificate is deleted, the""" |
143 """ checks will be reinstantiated and the server has to""" |
155 """ normal security checks will be reinstantiated""" |
144 """ present a valid certificate.</p>""")\ |
156 """ and the server has to present a valid""" |
|
157 """ certificate.</p>""")\ |
145 .format(itm.text(0))) |
158 .format(itm.text(0))) |
146 if res: |
159 if res: |
147 server = itm.text(1) |
160 server = itm.text(1) |
148 cert = self.serversCertificatesTree.currentItem().data(0, self.CertRole) |
161 cert = self.serversCertificatesTree.currentItem().data( |
149 |
162 0, self.CertRole) |
150 # delete the selected entry and its parent entry, if it was the only one |
163 |
|
164 # delete the selected entry and its parent entry, |
|
165 # if it was the only one |
151 parent = itm.parent() |
166 parent = itm.parent() |
152 parent.takeChild(parent.indexOfChild(itm)) |
167 parent.takeChild(parent.indexOfChild(itm)) |
153 if parent.childCount() == 0: |
168 if parent.childCount() == 0: |
154 self.serversCertificatesTree.takeTopLevelItem( |
169 self.serversCertificatesTree.takeTopLevelItem( |
155 self.serversCertificatesTree.indexOfTopLevelItem(parent)) |
170 self.serversCertificatesTree.indexOfTopLevelItem(parent)) |
194 if cert in sCerts: |
209 if cert in sCerts: |
195 if qVersion() >= "5.0.0": |
210 if qVersion() >= "5.0.0": |
196 commonStr = ", ".join( |
211 commonStr = ", ".join( |
197 cert.subjectInfo(QSslCertificate.CommonName)) |
212 cert.subjectInfo(QSslCertificate.CommonName)) |
198 else: |
213 else: |
199 commonStr = cert.subjectInfo(QSslCertificate.CommonName) |
214 commonStr = cert.subjectInfo( |
|
215 QSslCertificate.CommonName) |
200 E5MessageBox.warning(self, |
216 E5MessageBox.warning(self, |
201 self.trUtf8("Import Certificate"), |
217 self.trUtf8("Import Certificate"), |
202 self.trUtf8("""<p>The certificate <b>{0}</b> already exists.""" |
218 self.trUtf8( |
203 """ Skipping.</p>""") |
219 """<p>The certificate <b>{0}</b> already exists.""" |
|
220 """ Skipping.</p>""") |
204 .format(Utilities.decodeString(commonStr))) |
221 .format(Utilities.decodeString(commonStr))) |
205 else: |
222 else: |
206 pems.append(cert.toPem() + '\n') |
223 pems.append(cert.toPem() + '\n') |
207 if server not in certificateDict: |
224 if server not in certificateDict: |
208 certificateDict[server] = QByteArray() |
225 certificateDict[server] = QByteArray() |
218 @pyqtSlot() |
235 @pyqtSlot() |
219 def on_serversExportButton_clicked(self): |
236 def on_serversExportButton_clicked(self): |
220 """ |
237 """ |
221 Private slot to export the selected server certificate. |
238 Private slot to export the selected server certificate. |
222 """ |
239 """ |
223 cert = self.serversCertificatesTree.currentItem().data(0, self.CertRole) |
240 cert = self.serversCertificatesTree.currentItem().data( |
|
241 0, self.CertRole) |
224 fname = self.serversCertificatesTree.currentItem().text(0)\ |
242 fname = self.serversCertificatesTree.currentItem().text(0)\ |
225 .replace(" ", "").replace("\t", "") |
243 .replace(" ", "").replace("\t", "") |
226 self.__exportCertificate(fname, cert) |
244 self.__exportCertificate(fname, cert) |
227 |
245 |
228 def __updateDefaultConfiguration(self): |
246 def __updateDefaultConfiguration(self): |
316 def on_caViewButton_clicked(self): |
334 def on_caViewButton_clicked(self): |
317 """ |
335 """ |
318 Private slot to show data of the selected CA certificate. |
336 Private slot to show data of the selected CA certificate. |
319 """ |
337 """ |
320 try: |
338 try: |
321 from E5Network.E5SslCertificatesInfoDialog import E5SslCertificatesInfoDialog |
339 from E5Network.E5SslCertificatesInfoDialog import \ |
|
340 E5SslCertificatesInfoDialog |
322 cert = QSslCertificate.fromData( |
341 cert = QSslCertificate.fromData( |
323 self.caCertificatesTree.currentItem().data(0, self.CertRole)) |
342 self.caCertificatesTree.currentItem().data(0, self.CertRole)) |
324 dlg = E5SslCertificatesInfoDialog(cert, self) |
343 dlg = E5SslCertificatesInfoDialog(cert, self) |
325 dlg.exec_() |
344 dlg.exec_() |
326 except ImportError: |
345 except ImportError: |
332 Private slot to delete the selected CA certificate. |
351 Private slot to delete the selected CA certificate. |
333 """ |
352 """ |
334 itm = self.caCertificatesTree.currentItem() |
353 itm = self.caCertificatesTree.currentItem() |
335 res = E5MessageBox.yesNo(self, |
354 res = E5MessageBox.yesNo(self, |
336 self.trUtf8("Delete CA Certificate"), |
355 self.trUtf8("Delete CA Certificate"), |
337 self.trUtf8("""<p>Shall the CA certificate really be deleted?</p>""" |
356 self.trUtf8( |
338 """<p>{0}</p>""" |
357 """<p>Shall the CA certificate really be deleted?</p>""" |
339 """<p>If the CA certificate is deleted, the browser""" |
358 """<p>{0}</p>""" |
340 """ will not trust any certificate issued by this CA.</p>""")\ |
359 """<p>If the CA certificate is deleted, the browser""" |
|
360 """ will not trust any certificate issued by this CA.</p>""")\ |
341 .format(itm.text(0))) |
361 .format(itm.text(0))) |
342 if res: |
362 if res: |
343 cert = self.caCertificatesTree.currentItem().data(0, self.CertRole) |
363 cert = self.caCertificatesTree.currentItem().data(0, self.CertRole) |
344 |
364 |
345 # delete the selected entry and its parent entry, if it was the only one |
365 # delete the selected entry and its parent entry, |
|
366 # if it was the only one |
346 parent = itm.parent() |
367 parent = itm.parent() |
347 parent.takeChild(parent.indexOfChild(itm)) |
368 parent.takeChild(parent.indexOfChild(itm)) |
348 if parent.childCount() == 0: |
369 if parent.childCount() == 0: |
349 self.caCertificatesTree.takeTopLevelItem( |
370 self.caCertificatesTree.takeTopLevelItem( |
350 self.caCertificatesTree.indexOfTopLevelItem(parent)) |
371 self.caCertificatesTree.indexOfTopLevelItem(parent)) |
354 if cert in caCerts: |
375 if cert in caCerts: |
355 caCerts.remove(cert) |
376 caCerts.remove(cert) |
356 pems = QByteArray() |
377 pems = QByteArray() |
357 for cert in caCerts: |
378 for cert in caCerts: |
358 pems.append(cert.toPem() + '\n') |
379 pems.append(cert.toPem() + '\n') |
359 Preferences.Prefs.settings.setValue("Help/SystemCertificates", pems) |
380 Preferences.Prefs.settings.setValue( |
|
381 "Help/SystemCertificates", pems) |
360 |
382 |
361 # delete the certificate from the default certificates |
383 # delete the certificate from the default certificates |
362 self.__updateDefaultConfiguration() |
384 self.__updateDefaultConfiguration() |
363 |
385 |
364 @pyqtSlot() |
386 @pyqtSlot() |
373 if cert in caCerts: |
395 if cert in caCerts: |
374 if qVersion() >= "5.0.0": |
396 if qVersion() >= "5.0.0": |
375 commonStr = ", ".join( |
397 commonStr = ", ".join( |
376 cert.subjectInfo(QSslCertificate.CommonName)) |
398 cert.subjectInfo(QSslCertificate.CommonName)) |
377 else: |
399 else: |
378 commonStr = cert.subjectInfo(QSslCertificate.CommonName) |
400 commonStr = cert.subjectInfo( |
|
401 QSslCertificate.CommonName) |
379 E5MessageBox.warning(self, |
402 E5MessageBox.warning(self, |
380 self.trUtf8("Import Certificate"), |
403 self.trUtf8("Import Certificate"), |
381 self.trUtf8("""<p>The certificate <b>{0}</b> already exists.""" |
404 self.trUtf8( |
382 """ Skipping.</p>""") |
405 """<p>The certificate <b>{0}</b> already exists.""" |
|
406 """ Skipping.</p>""") |
383 .format(Utilities.decodeString(commonStr))) |
407 .format(Utilities.decodeString(commonStr))) |
384 else: |
408 else: |
385 caCerts.append(cert) |
409 caCerts.append(cert) |
386 |
410 |
387 pems = QByteArray() |
411 pems = QByteArray() |
388 for cert in caCerts: |
412 for cert in caCerts: |
389 pems.append(cert.toPem() + '\n') |
413 pems.append(cert.toPem() + '\n') |
390 Preferences.Prefs.settings.setValue("Help/SystemCertificates", pems) |
414 Preferences.Prefs.settings.setValue( |
|
415 "Help/SystemCertificates", pems) |
391 |
416 |
392 self.caCertificatesTree.clear() |
417 self.caCertificatesTree.clear() |
393 self.__populateCaCertificatesTree() |
418 self.__populateCaCertificatesTree() |
394 |
419 |
395 self.__updateDefaultConfiguration() |
420 self.__updateDefaultConfiguration() |
438 |
463 |
439 f = QFile(fname) |
464 f = QFile(fname) |
440 if not f.open(QIODevice.WriteOnly): |
465 if not f.open(QIODevice.WriteOnly): |
441 E5MessageBox.critical(self, |
466 E5MessageBox.critical(self, |
442 self.trUtf8("Export Certificate"), |
467 self.trUtf8("Export Certificate"), |
443 self.trUtf8("""<p>The certificate could not be written to file""" |
468 self.trUtf8( |
444 """ <b>{0}</b></p><p>Error: {1}</p>""") |
469 """<p>The certificate could not be written""" |
|
470 """ to file <b>{0}</b></p><p>Error: {1}</p>""") |
445 .format(fname, f.errorString())) |
471 .format(fname, f.errorString())) |
446 return |
472 return |
447 |
473 |
448 if fname.endswith(".pem"): |
474 if fname.endswith(".pem"): |
449 crt = cert.toPem() |
475 crt = cert.toPem() |
468 if fname: |
494 if fname: |
469 f = QFile(fname) |
495 f = QFile(fname) |
470 if not f.open(QIODevice.ReadOnly): |
496 if not f.open(QIODevice.ReadOnly): |
471 E5MessageBox.critical(self, |
497 E5MessageBox.critical(self, |
472 self.trUtf8("Export Certificate"), |
498 self.trUtf8("Export Certificate"), |
473 self.trUtf8("""<p>The certificate could not be read from file""" |
499 self.trUtf8( |
474 """ <b>{0}</b></p><p>Error: {1}</p>""") |
500 """<p>The certificate could not be read from file""" |
|
501 """ <b>{0}</b></p><p>Error: {1}</p>""") |
475 .format(fname, f.errorString())) |
502 .format(fname, f.errorString())) |
476 return [] |
503 return [] |
477 |
504 |
478 crt = f.readAll() |
505 crt = f.readAll() |
479 f.close() |
506 f.close() |