Helpviewer/VirusTotalApi.py

changeset 979
0ae0c8852d31
parent 978
11f8adbcac97
child 992
566e87428fc8
equal deleted inserted replaced
978:11f8adbcac97 979:0ae0c8852d31
7 Module implementing the <a href="http://www.virustotal.com">VirusTotal</a> API class. 7 Module implementing the <a href="http://www.virustotal.com">VirusTotal</a> API class.
8 """ 8 """
9 9
10 import json 10 import json
11 11
12 from PyQt4.QtCore import QObject, QUrl, QByteArray, QCoreApplication, QThread 12 from PyQt4.QtCore import QObject, QUrl, QByteArray, pyqtSignal
13 from PyQt4.QtNetwork import QNetworkRequest, QNetworkReply, QNetworkAccessManager 13 from PyQt4.QtNetwork import QNetworkRequest, QNetworkReply, QNetworkAccessManager
14 14
15 import Helpviewer.HelpWindow 15 import Helpviewer.HelpWindow
16 16
17 import Preferences 17 import Preferences
18 18
19 class VirusTotalAPI(QObject): 19 class VirusTotalAPI(QObject):
20 """ 20 """
21 Class implementing the <a href="http://www.virustotal.com">VirusTotal</a> API. 21 Class implementing the <a href="http://www.virustotal.com">VirusTotal</a> API.
22
23 @signal checkServiceKeyFinished(bool, str) emitted after the service key check
24 has been performed. It gives a flag indicating validity (boolean) and
25 an error message in case of a network error (string).
26 @signal submitUrlError(str) emitted with the error string, if the URL scan
27 submission returned an error.
28 @signal urlScanReport(str) emitted with the URL of the URL scan report page
29 @signal fileScanReport(str) emitted with the URL of the file scan report page
22 """ 30 """
31 checkServiceKeyFinished = pyqtSignal(bool, str)
32 submitUrlError = pyqtSignal(str)
33 urlScanReport = pyqtSignal(str)
34 fileScanReport = pyqtSignal(str)
35
23 TestServiceKeyScanID = \ 36 TestServiceKeyScanID = \
24 "4feed2c2e352f105f6188efd1d5a558f24aee6971bdf96d5fdb19c197d6d3fad" 37 "4feed2c2e352f105f6188efd1d5a558f24aee6971bdf96d5fdb19c197d6d3fad"
25 38
26 ServiceResult_RequestLimitReached = -2 39 ServiceResult_RequestLimitReached = -2
27 ServiceResult_InvalidServiceKey = -1 40 ServiceResult_InvalidServiceKey = -1
42 Constructor 55 Constructor
43 56
44 @param parent reference to the parent object (QObject) 57 @param parent reference to the parent object (QObject)
45 """ 58 """
46 QObject.__init__(self, parent) 59 QObject.__init__(self, parent)
60
61 self.__replies = []
47 62
48 self.__loadSettings() 63 self.__loadSettings()
49 64
50 def __loadSettings(self): 65 def __loadSettings(self):
51 """ 66 """
63 -2: self.trUtf8("Request limit has been reached."), 78 -2: self.trUtf8("Request limit has been reached."),
64 -1: self.trUtf8("Invalid key given."), 79 -1: self.trUtf8("Invalid key given."),
65 0: self.trUtf8("Requested item is not present.") 80 0: self.trUtf8("Requested item is not present.")
66 } 81 }
67 82
83 def preferencesChanged(self):
84 """
85 Public slot to handle a change of preferences.
86 """
87 self.__loadSettings()
88
68 def checkServiceKeyValidity(self, key, protocol=""): 89 def checkServiceKeyValidity(self, key, protocol=""):
69 """ 90 """
70 Public method to check the validity of the given service key. 91 Public method to check the validity of the given service key.
71 92
72 @param key service key (string) 93 @param key service key (string)
84 params = QByteArray("key={0}&resource={1}".format( 105 params = QByteArray("key={0}&resource={1}".format(
85 key, self.TestServiceKeyScanID)) 106 key, self.TestServiceKeyScanID))
86 107
87 nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager() 108 nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager()
88 reply = nam.post(request, params) 109 reply = nam.post(request, params)
89 while not reply.isFinished(): 110 reply.finished.connect(self.__checkServiceKeyValidityFinished)
90 QCoreApplication.processEvents() 111 self.__replies.append(reply)
91 QThread.msleep(100) 112
92 if QCoreApplication.closingDown(): 113 def __checkServiceKeyValidityFinished(self):
93 reply.abort() 114 """
94 QCoreApplication.processEvents() 115 Private slot to determine the result of the service key validity check.
116 """
117 res = False
118 msg = ""
119
120 reply = self.sender()
95 if reply.error() == QNetworkReply.NoError: 121 if reply.error() == QNetworkReply.NoError:
96 result = json.loads(str(reply.readAll(), "utf-8")) 122 result = json.loads(str(reply.readAll(), "utf-8"))
97 if result["result"] != self.ServiceResult_InvalidServiceKey: 123 if result["result"] != self.ServiceResult_InvalidServiceKey:
98 return True, "" 124 res = True
99 else: 125 else:
100 return False, "" 126 msg = reply.errorString()
101 127 self.__replies.remove(reply)
102 return False, reply.errorString() 128
129 self.checkServiceKeyFinished.emit(res, msg)
103 130
104 def submitUrl(self, url): 131 def submitUrl(self, url):
105 """ 132 """
106 Public method to submit an URL to be scanned. 133 Public method to submit an URL to be scanned.
107 134
115 "key={0}&url=".format(Preferences.getHelp("VirusTotalServiceKey")))\ 142 "key={0}&url=".format(Preferences.getHelp("VirusTotalServiceKey")))\
116 .append(QUrl.toPercentEncoding(url.toString())) 143 .append(QUrl.toPercentEncoding(url.toString()))
117 144
118 nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager() 145 nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager()
119 reply = nam.post(request, params) 146 reply = nam.post(request, params)
120 while not reply.isFinished(): 147 reply.finished.connect(self.__submitUrlFinished)
121 QCoreApplication.processEvents() 148 self.__replies.append(reply)
122 QThread.msleep(100) 149
123 if QCoreApplication.closingDown(): 150 def __submitUrlFinished(self):
124 reply.abort() 151 """
125 QCoreApplication.processEvents() 152 Private slot to determine the result of the URL scan submission.
153 """
154 reply = self.sender()
126 if reply.error() == QNetworkReply.NoError: 155 if reply.error() == QNetworkReply.NoError:
127 result = json.loads(str(reply.readAll(), "utf-8")) 156 result = json.loads(str(reply.readAll(), "utf-8"))
128 if result["result"] == self.ServiceResult_ItemPresent: 157 if result["result"] == self.ServiceResult_ItemPresent:
129 return True, result["scan_id"] 158 self.urlScanReport.emit(
159 self.ReportUrlScanPagePattern.format(result["scan_id"]))
160 self.__getFileScanReportUrl(result["scan_id"])
130 else: 161 else:
131 return False, self.errorMessages[result["result"]] 162 self.submitUrlError.emit(self.errorMessages[result["result"]])
132 163 else:
133 return False, reply.errorString() 164 self.submitUrlError.emit(reply.errorString())
134 165 self.__replies.remove(reply)
135 def getUrlScanReportUrl(self, scanId): 166
136 """ 167 def __getFileScanReportUrl(self, scanId):
137 Public method to get the report URL for a URL scan. 168 """
138 169 Private method to get the report URL for a file scan.
139 @param scanId ID of the scan to get the report URL for (string)
140 @return URL scan report URL (string)
141 """
142 return self.ReportUrlScanPagePattern.format(scanId)
143
144 def getFileScanReportUrl(self, scanId):
145 """
146 Public method to get the report URL for a file scan.
147 170
148 @param scanId ID of the scan to get the report URL for (string) 171 @param scanId ID of the scan to get the report URL for (string)
149 @return file scan report URL (string) 172 @return file scan report URL (string)
150 """ 173 """
151 fileScanPageUrl = "" # default value
152
153 request = QNetworkRequest(QUrl(self.GetUrlReportUrl)) 174 request = QNetworkRequest(QUrl(self.GetUrlReportUrl))
154 request.setHeader(QNetworkRequest.ContentTypeHeader, 175 request.setHeader(QNetworkRequest.ContentTypeHeader,
155 "application/x-www-form-urlencoded") 176 "application/x-www-form-urlencoded")
156 params = QByteArray("key={0}&resource={1}".format( 177 params = QByteArray("key={0}&resource={1}".format(
157 Preferences.getHelp("VirusTotalServiceKey"), scanId)) 178 Preferences.getHelp("VirusTotalServiceKey"), scanId))
158 179
159 nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager() 180 nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager()
160 reply = nam.post(request, params) 181 reply = nam.post(request, params)
161 while not reply.isFinished(): 182 reply.finished.connect(self.__getFileScanReportUrlFinished)
162 QCoreApplication.processEvents() 183 self.__replies.append(reply)
163 QThread.msleep(100) 184
164 if QCoreApplication.closingDown(): 185 def __getFileScanReportUrlFinished(self):
165 reply.abort() 186 """
166 QCoreApplication.processEvents() 187 Private slot to determine the result of the file scan report URL request.
188 """
189 reply = self.sender()
167 if reply.error() == QNetworkReply.NoError: 190 if reply.error() == QNetworkReply.NoError:
168 result = json.loads(str(reply.readAll(), "utf-8")) 191 result = json.loads(str(reply.readAll(), "utf-8"))
169 if "file-report" in result: 192 if "file-report" in result:
170 fileScanPageUrl = self.ReportFileScanPagePattern.format( 193 self.fileScanReport.emit(
171 result["file-report"]) 194 self.ReportFileScanPagePattern.format(result["file-report"]))
172 195 self.__replies.remove(reply)
173 return fileScanPageUrl
174 196
175 @classmethod 197 @classmethod
176 def getSearchRequestData(cls, term): 198 def getSearchRequestData(cls, term):
177 """ 199 """
178 200 Class method to assemble the search request data structure.
201
202 @param term search term (string)
203 @return tuple of network request object, operation and parameters
204 (QNetworkRequest, QNetworkAccessManager.Operation, QByteArray)
179 """ 205 """
180 request = QNetworkRequest(QUrl(cls.SearchUrl)) 206 request = QNetworkRequest(QUrl(cls.SearchUrl))
181 request.setHeader(QNetworkRequest.ContentTypeHeader, 207 request.setHeader(QNetworkRequest.ContentTypeHeader,
182 "application/x-www-form-urlencoded") 208 "application/x-www-form-urlencoded")
183 op = QNetworkAccessManager.PostOperation 209 op = QNetworkAccessManager.PostOperation

eric ide

mercurial