--- a/eric6/WebBrowser/WebBrowserPage.py Wed Oct 07 17:58:51 2020 +0200 +++ b/eric6/WebBrowser/WebBrowserPage.py Wed Oct 07 19:14:36 2020 +0200 @@ -23,6 +23,12 @@ PYQT_WEBENGINE_VERSION = QT_VERSION from PyQt5.QtWebChannel import QWebChannel +try: + from PyQt5.QtNetwork import QSslConfiguration, QSslCertificate + SSL_AVAILABLE = True +except ImportError: + SSL_AVAILABLE = False + from E5Gui import E5MessageBox from WebBrowser.WebBrowserWindow import WebBrowserWindow @@ -33,6 +39,7 @@ from .Tools import Scripts import Preferences +import Globals class WebBrowserPage(QWebEnginePage): @@ -47,6 +54,8 @@ shown web page @signal navigationRequestAccepted(url, navigation type, main frame) emitted to signal an accepted navigation request + @signal sslConfigurationChanged() emitted to indicate a change of the + stored SSL configuration data """ SafeJsWorld = QWebEngineScript.ApplicationWorld UnsafeJsWorld = QWebEngineScript.MainWorld @@ -58,6 +67,8 @@ navigationRequestAccepted = pyqtSignal(QUrl, QWebEnginePage.NavigationType, bool) + sslConfigurationChanged = pyqtSignal() + def __init__(self, parent=None): """ Constructor @@ -89,6 +100,8 @@ # defined for Qt >= 5.11 pass + self.__sslConfiguration = None + # Workaround for changing webchannel world inside # acceptNavigationRequest not working self.__channelUrl = QUrl() @@ -614,3 +627,107 @@ return self.__registerProtocolHandlerRequest.scheme() else: return "" + + ############################################################# + ## SSL configuration handling below + ############################################################# + + def setSslConfiguration(self, sslConfiguration): + """ + Public slot to set the SSL configuration data of the page. + + @param sslConfiguration SSL configuration to be set + @type QSslConfiguration + """ + self.__sslConfiguration = QSslConfiguration(sslConfiguration) + self.__sslConfiguration.url = self.url() + self.sslConfigurationChanged.emit() + + def getSslConfiguration(self): + """ + Public method to return a reference to the current SSL configuration. + + @return reference to the SSL configuration in use + @rtype QSslConfiguration + """ + return self.__sslConfiguration + + def clearSslConfiguration(self): + """ + Public slot to clear the stored SSL configuration data. + """ + self.__sslConfiguration = None + self.sslConfigurationChanged.emit() + + def getSslCertificate(self): + """ + Public method to get a reference to the SSL certificate. + + @return amended SSL certificate + @rtype QSslCertificate + """ + if self.__sslConfiguration is None: + return None + + sslCertificate = self.__sslConfiguration.peerCertificate() + sslCertificate.url = QUrl(self.__sslConfiguration.url) + return sslCertificate + + def getSslCertificateChain(self): + """ + Public method to get a reference to the SSL certificate chain. + + @return SSL certificate chain + @rtype list of QSslCertificate + """ + if self.__sslConfiguration is None: + return [] + + chain = self.__sslConfiguration.peerCertificateChain() + return chain + + def showSslInfo(self, pos): + """ + Public slot to show some SSL information for the loaded page. + + @param pos position to show the info at + @type QPoint + """ + if SSL_AVAILABLE and self.__sslConfiguration is not None: + from E5Network.E5SslInfoWidget import E5SslInfoWidget + widget = E5SslInfoWidget(self.url(), self.__sslConfiguration, + self.view()) + widget.showAt(pos) + else: + E5MessageBox.warning( + self.view(), + self.tr("SSL Info"), + self.tr("""This site does not contain SSL information.""")) + + def hasValidSslInfo(self): + """ + Public method to check, if the page has a valid SSL certificate. + + @return flag indicating a valid SSL certificate + @rtype bool + """ + if self.__sslConfiguration is None: + return False + + certList = self.__sslConfiguration.peerCertificateChain() + if not certList: + return False + + certificateDict = Globals.toDict( + Preferences.Prefs.settings.value("Ssl/CaCertificatesDict")) + for server in certificateDict: + localCAList = QSslCertificate.fromData(certificateDict[server]) + for cert in certList: + if cert in localCAList: + return True + + for cert in certList: + if cert.isBlacklisted(): + return False + + return True