src/eric7/EricNetwork/EricSslCertificatesDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
--- a/src/eric7/EricNetwork/EricSslCertificatesDialog.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/EricNetwork/EricSslCertificatesDialog.py	Wed Jul 13 14:55:47 2022 +0200
@@ -12,6 +12,7 @@
 
 from PyQt6.QtCore import pyqtSlot, Qt, QByteArray
 from PyQt6.QtWidgets import QDialog, QTreeWidgetItem
+
 with contextlib.suppress(ImportError):
     from PyQt6.QtNetwork import QSslCertificate, QSslConfiguration, QSsl
 
@@ -29,92 +30,86 @@
     """
     Class implementing a dialog to show and edit all certificates.
     """
+
     CertRole = Qt.ItemDataRole.UserRole + 1
-    
+
     def __init__(self, parent=None):
         """
         Constructor
-        
+
         @param parent reference to the parent widget (QWidget)
         """
         super().__init__(parent)
         self.setupUi(self)
-        
-        self.serversViewButton.setIcon(
-            UI.PixmapCache.getIcon("certificates"))
-        self.serversDeleteButton.setIcon(
-            UI.PixmapCache.getIcon("certificateDelete"))
-        self.serversExportButton.setIcon(
-            UI.PixmapCache.getIcon("certificateExport"))
-        self.serversImportButton.setIcon(
-            UI.PixmapCache.getIcon("certificateImport"))
-        
-        self.caViewButton.setIcon(
-            UI.PixmapCache.getIcon("certificates"))
-        self.caDeleteButton.setIcon(
-            UI.PixmapCache.getIcon("certificateDelete"))
-        self.caExportButton.setIcon(
-            UI.PixmapCache.getIcon("certificateExport"))
-        self.caImportButton.setIcon(
-            UI.PixmapCache.getIcon("certificateImport"))
-        
+
+        self.serversViewButton.setIcon(UI.PixmapCache.getIcon("certificates"))
+        self.serversDeleteButton.setIcon(UI.PixmapCache.getIcon("certificateDelete"))
+        self.serversExportButton.setIcon(UI.PixmapCache.getIcon("certificateExport"))
+        self.serversImportButton.setIcon(UI.PixmapCache.getIcon("certificateImport"))
+
+        self.caViewButton.setIcon(UI.PixmapCache.getIcon("certificates"))
+        self.caDeleteButton.setIcon(UI.PixmapCache.getIcon("certificateDelete"))
+        self.caExportButton.setIcon(UI.PixmapCache.getIcon("certificateExport"))
+        self.caImportButton.setIcon(UI.PixmapCache.getIcon("certificateImport"))
+
         self.__populateServerCertificatesTree()
         self.__populateCaCertificatesTree()
-    
+
     def __populateServerCertificatesTree(self):
         """
         Private slot to populate the server certificates tree.
         """
         certificateDict = Globals.toDict(
-            Preferences.getSettings().value("Ssl/CaCertificatesDict"))
+            Preferences.getSettings().value("Ssl/CaCertificatesDict")
+        )
         for server in certificateDict:
             for cert in QSslCertificate.fromData(certificateDict[server]):
                 self.__createServerCertificateEntry(server, cert)
-        
+
         self.serversCertificatesTree.expandAll()
         for i in range(self.serversCertificatesTree.columnCount()):
             self.serversCertificatesTree.resizeColumnToContents(i)
-    
+
     def __createServerCertificateEntry(self, server, cert):
         """
         Private method to create a server certificate entry.
-        
+
         @param server server name of the certificate (string)
         @param cert certificate to insert (QSslCertificate)
         """
         # step 1: extract the info to be shown
         organisation = Utilities.decodeString(
-            ", ".join(cert.subjectInfo(
-                QSslCertificate.SubjectInfo.Organization)))
+            ", ".join(cert.subjectInfo(QSslCertificate.SubjectInfo.Organization))
+        )
         commonName = Utilities.decodeString(
-            ", ".join(cert.subjectInfo(
-                QSslCertificate.SubjectInfo.CommonName)))
+            ", ".join(cert.subjectInfo(QSslCertificate.SubjectInfo.CommonName))
+        )
         if organisation is None or organisation == "":
             organisation = self.tr("(Unknown)")
         if commonName is None or commonName == "":
             commonName = self.tr("(Unknown common name)")
         expiryDate = cert.expiryDate().toString("yyyy-MM-dd")
-        
+
         # step 2: create the entry
         items = self.serversCertificatesTree.findItems(
             organisation,
-            Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive)
+            Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive,
+        )
         if len(items) == 0:
