eric7/E5Network/E5SslCertificatesDialog.py

branch
eric7
changeset 8354
12ebd3934fef
parent 8353
799196d0b05d
child 8355
8a7677a63c8d
--- a/eric7/E5Network/E5SslCertificatesDialog.py	Sat May 22 12:54:57 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,518 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2010 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a dialog to show and edit all certificates.
-"""
-
-import contextlib
-
-from PyQt6.QtCore import (
-    pyqtSlot, Qt, QByteArray, QFile, QFileInfo, QIODevice
-)
-from PyQt6.QtWidgets import QDialog, QTreeWidgetItem
-with contextlib.suppress(ImportError):
-    from PyQt6.QtNetwork import (
-        QSslCertificate, QSslSocket, QSslConfiguration, QSsl
-    )
-
-from E5Gui import E5MessageBox, E5FileDialog
-
-from .Ui_E5SslCertificatesDialog import Ui_E5SslCertificatesDialog
-
-import Preferences
-import Utilities
-import UI.PixmapCache
-import Globals
-
-
-class E5SslCertificatesDialog(QDialog, Ui_E5SslCertificatesDialog):
-    """
-    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.__populateServerCertificatesTree()
-        self.__populateCaCertificatesTree()
-    
-    def __populateServerCertificatesTree(self):
-        """
-        Private slot to populate the server certificates tree.
-        """
-        certificateDict = Globals.toDict(
-            Preferences.Prefs.settings.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)))
-        commonName = Utilities.decodeString(
-            ", ".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)
-        if len(items) == 0:
-            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)
-        """
-        enable = current is not None and current.parent() is not None
-        self.serversViewButton.setEnabled(enable)
-        self.serversDeleteButton.setEnabled(enable)
-        self.serversExportButton.setEnabled(enable)
-    
-    @pyqtSlot()
-    def on_serversViewButton_clicked(self):
-        """
-        Private slot to show data of the selected server certificate.
-        """
-        with contextlib.suppress(ImportError):
-            from E5Network.E5SslCertificatesInfoDialog import (
-                E5SslCertificatesInfoDialog
-            )
-            cert = QSslCertificate.fromData(
-                self.serversCertificatesTree.currentItem().data(
-                    0, self.CertRole))
-            dlg = E5SslCertificatesInfoDialog(cert, self)
-            dlg.exec()
-    
-    @pyqtSlot()
-    def on_serversDeleteButton_clicked(self):
-        """
-        Private slot to delete the selected server certificate.
-        """
-        itm = self.serversCertificatesTree.currentItem()
-        res = E5MessageBox.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)))
-        if res:
-            server = itm.text(1)
-            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))
-            
-            # delete the certificate from the user certificate store
-            certificateDict = Globals.toDict(
-                Preferences.Prefs.settings.value("Ssl/CaCertificatesDict"))
-            if server in certificateDict:
-                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')
-                    certificateDict[server] = pems
-                else:
-                    del certificateDict[server]
-            Preferences.Prefs.settings.setValue(
-                "Ssl/CaCertificatesDict",
-                certificateDict)
-            
-            # delete the certificate from the default certificates
-            self.__updateDefaultConfiguration()
-    
-    @pyqtSlot()
-    def on_serversImportButton_clicked(self):
-        """
-        Private slot to import server certificates.
-        """
-        certs = self.__importCertificate()
-        if certs:
-            server = "*"
-            certificateDict = Globals.toDict(
-                Preferences.Prefs.settings.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))
-                    E5MessageBox.warning(
-                        self,
-                        self.tr("Import Certificate"),
-                        self.tr(
-                            """<p>The certificate <b>{0}</b> already exists."""
-                            """ Skipping.</p>""")
-                        .format(Utilities.decodeString(commonStr)))
-                else:
-                    pems.append(cert.toPem() + '\n')
-            if server not in certificateDict:
-                certificateDict[server] = QByteArray()
-            certificateDict[server].append(pems)
-            Preferences.Prefs.settings.setValue(
-                "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)
-        fname = (
-            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.Prefs.settings.value("Ssl/CaCertificatesDict"))
-        for server in certificateDict:
-            for cert in QSslCertificate.fromData(certificateDict[server]):
-                if cert not in caList:
-                    caList.append(cert)
-        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.Prefs.settings.value("Help/SystemCertificates")))
-        if not caList:
-            caList = QSslSocket.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)))
-        commonName = Utilities.decodeString(
-            ", ".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)
-        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)
-        """
-        enable = current is not None and current.parent() is not None
-        self.caViewButton.setEnabled(enable)
-        self.caDeleteButton.setEnabled(enable)
-        self.caExportButton.setEnabled(enable)
-    
-    @pyqtSlot()
-    def on_caViewButton_clicked(self):
-        """
-        Private slot to show data of the selected CA certificate.
-        """
-        with contextlib.suppress(ImportError):
-            from E5Network.E5SslCertificatesInfoDialog import (
-                E5SslCertificatesInfoDialog
-            )
-            cert = QSslCertificate.fromData(
-                self.caCertificatesTree.currentItem().data(0, self.CertRole))
-            dlg = E5SslCertificatesInfoDialog(cert, self)
-            dlg.exec()
-    
-    @pyqtSlot()
-    def on_caDeleteButton_clicked(self):
-        """
-        Private slot to delete the selected CA certificate.
-        """
-        itm = self.caCertificatesTree.currentItem()
-        res = E5MessageBox.yesNo(
-            self,
-            self.tr("Delete CA Certificate"),
-            self.tr(
-                """<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)))
-        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))
-            
-            # 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.Prefs.settings.setValue(
-                "Help/SystemCertificates", pems)
-            
-            # delete the certificate from the default certificates
-            self.__updateDefaultConfiguration()
-    
-    @pyqtSlot()
-    def on_caImportButton_clicked(self):
-        """
-        Private slot to import server certificates.
-        """
-        certs = self.__importCertificate()
-        if certs:
-            caCerts = self.__getSystemCaCertificates()
-            for cert in certs:
-                if cert in caCerts:
-                    commonStr = ", ".join(
-                        cert.subjectInfo(
-                            QSslCertificate.SubjectInfo.CommonName))
-                    E5MessageBox.warning(
-                        self,
-                        self.tr("Import Certificate"),
-                        self.tr(
-                            """<p>The certificate <b>{0}</b> already exists."""
-                            """ Skipping.</p>""")
-                        .format(Utilities.decodeString(commonStr)))
-                else:
-                    caCerts.append(cert)
-            
-            pems = QByteArray()
-            for cert in caCerts:
-                pems.append(cert.toPem() + '\n')
-            Preferences.Prefs.settings.setValue(
-                "Help/SystemCertificates", pems)
-            
-            self.caCertificatesTree.clear()
-            self.__populateCaCertificatesTree()
-            
-            self.__updateDefaultConfiguration()
-    
-    @pyqtSlot()
-    def on_caExportButton_clicked(self):
-        """
-        Private slot to export the selected CA certificate.
-        """
-        cert = self.caCertificatesTree.currentItem().data(0, self.CertRole)
-        fname = (
-            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 (string)
-        @param cert certificate to be exported (QSslCertificate)
-        """
-        if cert is not None:
-            fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
-                self,
-                self.tr("Export Certificate"),
-                name,
-                self.tr("Certificate File (PEM) (*.pem);;"
-                        "Certificate File (DER) (*.der)"),
-                None,
-                E5FileDialog.DontConfirmOverwrite)
-            
-            if fname:
-                ext = QFileInfo(fname).suffix()
-                if not ext or ext not in ["pem", "der"]:
-                    ex = selectedFilter.split("(*")[1].split(")")[0]
-                    if ex:
-                        fname += ex
-                if QFileInfo(fname).exists():
-                    res = E5MessageBox.yesNo(
-                        self,
-                        self.tr("Export Certificate"),
-                        self.tr("<p>The file <b>{0}</b> already exists."
-                                " Overwrite it?</p>").format(fname),
-                        icon=E5MessageBox.Warning)
-                    if not res:
-                        return
-                
-                f = QFile(fname)
-                if not f.open(QIODevice.OpenModeFlag.WriteOnly):
-                    E5MessageBox.critical(
-                        self,
-                        self.tr("Export Certificate"),
-                        self.tr(
-                            """<p>The certificate could not be written"""
-                            """ to file <b>{0}</b></p><p>Error: {1}</p>""")
-                        .format(fname, f.errorString()))
-                    return
-                
-                if fname.endswith(".pem"):
-                    crt = cert.toPem()
-                else:
-                    crt = cert.toDer()
-                f.write(crt)
-                f.close()
-    
-    def __importCertificate(self):
-        """
-        Private method to read a certificate.
-        
-        @return certificates read (list of QSslCertificate)
-        """
-        fname = E5FileDialog.getOpenFileName(
-            self,
-            self.tr("Import Certificate"),
-            "",
-            self.tr("Certificate Files (*.pem *.crt *.der *.cer *.ca);;"
-                    "All Files (*)"))
-        
-        if fname:
-            f = QFile(fname)
-            if not f.open(QIODevice.OpenModeFlag.ReadOnly):
-                E5MessageBox.critical(
-                    self,
-                    self.tr("Export Certificate"),
-                    self.tr(
-                        """<p>The certificate could not be read from file"""
-                        """ <b>{0}</b></p><p>Error: {1}</p>""")
-                    .format(fname, f.errorString()))
-                return []
-            
-            crt = f.readAll()
-            f.close()
-            cert = QSslCertificate.fromData(crt, QSsl.EncodingFormat.Pem)
-            if not cert:
-                cert = QSslCertificate.fromData(crt, QSsl.EncodingFormat.Der)
-            
-            return cert
-        
-        return []

eric ide

mercurial