src/eric7/WebBrowser/SafeBrowsing/SafeBrowsingDialog.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9221
bf71ee032bb4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/WebBrowser/SafeBrowsing/SafeBrowsingDialog.py	Thu Jul 07 11:23:56 2022 +0200
@@ -0,0 +1,349 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to configure safe browsing support.
+"""
+
+from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QDateTime
+from PyQt6.QtWidgets import (
+    QDialog, QDialogButtonBox, QAbstractButton
+)
+
+from EricWidgets import EricMessageBox
+from EricGui.EricOverrideCursor import EricOverrideCursor
+
+from .Ui_SafeBrowsingDialog import Ui_SafeBrowsingDialog
+
+import UI.PixmapCache
+import Preferences
+
+
+class SafeBrowsingDialog(QDialog, Ui_SafeBrowsingDialog):
+    """
+    Class implementing a dialog to configure safe browsing support.
+    """
+    def __init__(self, manager, parent=None):
+        """
+        Constructor
+        
+        @param manager reference to the safe browsing manager
+        @type SafeBrowsingManager
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        self.setWindowFlags(Qt.WindowType.Window)
+        
+        self.__manager = manager
+        self.__manager.progressMessage.connect(self.__setProgressMessage)
+        self.__manager.progress.connect(self.__setProgress)
+        
+        self.iconLabel.setPixmap(
+            UI.PixmapCache.getPixmap("safeBrowsing48"))
+        
+        self.__gsbHelpDialog = None
+        
+        self.__enabled = Preferences.getWebBrowser("SafeBrowsingEnabled")
+        self.__apiKey = Preferences.getWebBrowser("SafeBrowsingApiKey")
+        self.__filterPlatform = Preferences.getWebBrowser(
+            "SafeBrowsingFilterPlatform")
+        self.__automaticUpdate = Preferences.getWebBrowser(
+            "SafeBrowsingAutoUpdate")
+        self.__useLookupApi = Preferences.getWebBrowser(
+            "SafeBrowsingUseLookupApi")
+        
+        self.buttonBox.setFocus()
+        
+        msh = self.minimumSizeHint()
+        self.resize(max(self.width(), msh.width()), msh.height())
+    
+    def show(self):
+        """
+        Public slot to show the dialog.
+        """
+        self.gsbGroupBox.setChecked(self.__enabled)
+        self.gsbApiKeyEdit.setText(self.__apiKey)
+        self.gsbFilterPlatformCheckBox.setChecked(self.__filterPlatform)
+        self.gsbAutoUpdateCheckBox.setChecked(self.__automaticUpdate)
+        self.gsbLookupCheckBox.setChecked(self.__useLookupApi)
+        
+        self.__updateCacheButtons()
+        
+        super().show()
+    
+    @pyqtSlot()
+    def on_gsbHelpButton_clicked(self):
+        """
+        Private slot to show some help text "How to create a safe
+        browsing API key.".
+        """
+        if self.__gsbHelpDialog is None:
+            from EricWidgets.EricSimpleHelpDialog import EricSimpleHelpDialog
+            from . import SafeBrowsingHelp
+            
+            helpStr = SafeBrowsingHelp()
+            self.__gsbHelpDialog = EricSimpleHelpDialog(
+                title=self.tr("Google Safe Browsing API Help"),
+                helpStr=helpStr, parent=self)
+        
+        self.__gsbHelpDialog.show()
+    
+    @pyqtSlot(QAbstractButton)
+    def on_buttonBox_clicked(self, button):
+        """
+        Private slot called by a button of the button box clicked.
+        
+        @param button button that was clicked (QAbstractButton)
+        """
+        if button == self.buttonBox.button(
+            QDialogButtonBox.StandardButton.Close
+        ):
+            self.close()
+    
+    @pyqtSlot()
+    def __save(self):
+        """
+        Private slot to save the configuration.
+        
+        @return flag indicating success
+        @rtype bool
+        """
+        self.__enabled = self.gsbGroupBox.isChecked()
+        self.__apiKey = self.gsbApiKeyEdit.text()
+        self.__filterPlatform = self.gsbFilterPlatformCheckBox.isChecked()
+        self.__automaticUpdate = self.gsbAutoUpdateCheckBox.isChecked()
+        self.__useLookupApi = self.gsbLookupCheckBox.isChecked()
+        
+        Preferences.setWebBrowser("SafeBrowsingEnabled", self.__enabled)
+        Preferences.setWebBrowser("SafeBrowsingApiKey", self.__apiKey)
+        Preferences.setWebBrowser("SafeBrowsingFilterPlatform",
+                                  self.__filterPlatform)
+        Preferences.setWebBrowser("SafeBrowsingAutoUpdate",
+                                  self.__automaticUpdate)
+        Preferences.setWebBrowser("SafeBrowsingUseLookupApi",
+                                  self.__useLookupApi)
+        
+        self.__manager.configurationChanged()
+        
+        self.__updateCacheButtons()
+        
+        return True
+    
+    def closeEvent(self, evt):
+        """
+        Protected method to handle close events.
+        
+        @param evt reference to the close event
+        @type QCloseEvent
+        """
+        if self.__okToClose():
+            evt.accept()
+        else:
+            evt.ignore()
+    
+    def __isModified(self):
+        """
+        Private method to check, if the dialog contains modified data.
+        
+        @return flag indicating the presence of modified data
+        @rtype bool
+        """
+        return (
+            (self.__enabled != self.gsbGroupBox.isChecked()) or
+            (self.__apiKey != self.gsbApiKeyEdit.text()) or
+            (self.__filterPlatform !=
+                self.gsbFilterPlatformCheckBox.isChecked()) or
+            (self.__automaticUpdate !=
+                self.gsbAutoUpdateCheckBox.isChecked()) or
+            (self.__useLookupApi != self.gsbLookupCheckBox.isChecked())
+        )
+    
+    def __okToClose(self):
+        """
+        Private method to check, if it is safe to close the dialog.
+        
+        @return flag indicating safe to close
+        @rtype bool
+        """
+        if self.__isModified():
+            res = EricMessageBox.okToClearData(
+                self,
+                self.tr("Safe Browsing Management"),
+                self.tr("""The dialog contains unsaved changes."""),
+                self.__save)
+            if not res:
+                return False
+        return True
+    
+    def __updateCacheButtons(self):
+        """
+        Private method to set enabled state of the cache buttons.
+        """
+        enable = self.__enabled and bool(self.__apiKey)
+        
+        self.updateCacheButton.setEnabled(enable)
+        self.clearCacheButton.setEnabled(enable)
+        
+        self.showUpdateTimeButton.setEnabled(enable and self.__automaticUpdate)
+    
+    @pyqtSlot()
+    def on_updateCacheButton_clicked(self):
+        """
+        Private slot to update the local cache database.
+        """
+        EricMessageBox.information(
+            self,
+            self.tr("Update Safe Browsing Cache"),
+            self.tr("""Updating the Safe Browsing cache might be a lengthy"""
+                    """ operation. Please be patient!"""))
+        
+        with EricOverrideCursor():
+            ok, error = self.__manager.updateHashPrefixCache()
+            self.__resetProgress()
+        if not ok:
+            if error:
+                EricMessageBox.critical(
+                    self,
+                    self.tr("Update Safe Browsing Cache"),
+                    self.tr("""<p>Updating the Safe Browsing cache failed."""
+                            """</p><p>Reason: {0}</p>""").format(error))
+            else:
+                EricMessageBox.critical(
+                    self,
+                    self.tr("Update Safe Browsing Cache"),
+                    self.tr("""<p>Updating the Safe Browsing cache failed."""
+                            """</p>"""))
+    
+    @pyqtSlot()
+    def on_clearCacheButton_clicked(self):
+        """
+        Private slot to clear the local cache database.
+        """
+        res = EricMessageBox.yesNo(
+            self,
+            self.tr("Clear Safe Browsing Cache"),
+            self.tr("""Do you really want to clear the Safe Browsing cache?"""
+                    """ Re-populating it might take some time."""))
+        if res:
+            with EricOverrideCursor():
+                self.__manager.fullCacheCleanup()
+    
+    @pyqtSlot(str, int)
+    def __setProgressMessage(self, message, maximum):
+        """
+        Private slot to set the progress message and the maximum value.
+        
+        @param message progress message to be set
+        @type str
+        @param maximum maximum value to be set
+        @type int
+        """
+        self.progressLabel.setText(message)
+        self.progressBar.setMaximum(maximum)
+        self.progressBar.setValue(0)
+    
+    @pyqtSlot(int)
+    def __setProgress(self, value):
+        """
+        Private slot to set the progress value.
+        
+        @param value progress value to be set
+        @type int
+        """
+        if bool(self.progressLabel.text()):
+            self.progressBar.setValue(value)
+    
+    def __resetProgress(self):
+        """
+        Private method to reset the progress info.
+        """
+        self.progressLabel.clear()
+        self.progressBar.setMaximum(100)
+        self.progressBar.setValue(0)
+    
+    @pyqtSlot(str)
+    def on_urlEdit_textChanged(self, text):
+        """
+        Private slot to handle changes of the entered URL text.
+        
+        @param text entered URL text
+        @type str
+        """
+        url = QUrl.fromUserInput(text)
+        enable = (
+            url.isValid() and
+            bool(url.scheme()) and
+            url.scheme() not in self.__manager.getIgnoreSchemes()
+        )
+        self.urlCheckButton.setEnabled(enable)
+    
+    @pyqtSlot()
+    def on_urlCheckButton_clicked(self):
+        """
+        Private slot to check the entered URL.
+        """
+        # Malicious URL for testing:
+        # http://malware.testing.google.test/testing/malware/*
+        # http://ianfette.org
+        #
+        urlStr = self.urlEdit.text()
+        url = QUrl.fromUserInput(urlStr)
+        threatLists, error = self.__manager.lookupUrl(url)
+        
+        if error:
+            EricMessageBox.warning(
+                self,
+                self.tr("Check URL"),
+                self.tr("<p>The Google Safe Browsing Server reported an"
+                        " error.</p><p>{0}</p>").format(error)
+            )
+        elif threatLists:
+            threatMessages = self.__manager.getThreatMessages(threatLists)
+            EricMessageBox.warning(
+                self,
+                self.tr("Check URL"),
+                self.tr("<p>The URL <b>{0}</b> was found in the Safe"
+                        " Browsing Database.</p>{1}").format(
+                    urlStr, "".join(threatMessages))
+            )
+        else:
+            EricMessageBox.information(
+                self,
+                self.tr("Check URL"),
+                self.tr("<p>The URL <b>{0}</b> was not found in the Safe"
+                        " Browsing Database and may be considered safe."
+                        "</p>")
+                .format(urlStr)
+            )
+    
+    @pyqtSlot()
+    def on_saveButton_clicked(self):
+        """
+        Private slot to save the configuration data.
+        """
+        self.__save()
+    
+    @pyqtSlot()
+    def on_showUpdateTimeButton_clicked(self):
+        """
+        Private slot to show the time of the next automatic threat list update.
+        """
+        nextUpdateDateTime = Preferences.getWebBrowser(
+            "SafeBrowsingUpdateDateTime")
+        message = (
+            self.tr("The next automatic threat list update will be done now.")
+            if (not nextUpdateDateTime.isValid() or
+                nextUpdateDateTime <= QDateTime.currentDateTime()) else
+            self.tr("<p>The next automatic threat list update will be done at"
+                    " <b>{0}</b>.</p>").format(
+                nextUpdateDateTime.toString("yyyy-MM-dd, HH:mm:ss"))
+        )
+        
+        EricMessageBox.information(
+            self,
+            self.tr("Update Time"),
+            message)

eric ide

mercurial