19 QUrl, QThread, QTextCodec |
19 QUrl, QThread, QTextCodec |
20 from PyQt5.QtGui import QDesktopServices, QKeySequence, QFont, QFontMetrics, \ |
20 from PyQt5.QtGui import QDesktopServices, QKeySequence, QFont, QFontMetrics, \ |
21 QIcon |
21 QIcon |
22 from PyQt5.QtWidgets import QWidget, QVBoxLayout, QSizePolicy, QDockWidget, \ |
22 from PyQt5.QtWidgets import QWidget, QVBoxLayout, QSizePolicy, QDockWidget, \ |
23 QComboBox, QLabel, QSplitter, QMenu, QToolButton, QLineEdit, \ |
23 QComboBox, QLabel, QSplitter, QMenu, QToolButton, QLineEdit, \ |
24 QApplication, QWhatsThis, QDialog, QHBoxLayout, QProgressBar, QAction |
24 QApplication, QWhatsThis, QDialog, QHBoxLayout, QProgressBar, QAction, \ |
|
25 QInputDialog |
25 from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest |
26 from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest |
26 from PyQt5.QtWebKit import QWebSettings, QWebDatabase, QWebSecurityOrigin |
27 from PyQt5.QtWebKit import QWebSettings, QWebDatabase, QWebSecurityOrigin |
27 from PyQt5.QtWebKitWidgets import QWebPage |
28 from PyQt5.QtWebKitWidgets import QWebPage |
28 try: |
29 try: |
29 from PyQt5.QtHelp import QHelpEngine, QHelpEngineCore, QHelpSearchQuery |
30 from PyQt5.QtHelp import QHelpEngine, QHelpEngineCore, QHelpSearchQuery |
1831 self.addToolBarBreak() |
1832 self.addToolBarBreak() |
1832 vttb = self.addToolBar(self.tr("VirusTotal")) |
1833 vttb = self.addToolBar(self.tr("VirusTotal")) |
1833 vttb.setObjectName("VirusTotalToolBar") |
1834 vttb.setObjectName("VirusTotalToolBar") |
1834 vttb.setIconSize(UI.Config.ToolBarIconSize) |
1835 vttb.setIconSize(UI.Config.ToolBarIconSize) |
1835 vttb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) |
1836 vttb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) |
1836 self.virustotalSearchEdit = QLineEdit() |
|
1837 self.virustotalSearchEdit.setMaximumWidth(250) |
|
1838 self.virustotalSearchEdit.setWhatsThis(self.tr( |
|
1839 """<h2>File search</h2>""" |
|
1840 """<p>In order to search for the last VirusTotal report on a""" |
|
1841 """ given file just enter its hash. Currently the allowed""" |
|
1842 """ hashes are MD5, SHA1 and SHA256. You can also search for""" |
|
1843 """ a particular file report by typing in its permalink id.</p>""" |
|
1844 """<h2>URL search</h2>""" |
|
1845 """<p>URL searches are simple, just type in the given URL, the""" |
|
1846 """ application will normalize it and compare it with the""" |
|
1847 """ entries in VirusTotal's database. Alternatively you may""" |
|
1848 """ enter the MD5 hash of an URL preceded by "url:", e.g.""" |
|
1849 """ url:7f911bbcf618f052ac6b9928600d2820.</p>""" |
|
1850 """<h2>User search</h2>""" |
|
1851 """<p>Do you want to know whether a friend has a VT Community""" |
|
1852 """ account? Simply type in his nick preceded by the symbol""" |
|
1853 """ "@", e.g. @EmilianoMartinez.</p>""" |
|
1854 """<h2>Search through comments</h2>""" |
|
1855 """<p>The comments in VT Community may often help in""" |
|
1856 """ disinfecting your PC or may proof themselves useful when""" |
|
1857 """ analysing a particular malware sample, comment tags enable""" |
|
1858 """ users to search through the VT Community reviews. The""" |
|
1859 """ standard file tags are: {0} The standard URL tags are: {1}""" |
|
1860 """User generated tags are preceded by the symbol "#", e.g.""" |
|
1861 """ #disinfect.</p>""" |
|
1862 ).format( |
|
1863 """<ul>""" |
|
1864 """<li>goodware</li>""" |
|
1865 """<li>malware</li>""" |
|
1866 """<li>spamattachmentorlink</li>""" |
|
1867 """<li>p2pdownload</li>""" |
|
1868 """<li>impropagating</li>""" |
|
1869 """<li>networkworm</li>""" |
|
1870 """<li>drivebydownload</li>""" |
|
1871 """</ul>""", |
|
1872 """<ul>""" |
|
1873 """<li>malicious</li>""" |
|
1874 """<li>benign</li>""" |
|
1875 """<li>malewaredownload</li>""" |
|
1876 """<li>phishingsite</li>""" |
|
1877 """<li>browserexploit</li>""" |
|
1878 """<li>spamlink</li>""" |
|
1879 """</ul>""", |
|
1880 )) |
|
1881 self.virustotalSearchEdit.textChanged.connect( |
|
1882 self.__virusTotalSearchChanged) |
|
1883 self.virustotalSearchEdit.returnPressed.connect( |
|
1884 self.__virusTotalSearch) |
|
1885 vttb.addWidget(self.virustotalSearchEdit) |
|
1886 self.virustotalSearchAct = vttb.addAction( |
|
1887 UI.PixmapCache.getIcon("virustotal.png"), |
|
1888 self.tr("Search VirusTotal"), |
|
1889 self.__virusTotalSearch) |
|
1890 self.virustotalSearchAct.setEnabled(False) |
|
1891 vttb.addSeparator() |
|
1892 self.virustotalScanCurrentAct = vttb.addAction( |
1837 self.virustotalScanCurrentAct = vttb.addAction( |
1893 UI.PixmapCache.getIcon("virustotal.png"), |
1838 UI.PixmapCache.getIcon("virustotal.png"), |
1894 self.tr("Scan current site"), |
1839 self.tr("Scan current site"), |
1895 self.__virusTotalScanCurrentSite) |
1840 self.__virusTotalScanCurrentSite) |
|
1841 self.virustotalIpReportAct = vttb.addAction( |
|
1842 UI.PixmapCache.getIcon("virustotal.png"), |
|
1843 self.tr("IP Address Report"), |
|
1844 self.__virusTotalIpAddressReport) |
|
1845 self.virustotalDomainReportAct = vttb.addAction( |
|
1846 UI.PixmapCache.getIcon("virustotal.png"), |
|
1847 self.tr("Domain Report"), |
|
1848 self.__virusTotalDomainReport) |
1896 if not Preferences.getHelp("VirusTotalEnabled") or \ |
1849 if not Preferences.getHelp("VirusTotalEnabled") or \ |
1897 Preferences.getHelp("VirusTotalServiceKey") == "": |
1850 Preferences.getHelp("VirusTotalServiceKey") == "": |
1898 self.virustotalSearchEdit.setEnabled(False) |
|
1899 self.virustotalScanCurrentAct.setEnabled(False) |
1851 self.virustotalScanCurrentAct.setEnabled(False) |
|
1852 self.virustotalIpReportAct.setEnabled(False) |
|
1853 self.virustotalDomainReportAct.setEnabled(False) |
1900 |
1854 |
1901 def __nextTab(self): |
1855 def __nextTab(self): |
1902 """ |
1856 """ |
1903 Private slot used to show the next tab. |
1857 Private slot used to show the next tab. |
1904 """ |
1858 """ |
2512 self.searchEdit.preferencesChanged() |
2468 self.searchEdit.preferencesChanged() |
2513 |
2469 |
2514 self.__virusTotal.preferencesChanged() |
2470 self.__virusTotal.preferencesChanged() |
2515 if not Preferences.getHelp("VirusTotalEnabled") or \ |
2471 if not Preferences.getHelp("VirusTotalEnabled") or \ |
2516 Preferences.getHelp("VirusTotalServiceKey") == "": |
2472 Preferences.getHelp("VirusTotalServiceKey") == "": |
2517 self.virustotalSearchEdit.setEnabled(False) |
|
2518 self.virustotalScanCurrentAct.setEnabled(False) |
2473 self.virustotalScanCurrentAct.setEnabled(False) |
|
2474 self.virustotalIpReportAct.setEnabled(False) |
|
2475 self.virustotalDomainReportAct.setEnabled(False) |
2519 else: |
2476 else: |
2520 self.virustotalSearchEdit.setEnabled(True) |
|
2521 self.virustotalScanCurrentAct.setEnabled(True) |
2477 self.virustotalScanCurrentAct.setEnabled(True) |
2522 self.__virusTotalSearchChanged(self.virustotalSearchEdit.text()) |
2478 self.virustotalIpReportAct.setEnabled(True) |
|
2479 self.virustotalDomainReportAct.setEnabled(True) |
2523 |
2480 |
2524 def masterPasswordChanged(self, oldPassword, newPassword): |
2481 def masterPasswordChanged(self, oldPassword, newPassword): |
2525 """ |
2482 """ |
2526 Public slot to handle the change of the master password. |
2483 Public slot to handle the change of the master password. |
2527 |
2484 |
3586 |
3543 |
3587 ########################################################################### |
3544 ########################################################################### |
3588 ## Interface to VirusTotal below ## |
3545 ## Interface to VirusTotal below ## |
3589 ########################################################################### |
3546 ########################################################################### |
3590 |
3547 |
3591 def __virusTotalSearchChanged(self, txt): |
3548 ## def __virusTotalSearchChanged(self, txt): |
3592 """ |
3549 ## """ |
3593 Private slot to react upon changes of the VirusTotal search text. |
3550 ## Private slot to react upon changes of the VirusTotal search text. |
3594 |
3551 ## |
3595 @param txt contents of the search (string) |
3552 ## @param txt contents of the search (string) |
3596 """ |
3553 ## """ |
3597 self.virustotalSearchAct.setEnabled( |
3554 ## self.virustotalSearchAct.setEnabled( |
3598 txt != "" and |
3555 ## txt != "" and |
3599 Preferences.getHelp("VirusTotalEnabled") and |
3556 ## Preferences.getHelp("VirusTotalEnabled") and |
3600 Preferences.getHelp("VirusTotalServiceKey") != "") |
3557 ## Preferences.getHelp("VirusTotalServiceKey") != "") |
3601 |
3558 ## |
3602 def __virusTotalSearch(self): |
3559 ## def __virusTotalSearch(self): |
3603 """ |
3560 ## """ |
3604 Private slot to search VirusTotal for a given entry. |
3561 ## Private slot to search VirusTotal for a given entry. |
3605 """ |
3562 ## """ |
3606 search = self.virustotalSearchEdit.text() |
3563 ## search = self.virustotalSearchEdit.text() |
3607 if search: |
3564 ## if search: |
3608 from .VirusTotalApi import VirusTotalAPI |
3565 ## from .VirusTotalApi import VirusTotalAPI |
3609 requestData = VirusTotalAPI.getSearchRequestData(search) |
3566 ## requestData = VirusTotalAPI.getSearchRequestData(search) |
3610 self.newTab(requestData=requestData) |
3567 ## self.newTab(requestData=requestData) |
3611 |
3568 ## |
3612 def __virusTotalScanCurrentSite(self): |
3569 def __virusTotalScanCurrentSite(self): |
3613 """ |
3570 """ |
3614 Private slot to ask VirusTotal for a scan of the URL of the current |
3571 Private slot to ask VirusTotal for a scan of the URL of the current |
3615 browser. |
3572 browser. |
3616 """ |
3573 """ |
3653 Private slot to initiate the display of the file scan report page. |
3610 Private slot to initiate the display of the file scan report page. |
3654 |
3611 |
3655 @param url URL of the file scan report page (string) |
3612 @param url URL of the file scan report page (string) |
3656 """ |
3613 """ |
3657 self.newTab(url) |
3614 self.newTab(url) |
|
3615 |
|
3616 def __virusTotalIpAddressReport(self): |
|
3617 """ |
|
3618 Private slot to retrieve an IP address report. |
|
3619 """ |
|
3620 ip, ok = QInputDialog.getText( |
|
3621 self, |
|
3622 self.tr("IP Address Report"), |
|
3623 self.tr("Enter a valid IPv4 address in dotted quad notation:"), |
|
3624 QLineEdit.Normal) |
|
3625 if ok and ip: |
|
3626 if ip.count(".") == 3: |
|
3627 self.__virusTotal.getIpAddressReport(ip) |
|
3628 else: |
|
3629 E5MessageBox.information( |
|
3630 self, |
|
3631 self.tr("IP Address Report"), |
|
3632 self.tr("""The given IP address is not in dotted quad""" |
|
3633 """ notation.""")) |
|
3634 |
|
3635 def __virusTotalDomainReport(self): |
|
3636 """ |
|
3637 Private slot to retrieve a domain report. |
|
3638 """ |
|
3639 domain, ok = QInputDialog.getText( |
|
3640 self, |
|
3641 self.tr("Domain Report"), |
|
3642 self.tr("Enter a valid domain name:"), |
|
3643 QLineEdit.Normal) |
|
3644 if ok and domain: |
|
3645 self.__virusTotal.getDomainReport(domain) |
|
3646 |
|
3647 ########################################################################### |
|
3648 ## Style sheet handling below ## |
|
3649 ########################################################################### |
3658 |
3650 |
3659 def reloadUserStyleSheet(self): |
3651 def reloadUserStyleSheet(self): |
3660 """ |
3652 """ |
3661 Public method to reload the user style sheet. |
3653 Public method to reload the user style sheet. |
3662 """ |
3654 """ |