-            parent = QTreeWidgetItem(
-                self.serversCertificatesTree, [organisation])
+            parent = QTreeWidgetItem(self.serversCertificatesTree, [organisation])
             parent.setFirstColumnSpanned(True)
         else:
             parent = items[0]
-        
+
         itm = QTreeWidgetItem(parent, [commonName, server, expiryDate])
         itm.setData(0, self.CertRole, cert.toPem())
-    
+
     @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
     def on_serversCertificatesTree_currentItemChanged(self, current, previous):
         """
         Private slot handling a change of the current item in the
         server certificates list.
-        
+
         @param current new current item (QTreeWidgetItem)
         @param previous previous current item (QTreeWidgetItem)
         """
@@ -122,7 +117,7 @@
         self.serversViewButton.setEnabled(enable)
         self.serversDeleteButton.setEnabled(enable)
         self.serversExportButton.setEnabled(enable)
-    
+
     @pyqtSlot()
     def on_serversViewButton_clicked(self):
         """
@@ -130,14 +125,15 @@
         """
         with contextlib.suppress(ImportError):
             from EricNetwork.EricSslCertificatesInfoDialog import (
-                EricSslCertificatesInfoDialog
+                EricSslCertificatesInfoDialog,
             )
+
             cert = QSslCertificate.fromData(
-                self.serversCertificatesTree.currentItem().data(
-                    0, self.CertRole))
+                self.serversCertificatesTree.currentItem().data(0, self.CertRole)
+            )
             dlg = EricSslCertificatesInfoDialog(cert, self)
             dlg.exec()
-    
+
     @pyqtSlot()
     def on_serversDeleteButton_clicked(self):
         """
@@ -147,48 +143,52 @@
         res = EricMessageBox.yesNo(
             self,
             self.tr("Delete Server Certificate"),
-            self.tr("""<p>Shall the server certificate really be"""
-                    """ deleted?</p><p>{0}</p>"""
-                    """<p>If the server certificate is deleted, the"""
-                    """ normal security checks will be reinstantiated"""
-                    """ and the server has to present a valid"""
-                    """ certificate.</p>""")
-            .format(itm.text(0)))
+            self.tr(
+                """<p>Shall the server certificate really be"""
+                """ deleted?</p><p>{0}</p>"""
+                """<p>If the server certificate is deleted, the"""
+                """ normal security checks will be reinstantiated"""
+                """ and the server has to present a valid"""
+                """ certificate.</p>"""
+            ).format(itm.text(0)),
+        )
         if res:
             server = itm.text(1)
-            cert = self.serversCertificatesTree.currentItem().data(
-                0, self.CertRole)
-            
+            cert = self.serversCertificatesTree.currentItem().data(0, self.CertRole)
+
             # delete the selected entry and its parent entry,
             # if it was the only one
             parent = itm.parent()
             parent.takeChild(parent.indexOfChild(itm))
             if parent.childCount() == 0:
                 self.serversCertificatesTree.takeTopLevelItem(
-                    self.serversCertificatesTree.indexOfTopLevelItem(parent))
-            
+                    self.serversCertificatesTree.indexOfTopLevelItem(parent)
+                )
+
             # delete the certificate from the user certificate store
             certificateDict = Globals.toDict(
-                Preferences.getSettings().value("Ssl/CaCertificatesDict"))
+                Preferences.getSettings().value("Ssl/CaCertificatesDict")
+            )
             if server in certificateDict:
-                certs = [c.toPem() for c in
-                         QSslCertificate.fromData(certificateDict[server])]
+                certs = [
+                    c.toPem() for c in QSslCertificate.fromData(certificateDict[server])
+                ]
                 if cert in certs:
                     certs.remove(cert)
                 if certs:
                     pems = QByteArray()
                     for cert in certs:
-                        pems.append(cert + b'\n')
+                        pems.append(cert + b"\n")
                     certificateDict[server] = pems
                 else:
                     del certificateDict[server]
             Preferences.getSettings().setValue(
-                "Ssl/CaCertificatesDict",
-                certificateDict)
-            
+                "Ssl/CaCertificatesDict", certificateDict
+            )
+
             # delete the certificate from the default certificates
             self.__updateDefaultConfiguration()
-    
+
     @pyqtSlot()
     def on_serversImportButton_clicked(self):
         """
@@ -198,59 +198,63 @@
         if certs:
             server = "*"
             certificateDict = Globals.toDict(
-                Preferences.getSettings().value("Ssl/CaCertificatesDict"))
+                Preferences.getSettings().value("Ssl/CaCertificatesDict")
+            )
             if server in certificateDict:
                 sCerts = QSslCertificate.fromData(certificateDict[server])
             else:
                 sCerts = []
