src/eric7/WebBrowser/SafeBrowsing/SafeBrowsingDialog.py

Tue, 18 Oct 2022 16:06:21 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Tue, 18 Oct 2022 16:06:21 +0200
branch
eric7
changeset 9413
80c06d472826
parent 9221
bf71ee032bb4
child 9473
3f23dbf37dbe
permissions
-rw-r--r--

Changed the eric7 import statements to include the package name (i.e. eric7) in order to not fiddle with sys.path.

# -*- 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 eric7.EricWidgets import EricMessageBox
from eric7.EricGui.EricOverrideCursor import EricOverrideCursor

from .Ui_SafeBrowsingDialog import Ui_SafeBrowsingDialog

from eric7.EricGui import EricPixmapCache
from eric7 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(EricPixmapCache.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 eric7.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