Helpviewer/VirusTotalApi.py

Sun, 10 Apr 2011 18:33:20 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 10 Apr 2011 18:33:20 +0200
changeset 978
11f8adbcac97
child 979
0ae0c8852d31
permissions
-rw-r--r--

Added an interface to VirusTotal to the web browser.

# -*- coding: utf-8 -*-

# Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the <a href="http://www.virustotal.com">VirusTotal</a> API class.
"""

import json

from PyQt4.QtCore import QObject, QUrl, QByteArray, QCoreApplication, QThread
from PyQt4.QtNetwork import QNetworkRequest, QNetworkReply, QNetworkAccessManager

import Helpviewer.HelpWindow

import Preferences

class VirusTotalAPI(QObject):
    """
    Class implementing the <a href="http://www.virustotal.com">VirusTotal</a> API.
    """
    TestServiceKeyScanID = \
        "4feed2c2e352f105f6188efd1d5a558f24aee6971bdf96d5fdb19c197d6d3fad"
    
    ServiceResult_RequestLimitReached = -2
    ServiceResult_InvalidServiceKey = -1
    ServiceResult_ItemNotPresent = 0
    ServiceResult_ItemPresent = 1
    
    GetFileReportPattern = "{0}://www.virustotal.com/api/get_file_report.json"
    ScanUrlPattern = "{0}://www.virustotal.com/api/scan_url.json"
    GetUrlReportPattern = "{0}://www.virustotal.com/api/get_url_report.json"
    
    ReportUrlScanPagePattern = "http://www.virustotal.com/url-scan/report.html?id={0}"
    ReportFileScanPagePattern = "http://www.virustotal.com/file-scan/report.html?id={0}"
    
    SearchUrl = "http://www.virustotal.com/search.html"
    
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent object (QObject)
        """
        QObject.__init__(self, parent)
        
        self.__loadSettings()
    
    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.errorMessages = {
            -2: self.trUtf8("Request limit has been reached."),
            -1: self.trUtf8("Invalid key given."),
             0: self.trUtf8("Requested item is not present.")
        }
    
    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)
        @return flag indicating validity (boolean) and an error message in
            case of a network error (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("key={0}&resource={1}".format(
            key, self.TestServiceKeyScanID))
        
        nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager()
        reply = nam.post(request, params)
        while not reply.isFinished():
            QCoreApplication.processEvents()
            QThread.msleep(100)
            if QCoreApplication.closingDown():
                reply.abort()
            QCoreApplication.processEvents()
        if reply.error() == QNetworkReply.NoError:
            result = json.loads(str(reply.readAll(), "utf-8"))
            if result["result"] != self.ServiceResult_InvalidServiceKey:
                return True, ""
            else:
                return False, ""
        
        return False, reply.errorString()
    
    def submitUrl(self, url):
        """
        Public method to submit an URL to be scanned.
        
        @param url url to be scanned (QUrl)
        @return flag indicating success (boolean) and the scan ID (string)
        """
        request = QNetworkRequest(QUrl(self.ScanUrlUrl))
        request.setHeader(QNetworkRequest.ContentTypeHeader,
                          "application/x-www-form-urlencoded")
        params = QByteArray(
            "key={0}&url=".format(Preferences.getHelp("VirusTotalServiceKey")))\
            .append(QUrl.toPercentEncoding(url.toString()))
        
        nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager()
        reply = nam.post(request, params)
        while not reply.isFinished():
            QCoreApplication.processEvents()
            QThread.msleep(100)
            if QCoreApplication.closingDown():
                reply.abort()
            QCoreApplication.processEvents()
        if reply.error() == QNetworkReply.NoError:
            result = json.loads(str(reply.readAll(), "utf-8"))
            if result["result"] == self.ServiceResult_ItemPresent:
                return True, result["scan_id"]
            else:
                return False, self.errorMessages[result["result"]]
        
        return False, reply.errorString()
    
    def getUrlScanReportUrl(self, scanId):
        """
        Public method to get the report URL for a URL scan.
        
        @param scanId ID of the scan to get the report URL for (string)
        @return URL scan report URL (string)
        """
        return self.ReportUrlScanPagePattern.format(scanId)
        
    def getFileScanReportUrl(self, scanId):
        """
        Public method to get the report URL for a file scan.
        
        @param scanId ID of the scan to get the report URL for (string)
        @return file scan report URL (string)
        """
        fileScanPageUrl = ""    # default value
        
        request = QNetworkRequest(QUrl(self.GetUrlReportUrl))
        request.setHeader(QNetworkRequest.ContentTypeHeader,
                          "application/x-www-form-urlencoded")
        params = QByteArray("key={0}&resource={1}".format(
            Preferences.getHelp("VirusTotalServiceKey"), scanId))
        
        nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager()
        reply = nam.post(request, params)
        while not reply.isFinished():
            QCoreApplication.processEvents()
            QThread.msleep(100)
            if QCoreApplication.closingDown():
                reply.abort()
            QCoreApplication.processEvents()
        if reply.error() == QNetworkReply.NoError:
            result = json.loads(str(reply.readAll(), "utf-8"))
            if "file-report" in result:
                fileScanPageUrl = self.ReportFileScanPagePattern.format(
                    result["file-report"])
        
        return fileScanPageUrl
    
    @classmethod
    def getSearchRequestData(cls, term):
        """
        
        """
        request = QNetworkRequest(QUrl(cls.SearchUrl))
        request.setHeader(QNetworkRequest.ContentTypeHeader,
                          "application/x-www-form-urlencoded")
        op = QNetworkAccessManager.PostOperation
        params = QByteArray("chain=").append(QUrl.toPercentEncoding(term))
        
        return (request, op, params)

eric ide

mercurial