-            
+
             pems = QByteArray()
             for cert in certs:
                 if cert in sCerts:
                     commonStr = ", ".join(
-                        cert.subjectInfo(
-                            QSslCertificate.SubjectInfo.CommonName))
+                        cert.subjectInfo(QSslCertificate.SubjectInfo.CommonName)
+                    )
                     EricMessageBox.warning(
                         self,
                         self.tr("Import Certificate"),
                         self.tr(
                             """<p>The certificate <b>{0}</b> already exists."""
-                            """ Skipping.</p>""")
-                        .format(Utilities.decodeString(commonStr)))
+                            """ Skipping.</p>"""
+                        ).format(Utilities.decodeString(commonStr)),
+                    )
                 else:
-                    pems.append(cert.toPem() + b'\n')
+                    pems.append(cert.toPem() + b"\n")
             if server not in certificateDict:
                 certificateDict[server] = QByteArray()
             certificateDict[server].append(pems)
             Preferences.getSettings().setValue(
-                "Ssl/CaCertificatesDict",
-                certificateDict)
-            
+                "Ssl/CaCertificatesDict", certificateDict
+            )
+
             self.serversCertificatesTree.clear()
             self.__populateServerCertificatesTree()
-            
+
             self.__updateDefaultConfiguration()
-    
+
     @pyqtSlot()
     def on_serversExportButton_clicked(self):
         """
         Private slot to export the selected server certificate.
         """
-        cert = self.serversCertificatesTree.currentItem().data(
-            0, self.CertRole)
+        cert = self.serversCertificatesTree.currentItem().data(0, self.CertRole)
         fname = (
-            self.serversCertificatesTree.currentItem().text(0).replace(" ", "")
+            self.serversCertificatesTree.currentItem()
+            .text(0)
+            .replace(" ", "")
             .replace("\t", "")
         )
         self.__exportCertificate(fname, cert)
-    
+
     def __updateDefaultConfiguration(self):
         """
         Private method to update the default SSL configuration.
         """
         caList = self.__getSystemCaCertificates()
         certificateDict = Globals.toDict(
-            Preferences.getSettings().value("Ssl/CaCertificatesDict"))
+            Preferences.getSettings().value("Ssl/CaCertificatesDict")
+        )
         for server in certificateDict:
             for cert in QSslCertificate.fromData(certificateDict[server]):
                 if cert not in caList:
@@ -258,69 +262,73 @@
         sslCfg = QSslConfiguration.defaultConfiguration()
         sslCfg.setCaCertificates(caList)
         QSslConfiguration.setDefaultConfiguration(sslCfg)
-    
+
     def __getSystemCaCertificates(self):
         """
         Private method to get the list of system certificates.
-        
+
         @return list of system certificates (list of QSslCertificate)
         """
-        caList = QSslCertificate.fromData(Globals.toByteArray(
-            Preferences.getSettings().value("Help/SystemCertificates")))
+        caList = QSslCertificate.fromData(
+            Globals.toByteArray(
+                Preferences.getSettings().value("Help/SystemCertificates")
+            )
+        )
         if not caList:
             caList = QSslConfiguration.systemCaCertificates()
         return caList
-    
+
     def __populateCaCertificatesTree(self):
         """
         Private slot to populate the CA certificates tree.
         """
         for cert in self.__getSystemCaCertificates():
             self.__createCaCertificateEntry(cert)
-        
+
         self.caCertificatesTree.expandAll()
         for i in range(self.caCertificatesTree.columnCount()):
             self.caCertificatesTree.resizeColumnToContents(i)
         self.caCertificatesTree.sortItems(0, Qt.SortOrder.AscendingOrder)
-    
+
     def __createCaCertificateEntry(self, cert):
         """
         Private method to create a CA certificate entry.
-        
+
         @param cert certificate to insert (QSslCertificate)
         """
         # step 1: extract the info to be shown
         organisation = Utilities.decodeString(
-            ", ".join(cert.subjectInfo(
-                QSslCertificate.SubjectInfo.Organization)))
+            ", ".join(cert.subjectInfo(QSslCertificate.SubjectInfo.Organization))
+        )
         commonName = Utilities.decodeString(
-            ", ".join(cert.subjectInfo(
-                QSslCertificate.SubjectInfo.CommonName)))
+            ", ".join(cert.subjectInfo(QSslCertificate.SubjectInfo.CommonName))
+        )
         if organisation is None or organisation == "":
             organisation = self.tr("(Unknown)")
         if commonName is None or commonName == "":
             commonName = self.tr("(Unknown common name)")
         expiryDate = cert.expiryDate().toString("yyyy-MM-dd")
