src/eric7/EricNetwork/EricSslCertificatesDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
10 import contextlib 10 import contextlib
11 import pathlib 11 import pathlib
12 12
13 from PyQt6.QtCore import pyqtSlot, Qt, QByteArray 13 from PyQt6.QtCore import pyqtSlot, Qt, QByteArray
14 from PyQt6.QtWidgets import QDialog, QTreeWidgetItem 14 from PyQt6.QtWidgets import QDialog, QTreeWidgetItem
15
15 with contextlib.suppress(ImportError): 16 with contextlib.suppress(ImportError):
16 from PyQt6.QtNetwork import QSslCertificate, QSslConfiguration, QSsl 17 from PyQt6.QtNetwork import QSslCertificate, QSslConfiguration, QSsl
17 18
18 from EricWidgets import EricMessageBox, EricFileDialog 19 from EricWidgets import EricMessageBox, EricFileDialog
19 20
27 28
28 class EricSslCertificatesDialog(QDialog, Ui_EricSslCertificatesDialog): 29 class EricSslCertificatesDialog(QDialog, Ui_EricSslCertificatesDialog):
29 """ 30 """
30 Class implementing a dialog to show and edit all certificates. 31 Class implementing a dialog to show and edit all certificates.
31 """ 32 """
33
32 CertRole = Qt.ItemDataRole.UserRole + 1 34 CertRole = Qt.ItemDataRole.UserRole + 1
33 35
34 def __init__(self, parent=None): 36 def __init__(self, parent=None):
35 """ 37 """
36 Constructor 38 Constructor
37 39
38 @param parent reference to the parent widget (QWidget) 40 @param parent reference to the parent widget (QWidget)
39 """ 41 """
40 super().__init__(parent) 42 super().__init__(parent)
41 self.setupUi(self) 43 self.setupUi(self)
42 44
43 self.serversViewButton.setIcon( 45 self.serversViewButton.setIcon(UI.PixmapCache.getIcon("certificates"))
44 UI.PixmapCache.getIcon("certificates")) 46 self.serversDeleteButton.setIcon(UI.PixmapCache.getIcon("certificateDelete"))
45 self.serversDeleteButton.setIcon( 47 self.serversExportButton.setIcon(UI.PixmapCache.getIcon("certificateExport"))
46 UI.PixmapCache.getIcon("certificateDelete")) 48 self.serversImportButton.setIcon(UI.PixmapCache.getIcon("certificateImport"))
47 self.serversExportButton.setIcon( 49
48 UI.PixmapCache.getIcon("certificateExport")) 50 self.caViewButton.setIcon(UI.PixmapCache.getIcon("certificates"))
49 self.serversImportButton.setIcon( 51 self.caDeleteButton.setIcon(UI.PixmapCache.getIcon("certificateDelete"))
50 UI.PixmapCache.getIcon("certificateImport")) 52 self.caExportButton.setIcon(UI.PixmapCache.getIcon("certificateExport"))
51 53 self.caImportButton.setIcon(UI.PixmapCache.getIcon("certificateImport"))
52 self.caViewButton.setIcon( 54
53 UI.PixmapCache.getIcon("certificates"))
54 self.caDeleteButton.setIcon(
55 UI.PixmapCache.getIcon("certificateDelete"))
56 self.caExportButton.setIcon(
57 UI.PixmapCache.getIcon("certificateExport"))
58 self.caImportButton.setIcon(
59 UI.PixmapCache.getIcon("certificateImport"))
60
61 self.__populateServerCertificatesTree() 55 self.__populateServerCertificatesTree()
62 self.__populateCaCertificatesTree() 56 self.__populateCaCertificatesTree()
63 57
64 def __populateServerCertificatesTree(self): 58 def __populateServerCertificatesTree(self):
65 """ 59 """
66 Private slot to populate the server certificates tree. 60 Private slot to populate the server certificates tree.
67 """ 61 """
68 certificateDict = Globals.toDict( 62 certificateDict = Globals.toDict(
69 Preferences.getSettings().value("Ssl/CaCertificatesDict")) 63 Preferences.getSettings().value("Ssl/CaCertificatesDict")
64 )
70 for server in certificateDict: 65 for server in certificateDict:
71 for cert in QSslCertificate.fromData(certificateDict[server]): 66 for cert in QSslCertificate.fromData(certificateDict[server]):
72 self.__createServerCertificateEntry(server, cert) 67 self.__createServerCertificateEntry(server, cert)
73 68
74 self.serversCertificatesTree.expandAll() 69 self.serversCertificatesTree.expandAll()
75 for i in range(self.serversCertificatesTree.columnCount()): 70 for i in range(self.serversCertificatesTree.columnCount()):
76 self.serversCertificatesTree.resizeColumnToContents(i) 71 self.serversCertificatesTree.resizeColumnToContents(i)
77 72
78 def __createServerCertificateEntry(self, server, cert): 73 def __createServerCertificateEntry(self, server, cert):
79 """ 74 """
80 Private method to create a server certificate entry. 75 Private method to create a server certificate entry.
81 76
82 @param server server name of the certificate (string) 77 @param server server name of the certificate (string)
83 @param cert certificate to insert (QSslCertificate) 78 @param cert certificate to insert (QSslCertificate)
84 """ 79 """
85 # step 1: extract the info to be shown 80 # step 1: extract the info to be shown
86 organisation = Utilities.decodeString( 81 organisation = Utilities.decodeString(
87 ", ".join(cert.subjectInfo( 82 ", ".join(cert.subjectInfo(QSslCertificate.SubjectInfo.Organization))
88 QSslCertificate.SubjectInfo.Organization))) 83 )
89 commonName = Utilities.decodeString( 84 commonName = Utilities.decodeString(
90 ", ".join(cert.subjectInfo( 85 ", ".join(cert.subjectInfo(QSslCertificate.SubjectInfo.CommonName))
91 QSslCertificate.SubjectInfo.CommonName))) 86 )
92 if organisation is None or organisation == "": 87 if organisation is None or organisation == "":
93 organisation = self.tr("(Unknown)") 88 organisation = self.tr("(Unknown)")
94 if commonName is None or commonName == "": 89 if commonName is None or commonName == "":
95 commonName = self.tr("(Unknown common name)") 90 commonName = self.tr("(Unknown common name)")
96 expiryDate = cert.expiryDate().toString("yyyy-MM-dd") 91 expiryDate = cert.expiryDate().toString("yyyy-MM-dd")
97 92
98 # step 2: create the entry 93 # step 2: create the entry
99 items = self.serversCertificatesTree.findItems( 94 items = self.serversCertificatesTree.findItems(
100 organisation, 95 organisation,
101 Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive) 96 Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive,
97 )
102 if len(items) == 0: 98 if len(items) == 0:
103 parent = QTreeWidgetItem( 99 parent = QTreeWidgetItem(self.serversCertificatesTree, [organisation])
104 self.serversCertificatesTree, [organisation])
105 parent.setFirstColumnSpanned(True) 100 parent.setFirstColumnSpanned(True)
106 else: 101 else:
107 parent = items[0] 102 parent = items[0]
108 103
109 itm = QTreeWidgetItem(parent, [commonName, server, expiryDate]) 104 itm = QTreeWidgetItem(parent, [commonName, server, expiryDate])
110 itm.setData(0, self.CertRole, cert.toPem()) 105 itm.setData(0, self.CertRole, cert.toPem())
111 106
112 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) 107 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
113 def on_serversCertificatesTree_currentItemChanged(self, current, previous): 108 def on_serversCertificatesTree_currentItemChanged(self, current, previous):
114 """ 109 """
115 Private slot handling a change of the current item in the 110 Private slot handling a change of the current item in the
116 server certificates list. 111 server certificates list.
117 112
118 @param current new current item (QTreeWidgetItem) 113 @param current new current item (QTreeWidgetItem)
119 @param previous previous current item (QTreeWidgetItem) 114 @param previous previous current item (QTreeWidgetItem)
120 """ 115 """
121 enable = current is not None and current.parent() is not None 116 enable = current is not None and current.parent() is not None
122 self.serversViewButton.setEnabled(enable) 117 self.serversViewButton.setEnabled(enable)
123 self.serversDeleteButton.setEnabled(enable) 118 self.serversDeleteButton.setEnabled(enable)
124 self.serversExportButton.setEnabled(enable) 119 self.serversExportButton.setEnabled(enable)
125 120
126 @pyqtSlot() 121 @pyqtSlot()
127 def on_serversViewButton_clicked(self): 122 def on_serversViewButton_clicked(self):
128 """ 123 """
129 Private slot to show data of the selected server certificate. 124 Private slot to show data of the selected server certificate.
130 """ 125 """
131 with contextlib.suppress(ImportError): 126 with contextlib.suppress(ImportError):
132 from EricNetwork.EricSslCertificatesInfoDialog import ( 127 from EricNetwork.EricSslCertificatesInfoDialog import (
133 EricSslCertificatesInfoDialog 128 EricSslCertificatesInfoDialog,
134 ) 129 )
130
135 cert = QSslCertificate.fromData( 131 cert = QSslCertificate.fromData(
136 self.serversCertificatesTree.currentItem().data( 132 self.serversCertificatesTree.currentItem().data(0, self.CertRole)
137 0, self.CertRole)) 133 )
138 dlg = EricSslCertificatesInfoDialog(cert, self) 134 dlg = EricSslCertificatesInfoDialog(cert, self)
139 dlg.exec() 135 dlg.exec()
140 136
141 @pyqtSlot() 137 @pyqtSlot()
142 def on_serversDeleteButton_clicked(self): 138 def on_serversDeleteButton_clicked(self):
143 """ 139 """
144 Private slot to delete the selected server certificate. 140 Private slot to delete the selected server certificate.
145 """ 141 """
146 itm = self.serversCertificatesTree.currentItem() 142 itm = self.serversCertificatesTree.currentItem()
147 res = EricMessageBox.yesNo( 143 res = EricMessageBox.yesNo(
148 self, 144 self,
149 self.tr("Delete Server Certificate"), 145 self.tr("Delete Server Certificate"),
150 self.tr("""<p>Shall the server certificate really be""" 146 self.tr(
151 """ deleted?</p><p>{0}</p>""" 147 """<p>Shall the server certificate really be"""
152 """<p>If the server certificate is deleted, the""" 148 """ deleted?</p><p>{0}</p>"""
153 """ normal security checks will be reinstantiated""" 149 """<p>If the server certificate is deleted, the"""
154 """ and the server has to present a valid""" 150 """ normal security checks will be reinstantiated"""
155 """ certificate.</p>""") 151 """ and the server has to present a valid"""
156 .format(itm.text(0))) 152 """ certificate.</p>"""
153 ).format(itm.text(0)),
154 )
157 if res: 155 if res:
158 server = itm.text(1) 156 server = itm.text(1)
159 cert = self.serversCertificatesTree.currentItem().data( 157 cert = self.serversCertificatesTree.currentItem().data(0, self.CertRole)
160 0, self.CertRole) 158
161
162 # delete the selected entry and its parent entry, 159 # delete the selected entry and its parent entry,
163 # if it was the only one 160 # if it was the only one
164 parent = itm.parent() 161 parent = itm.parent()
165 parent.takeChild(parent.indexOfChild(itm)) 162 parent.takeChild(parent.indexOfChild(itm))
166 if parent.childCount() == 0: 163 if parent.childCount() == 0:
167 self.serversCertificatesTree.takeTopLevelItem( 164 self.serversCertificatesTree.takeTopLevelItem(
168 self.serversCertificatesTree.indexOfTopLevelItem(parent)) 165 self.serversCertificatesTree.indexOfTopLevelItem(parent)
169 166 )
167
170 # delete the certificate from the user certificate store 168 # delete the certificate from the user certificate store
171 certificateDict = Globals.toDict( 169 certificateDict = Globals.toDict(
172 Preferences.getSettings().value("Ssl/CaCertificatesDict")) 170 Preferences.getSettings().value("Ssl/CaCertificatesDict")
171 )
173 if server in certificateDict: 172 if server in certificateDict:
174 certs = [c.toPem() for c in 173 certs = [
175 QSslCertificate.fromData(certificateDict[server])] 174 c.toPem() for c in QSslCertificate.fromData(certificateDict[server])
175 ]
176 if cert in certs: 176 if cert in certs:
177 certs.remove(cert) 177 certs.remove(cert)
178 if certs: 178 if certs:
179 pems = QByteArray() 179 pems = QByteArray()
180 for cert in certs: 180 for cert in certs:
181 pems.append(cert + b'\n') 181 pems.append(cert + b"\n")
182 certificateDict[server] = pems 182 certificateDict[server] = pems
183 else: 183 else:
184 del certificateDict[server] 184 del certificateDict[server]
185 Preferences.getSettings().setValue( 185 Preferences.getSettings().setValue(
186 "Ssl/CaCertificatesDict", 186 "Ssl/CaCertificatesDict", certificateDict
187 certificateDict) 187 )
188 188
189 # delete the certificate from the default certificates 189 # delete the certificate from the default certificates
190 self.__updateDefaultConfiguration() 190 self.__updateDefaultConfiguration()
191 191
192 @pyqtSlot() 192 @pyqtSlot()
193 def on_serversImportButton_clicked(self): 193 def on_serversImportButton_clicked(self):
194 """ 194 """
195 Private slot to import server certificates. 195 Private slot to import server certificates.
196 """ 196 """
197 certs = self.__importCertificate() 197 certs = self.__importCertificate()
198 if certs: 198 if certs:
199 server = "*" 199 server = "*"
200 certificateDict = Globals.toDict( 200 certificateDict = Globals.toDict(
201 Preferences.getSettings().value("Ssl/CaCertificatesDict")) 201 Preferences.getSettings().value("Ssl/CaCertificatesDict")
202 )
202 if server in certificateDict: 203 if server in certificateDict:
203 sCerts = QSslCertificate.fromData(certificateDict[server]) 204 sCerts = QSslCertificate.fromData(certificateDict[server])
204 else: 205 else:
205 sCerts = [] 206 sCerts = []
206 207
207 pems = QByteArray() 208 pems = QByteArray()
208 for cert in certs: 209 for cert in certs:
209 if cert in sCerts: 210 if cert in sCerts:
210 commonStr = ", ".join( 211 commonStr = ", ".join(
211 cert.subjectInfo( 212 cert.subjectInfo(QSslCertificate.SubjectInfo.CommonName)
212 QSslCertificate.SubjectInfo.CommonName)) 213 )
213 EricMessageBox.warning( 214 EricMessageBox.warning(
214 self, 215 self,
215 self.tr("Import Certificate"), 216 self.tr("Import Certificate"),
216 self.tr( 217 self.tr(
217 """<p>The certificate <b>{0}</b> already exists.""" 218 """<p>The certificate <b>{0}</b> already exists."""
218 """ Skipping.</p>""") 219 """ Skipping.</p>"""
219 .format(Utilities.decodeString(commonStr))) 220 ).format(Utilities.decodeString(commonStr)),
221 )
220 else: 222 else:
221 pems.append(cert.toPem() + b'\n') 223 pems.append(cert.toPem() + b"\n")
222 if server not in certificateDict: 224 if server not in certificateDict:
223 certificateDict[server] = QByteArray() 225 certificateDict[server] = QByteArray()
224 certificateDict[server].append(pems) 226 certificateDict[server].append(pems)
225 Preferences.getSettings().setValue( 227 Preferences.getSettings().setValue(
226 "Ssl/CaCertificatesDict", 228 "Ssl/CaCertificatesDict", certificateDict
227 certificateDict) 229 )
228 230
229 self.serversCertificatesTree.clear() 231 self.serversCertificatesTree.clear()
230 self.__populateServerCertificatesTree() 232 self.__populateServerCertificatesTree()
231 233
232 self.__updateDefaultConfiguration() 234 self.__updateDefaultConfiguration()
233 235
234 @pyqtSlot() 236 @pyqtSlot()
235 def on_serversExportButton_clicked(self): 237 def on_serversExportButton_clicked(self):
236 """ 238 """
237 Private slot to export the selected server certificate. 239 Private slot to export the selected server certificate.
238 """ 240 """
239 cert = self.serversCertificatesTree.currentItem().data( 241 cert = self.serversCertificatesTree.currentItem().data(0, self.CertRole)
240 0, self.CertRole)
241 fname = ( 242 fname = (
242 self.serversCertificatesTree.currentItem().text(0).replace(" ", "") 243 self.serversCertificatesTree.currentItem()
244 .text(0)
245 .replace(" ", "")
243 .replace("\t", "") 246 .replace("\t", "")
244 ) 247 )
245 self.__exportCertificate(fname, cert) 248 self.__exportCertificate(fname, cert)
246 249
247 def __updateDefaultConfiguration(self): 250 def __updateDefaultConfiguration(self):
248 """ 251 """
249 Private method to update the default SSL configuration. 252 Private method to update the default SSL configuration.
250 """ 253 """
251 caList = self.__getSystemCaCertificates() 254 caList = self.__getSystemCaCertificates()
252 certificateDict = Globals.toDict( 255 certificateDict = Globals.toDict(
253 Preferences.getSettings().value("Ssl/CaCertificatesDict")) 256 Preferences.getSettings().value("Ssl/CaCertificatesDict")
257 )
254 for server in certificateDict: 258 for server in certificateDict:
255 for cert in QSslCertificate.fromData(certificateDict[server]): 259 for cert in QSslCertificate.fromData(certificateDict[server]):
256 if cert not in caList: 260 if cert not in caList:
257 caList.append(cert) 261 caList.append(cert)
258 sslCfg = QSslConfiguration.defaultConfiguration() 262 sslCfg = QSslConfiguration.defaultConfiguration()
259 sslCfg.setCaCertificates(caList) 263 sslCfg.setCaCertificates(caList)
260 QSslConfiguration.setDefaultConfiguration(sslCfg) 264 QSslConfiguration.setDefaultConfiguration(sslCfg)
261 265
262 def __getSystemCaCertificates(self): 266 def __getSystemCaCertificates(self):
263 """ 267 """
264 Private method to get the list of system certificates. 268 Private method to get the list of system certificates.
265 269
266 @return list of system certificates (list of QSslCertificate) 270 @return list of system certificates (list of QSslCertificate)
267 """ 271 """
268 caList = QSslCertificate.fromData(Globals.toByteArray( 272 caList = QSslCertificate.fromData(
269 Preferences.getSettings().value("Help/SystemCertificates"))) 273 Globals.toByteArray(
274 Preferences.getSettings().value("Help/SystemCertificates")
275 )
276 )
270 if not caList: 277 if not caList:
271 caList = QSslConfiguration.systemCaCertificates() 278 caList = QSslConfiguration.systemCaCertificates()
272 return caList 279 return caList
273 280
274 def __populateCaCertificatesTree(self): 281 def __populateCaCertificatesTree(self):
275 """ 282 """
276 Private slot to populate the CA certificates tree. 283 Private slot to populate the CA certificates tree.
277 """ 284 """
278 for cert in self.__getSystemCaCertificates(): 285 for cert in self.__getSystemCaCertificates():
279 self.__createCaCertificateEntry(cert) 286 self.__createCaCertificateEntry(cert)
280 287
281 self.caCertificatesTree.expandAll() 288 self.caCertificatesTree.expandAll()
282 for i in range(self.caCertificatesTree.columnCount()): 289 for i in range(self.caCertificatesTree.columnCount()):
283 self.caCertificatesTree.resizeColumnToContents(i) 290 self.caCertificatesTree.resizeColumnToContents(i)
284 self.caCertificatesTree.sortItems(0, Qt.SortOrder.AscendingOrder) 291 self.caCertificatesTree.sortItems(0, Qt.SortOrder.AscendingOrder)
285 292
286 def __createCaCertificateEntry(self, cert): 293 def __createCaCertificateEntry(self, cert):
287 """ 294 """
288 Private method to create a CA certificate entry. 295 Private method to create a CA certificate entry.
289 296
290 @param cert certificate to insert (QSslCertificate) 297 @param cert certificate to insert (QSslCertificate)
291 """ 298 """
292 # step 1: extract the info to be shown 299 # step 1: extract the info to be shown
293 organisation = Utilities.decodeString( 300 organisation = Utilities.decodeString(
294 ", ".join(cert.subjectInfo( 301 ", ".join(cert.subjectInfo(QSslCertificate.SubjectInfo.Organization))
295 QSslCertificate.SubjectInfo.Organization))) 302 )
296 commonName = Utilities.decodeString( 303 commonName = Utilities.decodeString(
297 ", ".join(cert.subjectInfo( 304 ", ".join(cert.subjectInfo(QSslCertificate.SubjectInfo.CommonName))
298 QSslCertificate.SubjectInfo.CommonName))) 305 )
299 if organisation is None or organisation == "": 306 if organisation is None or organisation == "":
300 organisation = self.tr("(Unknown)") 307 organisation = self.tr("(Unknown)")
301 if commonName is None or commonName == "": 308 if commonName is None or commonName == "":
302 commonName = self.tr("(Unknown common name)") 309 commonName = self.tr("(Unknown common name)")
303 expiryDate = cert.expiryDate().toString("yyyy-MM-dd") 310 expiryDate = cert.expiryDate().toString("yyyy-MM-dd")
304 311
305 # step 2: create the entry 312 # step 2: create the entry
306 items = self.caCertificatesTree.findItems( 313 items = self.caCertificatesTree.findItems(
307 organisation, 314 organisation,
308 Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive) 315 Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive,
316 )
309 if len(items) == 0: 317 if len(items) == 0:
310 parent = QTreeWidgetItem(self.caCertificatesTree, [organisation]) 318 parent = QTreeWidgetItem(self.caCertificatesTree, [organisation])
311 parent.setFirstColumnSpanned(True) 319 parent.setFirstColumnSpanned(True)
312 else: 320 else:
313 parent = items[0] 321 parent = items[0]
314 322
315 itm = QTreeWidgetItem(parent, [commonName, expiryDate]) 323 itm = QTreeWidgetItem(parent, [commonName, expiryDate])
316 itm.setData(0, self.CertRole, cert.toPem()) 324 itm.setData(0, self.CertRole, cert.toPem())
317 325
318 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) 326 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
319 def on_caCertificatesTree_currentItemChanged(self, current, previous): 327 def on_caCertificatesTree_currentItemChanged(self, current, previous):
320 """ 328 """
321 Private slot handling a change of the current item 329 Private slot handling a change of the current item
322 in the CA certificates list. 330 in the CA certificates list.
323 331
324 @param current new current item (QTreeWidgetItem) 332 @param current new current item (QTreeWidgetItem)
325 @param previous previous current item (QTreeWidgetItem) 333 @param previous previous current item (QTreeWidgetItem)
326 """ 334 """
327 enable = current is not None and current.parent() is not None 335 enable = current is not None and current.parent() is not None
328 self.caViewButton.setEnabled(enable) 336 self.caViewButton.setEnabled(enable)
329 self.caDeleteButton.setEnabled(enable) 337 self.caDeleteButton.setEnabled(enable)
330 self.caExportButton.setEnabled(enable) 338 self.caExportButton.setEnabled(enable)
331 339
332 @pyqtSlot() 340 @pyqtSlot()
333 def on_caViewButton_clicked(self): 341 def on_caViewButton_clicked(self):
334 """ 342 """
335 Private slot to show data of the selected CA certificate. 343 Private slot to show data of the selected CA certificate.
336 """ 344 """
337 with contextlib.suppress(ImportError): 345 with contextlib.suppress(ImportError):
338 from EricNetwork.EricSslCertificatesInfoDialog import ( 346 from EricNetwork.EricSslCertificatesInfoDialog import (
339 EricSslCertificatesInfoDialog 347 EricSslCertificatesInfoDialog,
340 ) 348 )
349
341 cert = QSslCertificate.fromData( 350 cert = QSslCertificate.fromData(
342 self.caCertificatesTree.currentItem().data(0, self.CertRole)) 351 self.caCertificatesTree.currentItem().data(0, self.CertRole)
352 )
343 dlg = EricSslCertificatesInfoDialog(cert, self) 353 dlg = EricSslCertificatesInfoDialog(cert, self)
344 dlg.exec() 354 dlg.exec()
345 355
346 @pyqtSlot() 356 @pyqtSlot()
347 def on_caDeleteButton_clicked(self): 357 def on_caDeleteButton_clicked(self):
348 """ 358 """
349 Private slot to delete the selected CA certificate. 359 Private slot to delete the selected CA certificate.
350 """ 360 """
354 self.tr("Delete CA Certificate"), 364 self.tr("Delete CA Certificate"),
355 self.tr( 365 self.tr(
356 """<p>Shall the CA certificate really be deleted?</p>""" 366 """<p>Shall the CA certificate really be deleted?</p>"""
357 """<p>{0}</p>""" 367 """<p>{0}</p>"""
358 """<p>If the CA certificate is deleted, the browser""" 368 """<p>If the CA certificate is deleted, the browser"""
359 """ will not trust any certificate issued by this CA.</p>""") 369 """ will not trust any certificate issued by this CA.</p>"""
360 .format(itm.text(0))) 370 ).format(itm.text(0)),
371 )
361 if res: 372 if res:
362 cert = self.caCertificatesTree.currentItem().data(0, self.CertRole) 373 cert = self.caCertificatesTree.currentItem().data(0, self.CertRole)
363 374
364 # delete the selected entry and its parent entry, 375 # delete the selected entry and its parent entry,
365 # if it was the only one 376 # if it was the only one
366 parent = itm.parent() 377 parent = itm.parent()
367 parent.takeChild(parent.indexOfChild(itm)) 378 parent.takeChild(parent.indexOfChild(itm))
368 if parent.childCount() == 0: 379 if parent.childCount() == 0:
369 self.caCertificatesTree.takeTopLevelItem( 380 self.caCertificatesTree.takeTopLevelItem(
370 self.caCertificatesTree.indexOfTopLevelItem(parent)) 381 self.caCertificatesTree.indexOfTopLevelItem(parent)
371 382 )
383
372 # delete the certificate from the CA certificate store 384 # delete the certificate from the CA certificate store
373 caCerts = self.__getSystemCaCertificates() 385 caCerts = self.__getSystemCaCertificates()
374 if cert in caCerts: 386 if cert in caCerts:
375 caCerts.remove(cert) 387 caCerts.remove(cert)
376 pems = QByteArray() 388 pems = QByteArray()
377 for cert in caCerts: 389 for cert in caCerts:
378 pems.append(cert.toPem() + '\n') 390 pems.append(cert.toPem() + "\n")
379 Preferences.getSettings().setValue( 391 Preferences.getSettings().setValue("Help/SystemCertificates", pems)
380 "Help/SystemCertificates", pems) 392
381
382 # delete the certificate from the default certificates 393 # delete the certificate from the default certificates
383 self.__updateDefaultConfiguration() 394 self.__updateDefaultConfiguration()
384 395
385 @pyqtSlot() 396 @pyqtSlot()
386 def on_caImportButton_clicked(self): 397 def on_caImportButton_clicked(self):
387 """ 398 """
388 Private slot to import server certificates. 399 Private slot to import server certificates.
389 """ 400 """
391 if certs: 402 if certs:
392 caCerts = self.__getSystemCaCertificates() 403 caCerts = self.__getSystemCaCertificates()
393 for cert in certs: 404 for cert in certs:
394 if cert in caCerts: 405 if cert in caCerts:
395 commonStr = ", ".join( 406 commonStr = ", ".join(
396 cert.subjectInfo( 407 cert.subjectInfo(QSslCertificate.SubjectInfo.CommonName)
397 QSslCertificate.SubjectInfo.CommonName)) 408 )
398 EricMessageBox.warning( 409 EricMessageBox.warning(
399 self, 410 self,
400 self.tr("Import Certificate"), 411 self.tr("Import Certificate"),
401 self.tr( 412 self.tr(
402 """<p>The certificate <b>{0}</b> already exists.""" 413 """<p>The certificate <b>{0}</b> already exists."""
403 """ Skipping.</p>""") 414 """ Skipping.</p>"""
404 .format(Utilities.decodeString(commonStr))) 415 ).format(Utilities.decodeString(commonStr)),
416 )
405 else: 417 else:
406 caCerts.append(cert) 418 caCerts.append(cert)
407 419
408 pems = QByteArray() 420 pems = QByteArray()
409 for cert in caCerts: 421 for cert in caCerts:
410 pems.append(cert.toPem() + '\n') 422 pems.append(cert.toPem() + "\n")
411 Preferences.getSettings().setValue( 423 Preferences.getSettings().setValue("Help/SystemCertificates", pems)
412 "Help/SystemCertificates", pems) 424
413
414 self.caCertificatesTree.clear() 425 self.caCertificatesTree.clear()
415 self.__populateCaCertificatesTree() 426 self.__populateCaCertificatesTree()
416 427
417 self.__updateDefaultConfiguration() 428 self.__updateDefaultConfiguration()
418 429
419 @pyqtSlot() 430 @pyqtSlot()
420 def on_caExportButton_clicked(self): 431 def on_caExportButton_clicked(self):
421 """ 432 """
422 Private slot to export the selected CA certificate. 433 Private slot to export the selected CA certificate.
423 """ 434 """
424 cert = self.caCertificatesTree.currentItem().data(0, self.CertRole) 435 cert = self.caCertificatesTree.currentItem().data(0, self.CertRole)
425 fname = ( 436 fname = (
426 self.caCertificatesTree.currentItem().text(0).replace(" ", "") 437 self.caCertificatesTree.currentItem()
438 .text(0)
439 .replace(" ", "")
427 .replace("\t", "") 440 .replace("\t", "")
428 ) 441 )
429 self.__exportCertificate(fname, cert) 442 self.__exportCertificate(fname, cert)
430 443
431 def __exportCertificate(self, name, cert): 444 def __exportCertificate(self, name, cert):
432 """ 445 """
433 Private slot to export a certificate. 446 Private slot to export a certificate.
434 447
435 @param name default file name without extension 448 @param name default file name without extension
436 @type str 449 @type str
437 @param cert certificate to be exported encoded as PEM 450 @param cert certificate to be exported encoded as PEM
438 @type QByteArray 451 @type QByteArray
439 """ 452 """
440 if cert is not None: 453 if cert is not None:
441 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( 454 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
442 self, 455 self,
443 self.tr("Export Certificate"), 456 self.tr("Export Certificate"),
444 name, 457 name,
445 self.tr("Certificate File (PEM) (*.pem);;" 458 self.tr(
446 "Certificate File (DER) (*.der)"), 459 "Certificate File (PEM) (*.pem);;" "Certificate File (DER) (*.der)"
460 ),
447 None, 461 None,
448 EricFileDialog.DontConfirmOverwrite) 462 EricFileDialog.DontConfirmOverwrite,
449 463 )
464
450 if fname: 465 if fname:
451 fpath = pathlib.Path(fname) 466 fpath = pathlib.Path(fname)
452 if not fpath.suffix: 467 if not fpath.suffix:
453 ex = selectedFilter.split("(*")[1].split(")")[0] 468 ex = selectedFilter.split("(*")[1].split(")")[0]
454 if ex: 469 if ex:
455 fpath = fpath.with_suffix(ex) 470 fpath = fpath.with_suffix(ex)
456 if fpath.exists(): 471 if fpath.exists():
457 res = EricMessageBox.yesNo( 472 res = EricMessageBox.yesNo(
458 self, 473 self,
459 self.tr("Export Certificate"), 474 self.tr("Export Certificate"),
460 self.tr("<p>The file <b>{0}</b> already exists." 475 self.tr(
461 " Overwrite it?</p>").format(fname), 476 "<p>The file <b>{0}</b> already exists."
462 icon=EricMessageBox.Warning) 477 " Overwrite it?</p>"
478 ).format(fname),
479 icon=EricMessageBox.Warning,
480 )
463 if not res: 481 if not res:
464 return 482 return
465 483
466 if fpath.suffix == ".pem": 484 if fpath.suffix == ".pem":
467 crt = bytes(cert) 485 crt = bytes(cert)
468 else: 486 else:
469 crt = bytes( 487 crt = bytes(
470 QSslCertificate.fromData( 488 QSslCertificate.fromData(crt, QSsl.EncodingFormat.Pem)[
471 crt, QSsl.EncodingFormat.Pem)[0].toDer() 489 0
490 ].toDer()
472 ) 491 )
473 try: 492 try:
474 with fpath.open("wb") as f: 493 with fpath.open("wb") as f:
475 f.write(crt) 494 f.write(crt)
476 except OSError as err: 495 except OSError as err:
477 EricMessageBox.critical( 496 EricMessageBox.critical(
478 self, 497 self,
479 self.tr("Export Certificate"), 498 self.tr("Export Certificate"),
480 self.tr( 499 self.tr(
481 """<p>The certificate could not be written""" 500 """<p>The certificate could not be written"""
482 """ to file <b>{0}</b></p><p>Error: {1}</p>""") 501 """ to file <b>{0}</b></p><p>Error: {1}</p>"""
483 .format(fpath, str(err))) 502 ).format(fpath, str(err)),
484 503 )
504
485 def __importCertificate(self): 505 def __importCertificate(self):
486 """ 506 """
487 Private method to read a certificate. 507 Private method to read a certificate.
488 508
489 @return certificates read 509 @return certificates read
490 @rtype list of QSslCertificate 510 @rtype list of QSslCertificate
491 """ 511 """
492 fname = EricFileDialog.getOpenFileName( 512 fname = EricFileDialog.getOpenFileName(
493 self, 513 self,
494 self.tr("Import Certificate"), 514 self.tr("Import Certificate"),
495 "", 515 "",
496 self.tr("Certificate Files (*.pem *.crt *.der *.cer *.ca);;" 516 self.tr(
497 "All Files (*)")) 517 "Certificate Files (*.pem *.crt *.der *.cer *.ca);;" "All Files (*)"
498 518 ),
519 )
520
499 if fname: 521 if fname:
500 try: 522 try:
501 with pathlib.Path(fname).open("rb") as f: 523 with pathlib.Path(fname).open("rb") as f:
502 crt = QByteArray(f.read()) 524 crt = QByteArray(f.read())
503 cert = QSslCertificate.fromData( 525 cert = QSslCertificate.fromData(crt, QSsl.EncodingFormat.Pem)
504 crt, QSsl.EncodingFormat.Pem)
505 if not cert: 526 if not cert:
506 cert = QSslCertificate.fromData( 527 cert = QSslCertificate.fromData(crt, QSsl.EncodingFormat.Der)
507 crt, QSsl.EncodingFormat.Der) 528
508
509 return cert 529 return cert
510 except OSError as err: 530 except OSError as err:
511 EricMessageBox.critical( 531 EricMessageBox.critical(
512 self, 532 self,
513 self.tr("Import Certificate"), 533 self.tr("Import Certificate"),
514 self.tr( 534 self.tr(
515 """<p>The certificate could not be read from file""" 535 """<p>The certificate could not be read from file"""
516 """ <b>{0}</b></p><p>Error: {1}</p>""") 536 """ <b>{0}</b></p><p>Error: {1}</p>"""
517 .format(fname, str(err))) 537 ).format(fname, str(err)),
518 538 )
539
519 return [] 540 return []

eric ide

mercurial