Sat, 20 Feb 2016 14:34:32 +0100
Continued porting the web browser.
- added the VirusTotal code
--- a/Preferences/__init__.py Sat Feb 20 12:26:28 2016 +0100 +++ b/Preferences/__init__.py Sat Feb 20 14:34:32 2016 +0100 @@ -2652,7 +2652,7 @@ """ # the following entries are identical to the ones of the help viewer # and are being redirected there - if key.startswith(("FlashCookies", "Pim", "VirusTotal")): + if key.startswith(("FlashCookie", "Pim", "VirusTotal")): return getHelp(key, prefClass) if not prefClass.webEngineSettingsIntitialized: @@ -2784,7 +2784,7 @@ """ # the following entries are identical to the ones of the help viewer # and are being redirected there - if key.startswith(("FlashCookies", "Pim", "VirusTotal")): + if key.startswith(("FlashCookie", "Pim", "VirusTotal")): setHelp(key, value, prefClass) if key in ["StandardFont", "FixedFont"]:
--- a/WebBrowser/UrlBar/UrlBar.py Sat Feb 20 12:26:28 2016 +0100 +++ b/WebBrowser/UrlBar/UrlBar.py Sat Feb 20 14:34:32 2016 +0100 @@ -165,7 +165,7 @@ if manager.bookmarkForUrl(self.__browser.url()) is not None: self.__bookmarkButton.setIcon(self.__bmActiveIcon) bookmarks = manager.bookmarksForUrl(self.__browser.url()) - from Helpviewer.Bookmarks.BookmarkNode import BookmarkNode + from WebBrowser.Bookmarks.BookmarkNode import BookmarkNode for bookmark in bookmarks: manager.setTimestamp(bookmark, BookmarkNode.TsVisited, QDateTime.currentDateTime()) @@ -461,7 +461,7 @@ ## """ ## Private slot to handle clicking the RSS icon. ## """ -## from Helpviewer.Feeds.FeedsDialog import FeedsDialog +## from WebBrowser.Feeds.FeedsDialog import FeedsDialog ## feeds = self.__browser.getRSS() ## dlg = FeedsDialog(feeds, self.__browser) ## dlg.exec_()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/VirusTotal/VirusTotalApi.py Sat Feb 20 14:34:32 2016 +0100 @@ -0,0 +1,416 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2011 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the <a href="http://www.virustotal.com">VirusTotal</a> +API class. +""" + +from __future__ import unicode_literals +try: + str = unicode # __IGNORE_EXCEPTION__ +except NameError: + pass + +import json + +from PyQt5.QtCore import QObject, QUrl, QByteArray, pyqtSignal, qVersion +from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply + +from E5Gui import E5MessageBox + +import Preferences + + +class VirusTotalAPI(QObject): + """ + Class implementing the <a href="http://www.virustotal.com">VirusTotal</a> + API. + + @signal checkServiceKeyFinished(bool, str) emitted after the service key + check has been performed. It gives a flag indicating validity + (boolean) and an error message in case of a network error (string). + @signal submitUrlError(str) emitted with the error string, if the URL scan + submission returned an error. + @signal urlScanReport(str) emitted with the URL of the URL scan report page + @signal fileScanReport(str) emitted with the URL of the file scan report + page + """ + checkServiceKeyFinished = pyqtSignal(bool, str) + submitUrlError = pyqtSignal(str) + urlScanReport = pyqtSignal(str) + fileScanReport = pyqtSignal(str) + + TestServiceKeyScanID = \ + "4feed2c2e352f105f6188efd1d5a558f24aee6971bdf96d5fdb19c197d6d3fad" + + ServiceResult_ItemQueued = -2 + ServiceResult_ItemNotPresent = 0 + ServiceResult_ItemPresent = 1 + + # HTTP Status Codes + ServiceCode_InvalidKey = 202 + ServiceCode_RateLimitExceeded = 204 + ServiceCode_InvalidPrivilege = 403 + + GetFileReportPattern = "{0}://www.virustotal.com/vtapi/v2/file/report" + ScanUrlPattern = "{0}://www.virustotal.com/vtapi/v2/url/scan" + GetUrlReportPattern = "{0}://www.virustotal.com/vtapi/v2/url/report" + GetIpAddressReportPattern = \ + "{0}://www.virustotal.com/vtapi/v2/ip-address/report" + GetDomainReportPattern = "{0}://www.virustotal.com/vtapi/v2/domain/report" + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object (QObject) + """ + super(VirusTotalAPI, self).__init__(parent) + + self.__replies = [] + + self.__loadSettings() + + self.__lastIP = "" + self.__lastDomain = "" + self.__ipReportDlg = None + self.__domainReportDlg = None + + def __loadSettings(self): + """ + Private method to load the settings. + """ + if Preferences.getHelp("VirusTotalSecure"): + protocol = "https" + else: + protocol = "http" + self.GetFileReportUrl = self.GetFileReportPattern.format(protocol) + self.ScanUrlUrl = self.ScanUrlPattern.format(protocol) + self.GetUrlReportUrl = self.GetUrlReportPattern.format(protocol) + self.GetIpAddressReportUrl = self.GetIpAddressReportPattern.format( + protocol) + self.GetDomainReportUrl = self.GetDomainReportPattern.format(protocol) + + self.errorMessages = { + 204: self.tr("Request limit has been reached."), + 0: self.tr("Requested item is not present."), + -2: self.tr("Requested item is still queued."), + } + + def preferencesChanged(self): + """ + Public slot to handle a change of preferences. + """ + self.__loadSettings() + + def checkServiceKeyValidity(self, key, protocol=""): + """ + Public method to check the validity of the given service key. + + @param key service key (string) + @param protocol protocol used to access VirusTotal (string) + """ + if protocol == "": + urlStr = self.GetFileReportUrl + else: + urlStr = self.GetFileReportPattern.format(protocol) + request = QNetworkRequest(QUrl(urlStr)) + request.setHeader(QNetworkRequest.ContentTypeHeader, + "application/x-www-form-urlencoded") + params = QByteArray("apikey={0}&resource={1}".format( + key, self.TestServiceKeyScanID).encode("utf-8")) + + import WebBrowser.WebBrowserWindow + nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\ + .networkManager() + reply = nam.post(request, params) + reply.finished.connect(self.__checkServiceKeyValidityFinished) + self.__replies.append(reply) + + def __checkServiceKeyValidityFinished(self): + """ + Private slot to determine the result of the service key validity check. + """ + res = False + msg = "" + + reply = self.sender() + if reply.error() == QNetworkReply.NoError: + res = True + elif reply.error() == self.ServiceCode_InvalidKey: + res = False + else: + msg = reply.errorString() + self.__replies.remove(reply) + reply.deleteLater() + + self.checkServiceKeyFinished.emit(res, msg) + + def submitUrl(self, url): + """ + Public method to submit an URL to be scanned. + + @param url url to be scanned (QUrl) + """ + request = QNetworkRequest(QUrl(self.ScanUrlUrl)) + request.setHeader(QNetworkRequest.ContentTypeHeader, + "application/x-www-form-urlencoded") + params = QByteArray("apikey={0}&url=".format( + Preferences.getHelp("VirusTotalServiceKey")).encode("utf-8"))\ + .append(QUrl.toPercentEncoding(url.toString())) + + import WebBrowser.WebBrowserWindow + nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\ + .networkManager() + reply = nam.post(request, params) + reply.finished.connect(self.__submitUrlFinished) + self.__replies.append(reply) + + def __submitUrlFinished(self): + """ + Private slot to determine the result of the URL scan submission. + """ + reply = self.sender() + if reply.error() == QNetworkReply.NoError: + result = json.loads(str(reply.readAll(), "utf-8")) + if result["response_code"] == self.ServiceResult_ItemPresent: + self.urlScanReport.emit(result["permalink"]) + self.__getUrlScanReportUrl(result["scan_id"]) + else: + if result["response_code"] in self.errorMessages: + msg = self.errorMessages[result["response_code"]] + else: + msg = result["verbose_msg"] + self.submitUrlError.emit(msg) + elif reply.error() == self.ServiceCode_RateLimitExceeded: + self.submitUrlError.emit( + self.errorMessages[result[self.ServiceCode_RateLimitExceeded]]) + else: + self.submitUrlError.emit(reply.errorString()) + self.__replies.remove(reply) + reply.deleteLater() + + def __getUrlScanReportUrl(self, scanId): + """ + Private method to get the report URL for a URL scan. + + @param scanId ID of the scan to get the report URL for (string) + """ + request = QNetworkRequest(QUrl(self.GetUrlReportUrl)) + request.setHeader(QNetworkRequest.ContentTypeHeader, + "application/x-www-form-urlencoded") + params = QByteArray("apikey={0}&resource={1}".format( + Preferences.getHelp("VirusTotalServiceKey"), scanId) + .encode("utf-8")) + + import WebBrowser.WebBrowserWindow + nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\ + .networkManager() + reply = nam.post(request, params) + reply.finished.connect(self.__getUrlScanReportUrlFinished) + self.__replies.append(reply) + + def __getUrlScanReportUrlFinished(self): + """ + Private slot to determine the result of the URL scan report URL + request. + """ + reply = self.sender() + if reply.error() == QNetworkReply.NoError: + result = json.loads(str(reply.readAll(), "utf-8")) + if "filescan_id" in result and result["filescan_id"] is not None: + self.__getFileScanReportUrl(result["filescan_id"]) + self.__replies.remove(reply) + reply.deleteLater() + + def __getFileScanReportUrl(self, scanId): + """ + Private method to get the report URL for a file scan. + + @param scanId ID of the scan to get the report URL for (string) + """ + request = QNetworkRequest(QUrl(self.GetFileReportUrl)) + request.setHeader(QNetworkRequest.ContentTypeHeader, + "application/x-www-form-urlencoded") + params = QByteArray("apikey={0}&resource={1}".format( + Preferences.getHelp("VirusTotalServiceKey"), scanId) + .encode("utf-8")) + + import WebBrowser.WebBrowserWindow + nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\ + .networkManager() + reply = nam.post(request, params) + reply.finished.connect(self.__getFileScanReportUrlFinished) + self.__replies.append(reply) + + def __getFileScanReportUrlFinished(self): + """ + Private slot to determine the result of the file scan report URL + request. + """ + reply = self.sender() + if reply.error() == QNetworkReply.NoError: + result = json.loads(str(reply.readAll(), "utf-8")) + self.fileScanReport.emit(result["permalink"]) + self.__replies.remove(reply) + reply.deleteLater() + + def getIpAddressReport(self, ipAddress): + """ + Public method to retrieve a report for an IP address. + + @param ipAddress valid IPv4 address in dotted quad notation + @type str + """ + self.__lastIP = ipAddress + + queryItems = [ + ("apikey", Preferences.getHelp("VirusTotalServiceKey")), + ("ip", ipAddress), + ] + url = QUrl(self.GetIpAddressReportUrl) + if qVersion() >= "5.0.0": + from PyQt5.QtCore import QUrlQuery + query = QUrlQuery() + query.setQueryItems(queryItems) + url.setQuery(query) + else: + url.setQueryItems(queryItems) + request = QNetworkRequest(url) + + import WebBrowser.WebBrowserWindow + nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\ + .networkManager() + reply = nam.get(request) + reply.finished.connect(self.__getIpAddressReportFinished) + self.__replies.append(reply) + + def __getIpAddressReportFinished(self): + """ + Private slot to process the IP address report data. + """ + reply = self.sender() + if reply.error() == QNetworkReply.NoError: + result = json.loads(str(reply.readAll(), "utf-8")) + if result["response_code"] == 0: + E5MessageBox.information( + None, + self.tr("VirusTotal IP Address Report"), + self.tr("""VirusTotal does not have any information for""" + """ the given IP address.""")) + elif result["response_code"] == -1: + E5MessageBox.information( + None, + self.tr("VirusTotal IP Address Report"), + self.tr("""The submitted IP address is invalid.""")) + else: + owner = result["as_owner"] + resolutions = result["resolutions"] + try: + urls = result["detected_urls"] + except KeyError: + urls = [] + + from .VirusTotalIpReportDialog import VirusTotalIpReportDialog + self.__ipReportDlg = VirusTotalIpReportDialog( + self.__lastIP, owner, resolutions, urls) + self.__ipReportDlg.show() + self.__replies.remove(reply) + reply.deleteLater() + + def getDomainReport(self, domain): + """ + Public method to retrieve a report for a domain. + + @param domain domain name + @type str + """ + self.__lastDomain = domain + + queryItems = [ + ("apikey", Preferences.getHelp("VirusTotalServiceKey")), + ("domain", domain), + ] + url = QUrl(self.GetDomainReportUrl) + if qVersion() >= "5.0.0": + from PyQt5.QtCore import QUrlQuery + query = QUrlQuery() + query.setQueryItems(queryItems) + url.setQuery(query) + else: + url.setQueryItems(queryItems) + request = QNetworkRequest(url) + + import WebBrowser.WebBrowserWindow + nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\ + .networkManager() + reply = nam.get(request) + reply.finished.connect(self.__getDomainReportFinished) + self.__replies.append(reply) + + def __getDomainReportFinished(self): + """ + Private slot to process the IP address report data. + """ + reply = self.sender() + if reply.error() == QNetworkReply.NoError: + result = json.loads(str(reply.readAll(), "utf-8")) + if result["response_code"] == 0: + E5MessageBox.information( + None, + self.tr("VirusTotal Domain Report"), + self.tr("""VirusTotal does not have any information for""" + """ the given domain.""")) + elif result["response_code"] == -1: + E5MessageBox.information( + None, + self.tr("VirusTotal Domain Report"), + self.tr("""The submitted domain address is invalid.""")) + else: + resolutions = result["resolutions"] + try: + urls = result["detected_urls"] + except KeyError: + urls = [] + try: + subdomains = result["subdomains"] + except KeyError: + subdomains = [] + try: + bdCategory = result["BitDefender category"] + except KeyError: + bdCategory = self.tr("not available") + try: + tmCategory = result["TrendMicro category"] + except KeyError: + tmCategory = self.tr("not available") + try: + wtsCategory = result["Websense ThreatSeeker category"] + except KeyError: + wtsCategory = self.tr("not available") + try: + whois = result["whois"] + except KeyError: + whois = "" + + from .VirusTotalDomainReportDialog import \ + VirusTotalDomainReportDialog + self.__domainReportDlg = VirusTotalDomainReportDialog( + self.__lastDomain, resolutions, urls, subdomains, + bdCategory, tmCategory, wtsCategory, whois) + self.__domainReportDlg.show() + self.__replies.remove(reply) + reply.deleteLater() + + def close(self): + """ + Public slot to close the API. + """ + for reply in self.__replies: + reply.abort() + + self.__ipReportDlg and self.__ipReportDlg.close() + self.__domainReportDlg and self.__domainReportDlg.close()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/VirusTotal/VirusTotalDomainReportDialog.py Sat Feb 20 14:34:32 2016 +0100 @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show the VirusTotal domain report. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSlot, Qt +from PyQt5.QtWidgets import QDialog, QTreeWidgetItem + +from .Ui_VirusTotalDomainReportDialog import Ui_VirusTotalDomainReportDialog + +import UI.PixmapCache + + +class VirusTotalDomainReportDialog(QDialog, Ui_VirusTotalDomainReportDialog): + """ + Class implementing a dialog to show the VirusTotal domain report. + """ + def __init__(self, domain, resolutions, urls, subdomains, + bdCategory, tmCategory, wtsCategory, whois, parent=None): + """ + Constructor + + @param domain domain name + @type str + @param resolutions list of resolved host names + @type list of dict + @param urls list of detected URLs + @type list of dict + @param subdomains list of subdomains + @type list of str + @param bdCategory BitDefender categorization + @type str + @param tmCategory TrendMicro categorization + @type str + @param wtsCategory Websense ThreatSeeker categorization + @type str + @param whois whois information + @type str + @param parent reference to the parent widget + @type QWidget + """ + super(VirusTotalDomainReportDialog, self).__init__(parent) + self.setupUi(self) + self.setWindowFlags(Qt.Window) + + self.headerLabel.setText( + self.tr("<b>Report for domain {0}</b>").format(domain)) + self.headerPixmap.setPixmap( + UI.PixmapCache.getPixmap("virustotal.png")) + + for resolution in resolutions: + QTreeWidgetItem( + self.resolutionsList, + [resolution["ip_address"], + resolution["last_resolved"].split()[0]] + ) + self.resolutionsList.resizeColumnToContents(0) + self.resolutionsList.resizeColumnToContents(1) + self.resolutionsList.sortByColumn(0, Qt.AscendingOrder) + + if not urls: + self.detectedUrlsGroup.setVisible(False) + for url in urls: + QTreeWidgetItem( + self.urlsList, + [url["url"], + self.tr("{0}/{1}", "positives / total").format( + url["positives"], url["total"]), + url["scan_date"].split()[0]] + ) + self.urlsList.resizeColumnToContents(0) + self.urlsList.resizeColumnToContents(1) + self.urlsList.resizeColumnToContents(2) + self.urlsList.sortByColumn(0, Qt.AscendingOrder) + + if not subdomains: + self.subdomainsGroup.setVisible(False) + else: + self.subdomainsList.addItems(subdomains) + self.subdomainsList.sortItems() + + self.bdLabel.setText(bdCategory) + self.tmLabel.setText(tmCategory) + self.wtsLabel.setText(wtsCategory) + + self.__whois = whois + self.__whoisDomain = domain + self.whoisButton.setEnabled(bool(whois)) + + @pyqtSlot() + def on_whoisButton_clicked(self): + """ + Private slot to show the whois information. + """ + from .VirusTotalWhoisDialog import VirusTotalWhoisDialog + dlg = VirusTotalWhoisDialog(self.__whoisDomain, self.__whois) + dlg.exec_()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/VirusTotal/VirusTotalDomainReportDialog.ui Sat Feb 20 14:34:32 2016 +0100 @@ -0,0 +1,304 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>VirusTotalDomainReportDialog</class> + <widget class="QDialog" name="VirusTotalDomainReportDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>900</width> + <height>700</height> + </rect> + </property> + <property name="windowTitle"> + <string>Domain Report</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLabel" name="headerPixmap"/> + </item> + <item> + <widget class="QLabel" name="headerLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line9_3"> + <property name="frameShape"> + <enum>QFrame::HLine</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Categorizations</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string notr="true">BitDefender:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="bdLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string notr="true">TrendMicro:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="tmLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string notr="true">Websense ThreatSeeker:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="wtsLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>690</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QPushButton" name="whoisButton"> + <property name="text"> + <string>Whois</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QGroupBox" name="resolutionsGroup"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>4</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Resolutions</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QTreeWidget" name="resolutionsList"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <column> + <property name="text"> + <string>IP-Address</string> + </property> + </column> + <column> + <property name="text"> + <string>Resolved Date</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="subdomainsGroup"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>4</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Subdomains</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QListWidget" name="subdomainsList"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QGroupBox" name="detectedUrlsGroup"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>2</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Detected URLs</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QTreeWidget" name="urlsList"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <column> + <property name="text"> + <string>URL</string> + </property> + </column> + <column> + <property name="text"> + <string>Scan Result</string> + </property> + </column> + <column> + <property name="text"> + <string>Scan Date</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>whoisButton</tabstop> + <tabstop>resolutionsList</tabstop> + <tabstop>subdomainsList</tabstop> + <tabstop>urlsList</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>VirusTotalDomainReportDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>VirusTotalDomainReportDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/VirusTotal/VirusTotalIpReportDialog.py Sat Feb 20 14:34:32 2016 +0100 @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show the VirusTotal IP address report. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QDialog, QTreeWidgetItem + +from .Ui_VirusTotalIpReportDialog import Ui_VirusTotalIpReportDialog + +import UI.PixmapCache + + +class VirusTotalIpReportDialog(QDialog, Ui_VirusTotalIpReportDialog): + """ + Class implementing a dialog to show the VirusTotal IP address report. + """ + def __init__(self, ip, owner, resolutions, urls, parent=None): + """ + Constructor + + @param ip IP address + @type str + @param owner owner of the IP address + @type str + @param resolutions list of resolved host names + @type list of dict + @param urls list of detected URLs + @type list of dict + @param parent reference to the parent widget + @type QWidget + """ + super(VirusTotalIpReportDialog, self).__init__(parent) + self.setupUi(self) + self.setWindowFlags(Qt.Window) + + self.headerLabel.setText( + self.tr("<b>Report for IP {0}</b>").format(ip)) + self.headerPixmap.setPixmap( + UI.PixmapCache.getPixmap("virustotal.png")) + self.ownerLabel.setText(owner) + + for resolution in resolutions: + QTreeWidgetItem( + self.resolutionsList, + [resolution["hostname"], + resolution["last_resolved"].split()[0]] + ) + self.resolutionsList.resizeColumnToContents(0) + self.resolutionsList.resizeColumnToContents(1) + self.resolutionsList.sortByColumn(0, Qt.AscendingOrder) + + if not urls: + self.detectedUrlsGroup.setVisible(False) + for url in urls: + QTreeWidgetItem( + self.urlsList, + [url["url"], + self.tr("{0}/{1}", "positives / total").format( + url["positives"], url["total"]), + url["scan_date"].split()[0]] + ) + self.urlsList.resizeColumnToContents(0) + self.urlsList.resizeColumnToContents(1) + self.urlsList.resizeColumnToContents(2) + self.urlsList.sortByColumn(0, Qt.AscendingOrder)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/VirusTotal/VirusTotalIpReportDialog.ui Sat Feb 20 14:34:32 2016 +0100 @@ -0,0 +1,208 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>VirusTotalIpReportDialog</class> + <widget class="QDialog" name="VirusTotalIpReportDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>IP Address Report</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLabel" name="headerPixmap"/> + </item> + <item> + <widget class="QLabel" name="headerLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line9_3"> + <property name="frameShape"> + <enum>QFrame::HLine</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Owner:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="ownerLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QGroupBox" name="resolutionsGroup"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>4</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Resolutions</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QTreeWidget" name="resolutionsList"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <column> + <property name="text"> + <string>Hostname</string> + </property> + </column> + <column> + <property name="text"> + <string>Resolved Date</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="detectedUrlsGroup"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>2</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Detected URLs</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QTreeWidget" name="urlsList"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <column> + <property name="text"> + <string>URL</string> + </property> + </column> + <column> + <property name="text"> + <string>Scan Result</string> + </property> + </column> + <column> + <property name="text"> + <string>Scan Date</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>VirusTotalIpReportDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>VirusTotalIpReportDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/VirusTotal/VirusTotalWhoisDialog.py Sat Feb 20 14:34:32 2016 +0100 @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show the 'whois' information. +""" + +from __future__ import unicode_literals + +from PyQt5.QtWidgets import QDialog + +from .Ui_VirusTotalWhoisDialog import Ui_VirusTotalWhoisDialog + +import UI.PixmapCache + + +class VirusTotalWhoisDialog(QDialog, Ui_VirusTotalWhoisDialog): + """ + Class implementing a dialog to show the 'whois' information. + """ + def __init__(self, domain, whois, parent=None): + """ + Constructor + + @param domain domain name + @type str + @param whois whois information + @type str + @param parent reference to the parent widget + @type QWidget + """ + super(VirusTotalWhoisDialog, self).__init__(parent) + self.setupUi(self) + + self.headerLabel.setText( + self.tr("<b>Whois information for domain {0}</b>").format(domain)) + self.headerPixmap.setPixmap( + UI.PixmapCache.getPixmap("virustotal.png")) + self.whoisEdit.setPlainText(whois)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/VirusTotal/VirusTotalWhoisDialog.ui Sat Feb 20 14:34:32 2016 +0100 @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>VirusTotalWhoisDialog</class> + <widget class="QDialog" name="VirusTotalWhoisDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>400</height> + </rect> + </property> + <property name="windowTitle"> + <string>Whois Information</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLabel" name="headerPixmap"/> + </item> + <item> + <widget class="QLabel" name="headerLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line9_3"> + <property name="frameShape"> + <enum>QFrame::HLine</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QPlainTextEdit" name="whoisEdit"> + <property name="tabChangesFocus"> + <bool>true</bool> + </property> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>VirusTotalWhoisDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>VirusTotalWhoisDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/VirusTotal/__init__.py Sat Feb 20 14:34:32 2016 +0100 @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package containing the VirusTotal interface. +"""
--- a/WebBrowser/WebBrowserPage.py Sat Feb 20 12:26:28 2016 +0100 +++ b/WebBrowser/WebBrowserPage.py Sat Feb 20 14:34:32 2016 +0100 @@ -140,13 +140,13 @@ ## self.__lastRequest = None ## self.__lastRequestType = QWebPage.NavigationTypeOther ## -## import Helpviewer.HelpWindow +## import WebBrowser.WebBrowserWindow ## from .Network.NetworkAccessManagerProxy import \ ## NetworkAccessManagerProxy ## self.__proxy = NetworkAccessManagerProxy(self) ## self.__proxy.setWebPage(self) ## self.__proxy.setPrimaryNetworkAccessManager( -## Helpviewer.HelpWindow.HelpWindow.networkAccessManager()) +## WebBrowser.WebBrowserWindow.WebBrowserWindow.networkAccessManager()) ## self.setNetworkAccessManager(self.__proxy) self.__sslConfiguration = None @@ -452,8 +452,8 @@ ## @param url URL to determine user agent for (QUrl) ## @return user agent string (string) ## """ -## import Helpviewer.HelpWindow -## agent = Helpviewer.HelpWindow.HelpWindow.userAgentsManager()\ +## import WebBrowser.WebBrowserWindow +## agent = WebBrowser.WebBrowserWindow.WebBrowserWindow.userAgentsManager()\ ## .userAgentForUrl(url) ## if agent == "": ## # no agent string specified for the given host -> use global one @@ -463,6 +463,7 @@ ## agent = QWebPage.userAgentForUrl(self, url) ## return agent ## + # TODO: SSL ## def __managerFinished(self, reply): ## """ ## Private slot to handle a finished reply. @@ -496,8 +497,8 @@ ## reply.url() == self.mainFrame().url(): ## modified = reply.header(QNetworkRequest.LastModifiedHeader) ## if modified and modified.isValid(): -## import Helpviewer.HelpWindow -## manager = Helpviewer.HelpWindow.HelpWindow.bookmarksManager() +## import WebBrowser.WebBrowserWindow +## manager = WebBrowser.WebBrowserWindow.WebBrowserWindow.bookmarksManager() ## from .Bookmarks.BookmarkNode import BookmarkNode ## for bookmark in manager.bookmarksForUrl(reply.url()): ## manager.setTimestamp(bookmark, BookmarkNode.TsModified,
--- a/WebBrowser/WebBrowserView.py Sat Feb 20 12:26:28 2016 +0100 +++ b/WebBrowser/WebBrowserView.py Sat Feb 20 14:34:32 2016 +0100 @@ -88,8 +88,8 @@ self.installEventFilter(self) # TODO: Speeddial -## import Helpviewer.HelpWindow -## self.__speedDial = Helpviewer.HelpWindow.HelpWindow.speedDial() +## import WebBrowser.WebBrowserWindow +## self.__speedDial = WebBrowser.WebBrowserWindow.WebBrowserWindow.speedDial() self.__page = WebBrowserPage(self) self.setPage(self.__page) @@ -105,9 +105,6 @@ self.__currentZoom = 100 self.__zoomLevels = WebBrowserView.ZoomLevels[:] -## -## self.__javaScriptBinding = None -## self.__javaScriptEricObject = None ## self.__mw.zoomTextOnlyChanged.connect(self.__applyZoom) @@ -126,9 +123,6 @@ ## self.page().setForwardUnsupportedContent(True) ## self.page().unsupportedContent.connect(self.__unsupportedContent) -## self.page().frameCreated.connect(self.__addExternalBinding) -## self.__addExternalBinding(self.page().mainFrame()) - ## self.page().databaseQuotaExceeded.connect(self.__databaseQuotaExceeded) self.__mw.openSearchManager().currentEngineChanged.connect( @@ -330,11 +324,6 @@ """ for URL <b>{0}</b>.</p>""") .format(name.toString())) return -## elif name.scheme() == "javascript": -## scriptSource = QUrl.fromPercentEncoding(name.toString( -## QUrl.FormattingOptions(QUrl.TolerantMode | QUrl.RemoveScheme))) -## self.page().mainFrame().evaluateJavaScript(scriptSource) -## return else: if name.toString().endswith(".pdf") or \ name.toString().endswith(".PDF") or \ @@ -689,13 +678,12 @@ UI.PixmapCache.getIcon("mailSend.png"), self.tr("Send Link"), self.__sendLink).setData(hitTest.linkUrl()) - # TODO: VirusTotal -## if Preferences.getWebBrowser("VirusTotalEnabled") and \ -## Preferences.getWebBrowser("VirusTotalServiceKey") != "": -## menu.addAction( -## UI.PixmapCache.getIcon("virustotal.png"), -## self.tr("Scan Link with VirusTotal"), -## self.__virusTotal).setData(hitTest.linkUrl()) + if Preferences.getWebBrowser("VirusTotalEnabled") and \ + Preferences.getWebBrowser("VirusTotalServiceKey") != "": + menu.addAction( + UI.PixmapCache.getIcon("virustotal.png"), + self.tr("Scan Link with VirusTotal"), + self.__virusTotal).setData(hitTest.linkUrl()) def __createImageContextMenu(self, menu, hitTest): """ @@ -735,13 +723,12 @@ ## UI.PixmapCache.getIcon("adBlockPlus.png"), ## self.tr("Block Image"), self.__blockImage)\ ## .setData(hitTest.imageUrl().toString()) - # TODO: VirusTotal -## if Preferences.getWebBrowser("VirusTotalEnabled") and \ -## Preferences.getWebBrowser("VirusTotalServiceKey") != "": -## menu.addAction( -## UI.PixmapCache.getIcon("virustotal.png"), -## self.tr("Scan Image with VirusTotal"), -## self.__virusTotal).setData(hitTest.imageUrl()) + if Preferences.getWebBrowser("VirusTotalEnabled") and \ + Preferences.getWebBrowser("VirusTotalServiceKey") != "": + menu.addAction( + UI.PixmapCache.getIcon("virustotal.png"), + self.tr("Scan Image with VirusTotal"), + self.__virusTotal).setData(hitTest.imageUrl()) def __createMediaContextMenu(self, menu, hitTest): """ @@ -1029,10 +1016,10 @@ ## """ ## Private slot to add a block rule for an image URL. ## """ -## import Helpviewer.HelpWindow +## import WebBrowser.WebBrowserWindow ## act = self.sender() ## url = act.data() -## dlg = Helpviewer.HelpWindow.HelpWindow.adBlockManager().showDialog() +## dlg = WebBrowser.WebBrowserWindow.WebBrowserWindow.adBlockManager().showDialog() ## dlg.addCustomRule(url) # TODO: DownloadManager @@ -1060,14 +1047,13 @@ script = Scripts.toggleMediaMute(self.__clickedPos) self.page().runJavaScript(script) - # TODO: VirusTotal -## def __virusTotal(self): -## """ -## Private slot to scan the selected URL with VirusTotal. -## """ -## act = self.sender() -## url = act.data() -## self.__mw.requestVirusTotalScan(url) + def __virusTotal(self): + """ + Private slot to scan the selected URL with VirusTotal. + """ + act = self.sender() + url = act.data() + self.__mw.requestVirusTotalScan(url) def __searchRequested(self, act): """ @@ -1152,14 +1138,6 @@ dlg.setTitle(self.title()) dlg.setDescription(description) dlg.exec_() -## from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog -## dlg = AddBookmarkDialog() -## dlg.setUrl(bytes(self.url().toEncoded()).decode()) -## dlg.setTitle(self.title()) -## meta = self.page().mainFrame().metaData() -## if "description" in meta: -## dlg.setDescription(meta["description"][0]) -## dlg.exec_() def dragEnterEvent(self, evt): """
--- a/WebBrowser/WebBrowserWindow.py Sat Feb 20 12:26:28 2016 +0100 +++ b/WebBrowser/WebBrowserWindow.py Sat Feb 20 14:34:32 2016 +0100 @@ -38,7 +38,7 @@ from E5Gui.E5Application import e5App from E5Gui.E5ZoomWidget import E5ZoomWidget -##from E5Network.E5NetworkIcon import E5NetworkIcon +from E5Network.E5NetworkIcon import E5NetworkIcon import Preferences from Preferences import Shortcuts @@ -137,21 +137,6 @@ self.__initActions() else: self.webProfile(private) -## if self.isPrivate(): -## self.__webProfile = QWebEngineProfile(self) -## else: -## self.__webProfile = QWebEngineProfile.defaultProfile() -## self.__webProfile.downloadRequested.connect( -## self.__downloadRequested) -## -## # Setup QWebChannel user script -## script = QWebEngineScript() -## script.setName("_eric_webchannel") -## script.setInjectionPoint(QWebEngineScript.DocumentCreation) -## script.setWorldId(QWebEngineScript.MainWorld) -## script.setRunsOnSubFrames(True) -## script.setSourceCode(Scripts.setupWebChannel()) -## self.__webProfile.scripts().insert(script) from .SearchWidget import SearchWidget # TODO: QtHelp @@ -162,8 +147,7 @@ from .WebBrowserTabWidget import WebBrowserTabWidget # TODO: AdBlock ## from .AdBlock.AdBlockIcon import AdBlockIcon - # TODO: VirusTotal -## from .VirusTotal.VirusTotalApi import VirusTotalAPI + from .VirusTotal.VirusTotalApi import VirusTotalAPI # TODO: allow using Qt Help even if not called from eric6 WebBrowserWindow.setUseQtHelp(self.__fromEric) @@ -268,8 +252,9 @@ self.__initMenus() self.__initToolbars() -## self.historyManager() -## + self.historyManager() + + # TODO: Sync ## syncMgr = self.syncManager() ## syncMgr.syncMessage.connect(self.statusBar().showMessage) ## syncMgr.syncError.connect(self.statusBar().showMessage) @@ -279,6 +264,7 @@ WebBrowserWindow.BrowserWindows.append(self) + # TODO: AdBlock ## self.__adBlockIcon = AdBlockIcon(self) ## self.statusBar().addPermanentWidget(self.__adBlockIcon) ## self.__adBlockIcon.setEnabled( @@ -288,9 +274,9 @@ ## self.__tabWidget.sourceChanged.connect( ## self.__adBlockIcon.sourceChanged) ## -## self.networkIcon = E5NetworkIcon(self) -## self.statusBar().addPermanentWidget(self.networkIcon) -## + self.networkIcon = E5NetworkIcon(self) + self.statusBar().addPermanentWidget(self.networkIcon) + QDesktopServices.setUrlHandler("http", self.__linkActivated) QDesktopServices.setUrlHandler("https", self.__linkActivated) @@ -317,21 +303,22 @@ state = Preferences.getWebBrowser("WebBrowserState") self.restoreState(state) + # TODO: QtHelp ## self.__initHelpDb() -## self.__virusTotal = VirusTotalAPI(self) -## self.__virusTotal.submitUrlError.connect( -## self.__virusTotalSubmitUrlError) -## self.__virusTotal.urlScanReport.connect( -## self.__virusTotalUrlScanReport) -## self.__virusTotal.fileScanReport.connect( -## self.__virusTotalFileScanReport) -## + self.__virusTotal = VirusTotalAPI(self) + self.__virusTotal.submitUrlError.connect( + self.__virusTotalSubmitUrlError) + self.__virusTotal.urlScanReport.connect( + self.__virusTotalUrlScanReport) + self.__virusTotal.fileScanReport.connect( + self.__virusTotalFileScanReport) + self.__previewer = None self.__shutdownCalled = False -## self.flashCookieManager() -## + self.flashCookieManager() + # TODO: QtHelp, do these once Qt 5.6 is available ## if WebBrowserWindow.UseQtHelp: ## QTimer.singleShot(0, self.__lookForNewDocumentation) @@ -341,6 +328,7 @@ self.__lastActiveWindow = None e5App().focusChanged[QWidget, QWidget].connect( self.__appFocusChanged) + #TODO: Sync ## ## QTimer.singleShot(0, syncMgr.loadSettings) @@ -386,6 +374,7 @@ """ standardFont = Preferences.getWebBrowser("StandardFont") fixedFont = Preferences.getWebBrowser("FixedFont") + # TODO: Fonts: add support for other font types settings = QWebEngineSettings.globalSettings() ## settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True) @@ -578,6 +567,7 @@ if not self.__initShortcutsOnly: self.openTabAct.triggered.connect(self.__openFileNewTab) self.__actions.append(self.openTabAct) + # TODO: Save ## ## self.saveAsAct = E5Action( ## self.tr('Save As'), @@ -1386,7 +1376,7 @@ self.__showFeaturePermissionDialog) self.__actions.append(self.featurePermissionAct) - # TODO: re-enable once Qt 5.6 is available + # TODO: QtHelp: re-enable once Qt 5.6 is available ## if WebBrowserWindow.UseQtHelp or self.__initShortcutsOnly: ## self.syncTocAct = E5Action( ## self.tr('Sync with Table of Contents'), @@ -1883,6 +1873,7 @@ ## menu.addAction(self.userAgentManagerAct) ## menu.addSeparator() + # TODO: QtHelp ## if WebBrowserWindow.UseQtHelp: ## menu.addAction(self.manageQtHelpDocsAct) ## menu.addAction(self.manageQtHelpFiltersAct) @@ -1891,8 +1882,8 @@ menu.addAction(self.clearPrivateDataAct) menu.addAction(self.clearIconsAct) -## menu = mb.addMenu(self.tr("&Tools")) -## menu.setTearOffEnabled(True) + menu = mb.addMenu(self.tr("&Tools")) + menu.setTearOffEnabled(True) ## menu.addAction(self.feedsManagerAct) ## menu.addAction(self.siteInfoAct) ## menu.addSeparator() @@ -1975,6 +1966,7 @@ findtb.addAction(self.findNextAct) findtb.addAction(self.findPrevAct) + # TODO: QtHelp ## if WebBrowserWindow.UseQtHelp: ## filtertb = self.addToolBar(self.tr("Filter")) ## filtertb.setObjectName("FilterToolBar") @@ -2000,9 +1992,9 @@ ## settingstb.addAction(self.greaseMonkeyAct) settingstb.addAction(self.featurePermissionAct) -## toolstb = self.addToolBar(self.tr("Tools")) -## toolstb.setObjectName("ToolsToolBar") -## toolstb.setIconSize(UI.Config.ToolBarIconSize) + toolstb = self.addToolBar(self.tr("Tools")) + toolstb.setObjectName("ToolsToolBar") + toolstb.setIconSize(UI.Config.ToolBarIconSize) ## toolstb.addAction(self.feedsManagerAct) ## toolstb.addAction(self.siteInfoAct) ## toolstb.addSeparator() @@ -2067,28 +2059,28 @@ self.addToolBarBreak() self.addToolBar(self.bookmarksToolBar) -## self.addToolBarBreak() -## vttb = self.addToolBar(self.tr("VirusTotal")) -## vttb.setObjectName("VirusTotalToolBar") -## vttb.setIconSize(UI.Config.ToolBarIconSize) -## vttb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) -## self.virustotalScanCurrentAct = vttb.addAction( -## UI.PixmapCache.getIcon("virustotal.png"), -## self.tr("Scan current site"), -## self.__virusTotalScanCurrentSite) -## self.virustotalIpReportAct = vttb.addAction( -## UI.PixmapCache.getIcon("virustotal.png"), -## self.tr("IP Address Report"), -## self.__virusTotalIpAddressReport) -## self.virustotalDomainReportAct = vttb.addAction( -## UI.PixmapCache.getIcon("virustotal.png"), -## self.tr("Domain Report"), -## self.__virusTotalDomainReport) -## if not Preferences.getWebBrowser("VirusTotalEnabled") or \ -## Preferences.getWebBrowser("VirusTotalServiceKey") == "": -## self.virustotalScanCurrentAct.setEnabled(False) -## self.virustotalIpReportAct.setEnabled(False) -## self.virustotalDomainReportAct.setEnabled(False) + self.addToolBarBreak() + vttb = self.addToolBar(self.tr("VirusTotal")) + vttb.setObjectName("VirusTotalToolBar") + vttb.setIconSize(UI.Config.ToolBarIconSize) + vttb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) + self.virustotalScanCurrentAct = vttb.addAction( + UI.PixmapCache.getIcon("virustotal.png"), + self.tr("Scan current site"), + self.__virusTotalScanCurrentSite) + self.virustotalIpReportAct = vttb.addAction( + UI.PixmapCache.getIcon("virustotal.png"), + self.tr("IP Address Report"), + self.__virusTotalIpAddressReport) + self.virustotalDomainReportAct = vttb.addAction( + UI.PixmapCache.getIcon("virustotal.png"), + self.tr("Domain Report"), + self.__virusTotalDomainReport) + if not Preferences.getWebBrowser("VirusTotalEnabled") or \ + Preferences.getWebBrowser("VirusTotalServiceKey") == "": + self.virustotalScanCurrentAct.setEnabled(False) + self.virustotalIpReportAct.setEnabled(False) + self.virustotalDomainReportAct.setEnabled(False) def __nextTab(self): """ @@ -2480,8 +2472,8 @@ self.bookmarksToolBar.setModel(None) self.bookmarksManager().close() -## self.historyManager().close() -## + self.historyManager().close() + self.passwordManager().close() ## self.adBlockManager().close() @@ -2495,13 +2487,14 @@ ZoomManager.instance().close() WebIconProvider.instance().close() -## -## self.__virusTotal.close() -## -## self.flashCookieManager().shutdown() -## + + self.__virusTotal.close() + + self.flashCookieManager().shutdown() + self.searchEdit.openSearchManager().close() + # TODO: QtHelp ## if WebBrowserWindow.UseQtHelp: ## self.__searchEngine.cancelIndexing() ## self.__searchEngine.cancelSearching() @@ -2669,6 +2662,7 @@ Private slot to handle the select all action. """ self.currentBrowser().selectAll() + # TODO: Private Browsing ## ## def __privateBrowsing(self): ## """ @@ -2803,17 +2797,16 @@ self.searchEdit.preferencesChanged() - # TODO: VirusTotal -## self.__virusTotal.preferencesChanged() -## if not Preferences.getWebBrowser("VirusTotalEnabled") or \ -## Preferences.getWebBrowser("VirusTotalServiceKey") == "": -## self.virustotalScanCurrentAct.setEnabled(False) -## self.virustotalIpReportAct.setEnabled(False) -## self.virustotalDomainReportAct.setEnabled(False) -## else: -## self.virustotalScanCurrentAct.setEnabled(True) -## self.virustotalIpReportAct.setEnabled(True) -## self.virustotalDomainReportAct.setEnabled(True) + self.__virusTotal.preferencesChanged() + if not Preferences.getWebBrowser("VirusTotalEnabled") or \ + Preferences.getWebBrowser("VirusTotalServiceKey") == "": + self.virustotalScanCurrentAct.setEnabled(False) + self.virustotalIpReportAct.setEnabled(False) + self.virustotalDomainReportAct.setEnabled(False) + else: + self.virustotalScanCurrentAct.setEnabled(True) + self.virustotalIpReportAct.setEnabled(True) + self.virustotalDomainReportAct.setEnabled(True) def masterPasswordChanged(self, oldPassword, newPassword): """ @@ -2876,6 +2869,7 @@ else: cls.useQtHelp = False + # TODO: QtHelp ## @classmethod ## def helpEngine(cls): ## """ @@ -2938,6 +2932,7 @@ self.currentBrowser().setUrl(url) self.__activating = False + # TODO: QtHelp ## def __linksActivated(self, links, keyword): ## """ ## Private slot to select a topic to be shown. @@ -2960,6 +2955,7 @@ """ self.currentBrowser().setFocus() + # TODO: QtHelp ## def __syncTOC(self): ## """ ## Private slot to synchronize the TOC with the currently shown page. @@ -3771,7 +3767,8 @@ self.currentBrowser().triggerPageAction(QWebEnginePage.Forward) else: super(WebBrowserWindow, self).mousePressEvent(evt) - + + # TODO: RSS ## @classmethod ## def feedsManager(cls): ## """ @@ -3804,6 +3801,7 @@ ## feedsManager.newUrl.disconnect(self.openUrlNewTab) ## feedsManager.rejected.disconnect(self.__feedsManagerClosed) ## + # TODO: Site Info ## def __showSiteinfoDialog(self): ## """ ## Private slot to show the site info dialog. @@ -3812,6 +3810,7 @@ ## self.__siteinfoDialog = SiteInfoDialog(self.currentBrowser(), self) ## self.__siteinfoDialog.show() ## + # TODO: User Agents ## @classmethod ## def userAgentsManager(cls): ## """ @@ -3834,6 +3833,7 @@ ## dlg = UserAgentsDialog(self) ## dlg.exec_() ## + # TODO: Sync ## @classmethod ## def syncManager(cls): ## """ @@ -3853,6 +3853,7 @@ ## """ ## self.syncManager().showSyncDialog() ## + # TODO: SpeedDial ## @classmethod ## def speedDial(cls): ## """ @@ -3902,6 +3903,7 @@ number = self.__tabWidget.count() self.__tabWidget.setCurrentIndex(number - 1) return + # TODO: SpeeedDial ## ## if evt.modifiers() == Qt.KeyboardModifiers(Qt.MetaModifier): ## url = self.speedDial().urlForShortcut(number - 1) @@ -3911,87 +3913,87 @@ super(WebBrowserWindow, self).keyPressEvent(evt) -## ########################################################################### -## ## Interface to VirusTotal below ## -## ########################################################################### -## -## def __virusTotalScanCurrentSite(self): -## """ -## Private slot to ask VirusTotal for a scan of the URL of the current -## browser. -## """ -## cb = self.currentBrowser() -## if cb is not None: -## url = cb.url() -## if url.scheme() in ["http", "https", "ftp"]: -## self.requestVirusTotalScan(url) -## -## def requestVirusTotalScan(self, url): -## """ -## Public method to submit a request to scan an URL by VirusTotal. -## -## @param url URL to be scanned (QUrl) -## """ -## self.__virusTotal.submitUrl(url) -## -## def __virusTotalSubmitUrlError(self, msg): -## """ -## Private slot to handle an URL scan submission error. -## -## @param msg error message (str) -## """ -## E5MessageBox.critical( -## self, -## self.tr("VirusTotal Scan"), -## self.tr("""<p>The VirusTotal scan could not be""" -## """ scheduled.<p>\n<p>Reason: {0}</p>""").format(msg)) -## -## def __virusTotalUrlScanReport(self, url): -## """ -## Private slot to initiate the display of the URL scan report page. -## -## @param url URL of the URL scan report page (string) -## """ -## self.newTab(url) -## -## def __virusTotalFileScanReport(self, url): -## """ -## Private slot to initiate the display of the file scan report page. -## -## @param url URL of the file scan report page (string) -## """ -## self.newTab(url) -## -## def __virusTotalIpAddressReport(self): -## """ -## Private slot to retrieve an IP address report. -## """ -## ip, ok = QInputDialog.getText( -## self, -## self.tr("IP Address Report"), -## self.tr("Enter a valid IPv4 address in dotted quad notation:"), -## QLineEdit.Normal) -## if ok and ip: -## if ip.count(".") == 3: -## self.__virusTotal.getIpAddressReport(ip) -## else: -## E5MessageBox.information( -## self, -## self.tr("IP Address Report"), -## self.tr("""The given IP address is not in dotted quad""" -## """ notation.""")) -## -## def __virusTotalDomainReport(self): -## """ -## Private slot to retrieve a domain report. -## """ -## domain, ok = QInputDialog.getText( -## self, -## self.tr("Domain Report"), -## self.tr("Enter a valid domain name:"), -## QLineEdit.Normal) -## if ok and domain: -## self.__virusTotal.getDomainReport(domain) + ########################################################################### + ## Interface to VirusTotal below ## + ########################################################################### + + def __virusTotalScanCurrentSite(self): + """ + Private slot to ask VirusTotal for a scan of the URL of the current + browser. + """ + cb = self.currentBrowser() + if cb is not None: + url = cb.url() + if url.scheme() in ["http", "https", "ftp"]: + self.requestVirusTotalScan(url) + + def requestVirusTotalScan(self, url): + """ + Public method to submit a request to scan an URL by VirusTotal. + + @param url URL to be scanned (QUrl) + """ + self.__virusTotal.submitUrl(url) + + def __virusTotalSubmitUrlError(self, msg): + """ + Private slot to handle an URL scan submission error. + + @param msg error message (str) + """ + E5MessageBox.critical( + self, + self.tr("VirusTotal Scan"), + self.tr("""<p>The VirusTotal scan could not be""" + """ scheduled.<p>\n<p>Reason: {0}</p>""").format(msg)) + + def __virusTotalUrlScanReport(self, url): + """ + Private slot to initiate the display of the URL scan report page. + + @param url URL of the URL scan report page (string) + """ + self.newTab(url) + + def __virusTotalFileScanReport(self, url): + """ + Private slot to initiate the display of the file scan report page. + + @param url URL of the file scan report page (string) + """ + self.newTab(url) + + def __virusTotalIpAddressReport(self): + """ + Private slot to retrieve an IP address report. + """ + ip, ok = QInputDialog.getText( + self, + self.tr("IP Address Report"), + self.tr("Enter a valid IPv4 address in dotted quad notation:"), + QLineEdit.Normal) + if ok and ip: + if ip.count(".") == 3: + self.__virusTotal.getIpAddressReport(ip) + else: + E5MessageBox.information( + self, + self.tr("IP Address Report"), + self.tr("""The given IP address is not in dotted quad""" + """ notation.""")) + + def __virusTotalDomainReport(self): + """ + Private slot to retrieve a domain report. + """ + domain, ok = QInputDialog.getText( + self, + self.tr("Domain Report"), + self.tr("Enter a valid domain name:"), + QLineEdit.Normal) + if ok and domain: + self.__virusTotal.getDomainReport(domain) ########################################################################### ## Style sheet handling below ##
--- a/eric6.e4p Sat Feb 20 12:26:28 2016 +0100 +++ b/eric6.e4p Sat Feb 20 14:34:32 2016 +0100 @@ -1348,6 +1348,11 @@ <Source>WebBrowser/UrlBar/StackedUrlBar.py</Source> <Source>WebBrowser/UrlBar/UrlBar.py</Source> <Source>WebBrowser/UrlBar/__init__.py</Source> + <Source>WebBrowser/VirusTotal/VirusTotalApi.py</Source> + <Source>WebBrowser/VirusTotal/VirusTotalDomainReportDialog.py</Source> + <Source>WebBrowser/VirusTotal/VirusTotalIpReportDialog.py</Source> + <Source>WebBrowser/VirusTotal/VirusTotalWhoisDialog.py</Source> + <Source>WebBrowser/VirusTotal/__init__.py</Source> <Source>WebBrowser/WebBrowserClearPrivateDataDialog.py</Source> <Source>WebBrowser/WebBrowserPage.py</Source> <Source>WebBrowser/WebBrowserTabBar.py</Source> @@ -1772,6 +1777,9 @@ <Form>WebBrowser/SearchWidget.ui</Form> <Form>WebBrowser/UrlBar/BookmarkActionSelectionDialog.ui</Form> <Form>WebBrowser/UrlBar/BookmarkInfoDialog.ui</Form> + <Form>WebBrowser/VirusTotal/VirusTotalDomainReportDialog.ui</Form> + <Form>WebBrowser/VirusTotal/VirusTotalIpReportDialog.ui</Form> + <Form>WebBrowser/VirusTotal/VirusTotalWhoisDialog.ui</Form> <Form>WebBrowser/WebBrowserClearPrivateDataDialog.ui</Form> <Form>WebBrowser/ZoomManager/ZoomValuesDialog.ui</Form> </Forms>