-        
+
         # step 2: create the entry
         items = self.caCertificatesTree.findItems(
             organisation,
-            Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive)
+            Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive,
+        )
         if len(items) == 0:
             parent = QTreeWidgetItem(self.caCertificatesTree, [organisation])
             parent.setFirstColumnSpanned(True)
         else:
             parent = items[0]
-        
+
         itm = QTreeWidgetItem(parent, [commonName, expiryDate])
         itm.setData(0, self.CertRole, cert.toPem())
-    
+
     @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
     def on_caCertificatesTree_currentItemChanged(self, current, previous):
         """
         Private slot handling a change of the current item
         in the CA certificates list.
-        
+
         @param current new current item (QTreeWidgetItem)
         @param previous previous current item (QTreeWidgetItem)
         """
@@ -328,7 +336,7 @@
         self.caViewButton.setEnabled(enable)
         self.caDeleteButton.setEnabled(enable)
         self.caExportButton.setEnabled(enable)
-    
+
     @pyqtSlot()
     def on_caViewButton_clicked(self):
         """
@@ -336,13 +344,15 @@
         """
         with contextlib.suppress(ImportError):
             from EricNetwork.EricSslCertificatesInfoDialog import (
-                EricSslCertificatesInfoDialog
+                EricSslCertificatesInfoDialog,
             )
+
             cert = QSslCertificate.fromData(
-                self.caCertificatesTree.currentItem().data(0, self.CertRole))
+                self.caCertificatesTree.currentItem().data(0, self.CertRole)
+            )
             dlg = EricSslCertificatesInfoDialog(cert, self)
             dlg.exec()
-    
+
     @pyqtSlot()
     def on_caDeleteButton_clicked(self):
         """
@@ -356,32 +366,33 @@
                 """<p>Shall the CA certificate really be deleted?</p>"""
                 """<p>{0}</p>"""
                 """<p>If the CA certificate is deleted, the browser"""
-                """ will not trust any certificate issued by this CA.</p>""")
-            .format(itm.text(0)))
+                """ will not trust any certificate issued by this CA.</p>"""
+            ).format(itm.text(0)),
+        )
         if res:
             cert = self.caCertificatesTree.currentItem().data(0, self.CertRole)
-            
+
             # delete the selected entry and its parent entry,
             # if it was the only one
             parent = itm.parent()
             parent.takeChild(parent.indexOfChild(itm))
             if parent.childCount() == 0:
                 self.caCertificatesTree.takeTopLevelItem(
-                    self.caCertificatesTree.indexOfTopLevelItem(parent))
-            
+                    self.caCertificatesTree.indexOfTopLevelItem(parent)
+                )
+
             # delete the certificate from the CA certificate store
             caCerts = self.__getSystemCaCertificates()
             if cert in caCerts:
                 caCerts.remove(cert)
             pems = QByteArray()
             for cert in caCerts:
-                pems.append(cert.toPem() + '\n')
-            Preferences.getSettings().setValue(
-                "Help/SystemCertificates", pems)
-            
+                pems.append(cert.toPem() + "\n")
+            Preferences.getSettings().setValue("Help/SystemCertificates", pems)
+
             # delete the certificate from the default certificates
             self.__updateDefaultConfiguration()
-    
+
     @pyqtSlot()
     def on_caImportButton_clicked(self):
         """
@@ -393,29 +404,29 @@
             for cert in certs:
                 if cert in caCerts:
                     commonStr = ", ".join(
-                        cert.subjectInfo(
-                            QSslCertificate.SubjectInfo.CommonName))
+                        cert.subjectInfo(QSslCertificate.SubjectInfo.CommonName)
+                    )
                     EricMessageBox.warning(
                         self,
                         self.tr("Import Certificate"),
                         self.tr(
                             """<p>The certificate <b>{0}</b> already exists."""
-                            """ Skipping.</p>""")
-                        .format(Utilities.decodeString(commonStr)))
+                            """ Skipping.</p>"""
+                        ).format(Utilities.decodeString(commonStr)),
+                    )
                 else:
                     caCerts.append(cert)
-            
+
             pems = QByteArray()
             for cert in caCerts:
-                pems.append(cert.toPem() + '\n')
-            Preferences.getSettings().setValue(
-                "Help/SystemCertificates", pems)
-            
+                pems.append(cert.toPem() + "\n")
+            Preferences.getSettings().setValue("Help/SystemCertificates", pems)
+
             self.caCertificatesTree.clear()
             self.__populateCaCertificatesTree()
-            
+
             self.__updateDefaultConfiguration()
-    
+
     @pyqtSlot()
     def on_caExportButton_clicked(self):
         """
@@ -423,15 +434,17 @@
         """
         cert = self.caCertificatesTree.currentItem().data(0, self.CertRole)
         fname = (
-            self.caCertificatesTree.currentItem().text(0).replace(" ", "")
+            self.caCertificatesTree.currentItem()
+            .text(0)
+            .replace(" ", "")
             .replace("\t", "")
         )
         self.__exportCertificate(fname, cert)
-    
+
     def __exportCertificate(self, name, cert):
         """
         Private slot to export a certificate.
-        
+
         @param name default file name without extension
         @type str
         @param cert certificate to be exported encoded as PEM
@@ -442,11 +455,13 @@
                 self,
                 self.tr("Export Certificate"),
                 name,
-                self.tr("Certificate File (PEM) (*.pem);;"
-                        "Certificate File (DER) (*.der)"),
+                self.tr(
+                    "Certificate File (PEM) (*.pem);;" "Certificate File (DER) (*.der)"
+                ),
                 None,
-                EricFileDialog.DontConfirmOverwrite)
-            
+                EricFileDialog.DontConfirmOverwrite,
+            )
+
             if fname:
                 fpath = pathlib.Path(fname)
                 if not fpath.suffix:
@@ -457,18 +472,22 @@
                     res = EricMessageBox.yesNo(
                         self,
                         self.tr("Export Certificate"),
-                        self.tr("<p>The file <b>{0}</b> already exists."
-                                " Overwrite it?</p>").format(fname),
-                        icon=EricMessageBox.Warning)
+                        self.tr(
+                            "<p>The file <b>{0}</b> already exists."
+                            " Overwrite it?</p>"
+                        ).format(fname),
+                        icon=EricMessageBox.Warning,
+                    )
                     if not res:
                         return
-                
+
                 if fpath.suffix == ".pem":
                     crt = bytes(cert)
                 else:
                     crt = bytes(
-                        QSslCertificate.fromData(
-                            crt, QSsl.EncodingFormat.Pem)[0].toDer()
+                        QSslCertificate.fromData(crt, QSsl.EncodingFormat.Pem)[
+                            0
+                        ].toDer()
                     )
                 try:
                     with fpath.open("wb") as f:
@@ -479,13 +498,14 @@
                         self.tr("Export Certificate"),
                         self.tr(
                             """<p>The certificate could not be written"""
-                            """ to file <b>{0}</b></p><p>Error: {1}</p>""")
-                        .format(fpath, str(err)))
-    
+                            """ to file <b>{0}</b></p><p>Error: {1}</p>"""
+                        ).format(fpath, str(err)),
+                    )
+
     def __importCertificate(self):
         """
         Private method to read a certificate.
-        
+
         @return certificates read
         @rtype list of QSslCertificate
         """
@@ -493,19 +513,19 @@
             self,
             self.tr("Import Certificate"),
             "",
-            self.tr("Certificate Files (*.pem *.crt *.der *.cer *.ca);;"
-                    "All Files (*)"))
-        
+            self.tr(
+                "Certificate Files (*.pem *.crt *.der *.cer *.ca);;" "All Files (*)"
+            ),
+        )
+
         if fname:
             try:
                 with pathlib.Path(fname).open("rb") as f:
                     crt = QByteArray(f.read())
-                cert = QSslCertificate.fromData(
-                    crt, QSsl.EncodingFormat.Pem)
+                cert = QSslCertificate.fromData(crt, QSsl.EncodingFormat.Pem)
                 if not cert:
-                    cert = QSslCertificate.fromData(
-                        crt, QSsl.EncodingFormat.Der)
-                
+                    cert = QSslCertificate.fromData(crt, QSsl.EncodingFormat.Der)
+
                 return cert
             except OSError as err:
                 EricMessageBox.critical(
@@ -513,7 +533,8 @@
                     self.tr("Import Certificate"),
                     self.tr(
                         """<p>The certificate could not be read from file"""
-                        """ <b>{0}</b></p><p>Error: {1}</p>""")
-                    .format(fname, str(err)))
-        
+                        """ <b>{0}</b></p><p>Error: {1}</p>"""
+                    ).format(fname, str(err)),
+                )
+
         return []

eric ide

mercurial