21 |
21 |
22 class VirusTotalAPI(QObject): |
22 class VirusTotalAPI(QObject): |
23 """ |
23 """ |
24 Class implementing the <a href="http://www.virustotal.com">VirusTotal</a> |
24 Class implementing the <a href="http://www.virustotal.com">VirusTotal</a> |
25 API. |
25 API. |
26 |
26 |
27 @signal checkServiceKeyFinished(bool, str) emitted after the service key |
27 @signal checkServiceKeyFinished(bool, str) emitted after the service key |
28 check has been performed. It gives a flag indicating validity |
28 check has been performed. It gives a flag indicating validity |
29 (boolean) and an error message in case of a network error (string). |
29 (boolean) and an error message in case of a network error (string). |
30 @signal submitUrlError(str) emitted with the error string, if the URL scan |
30 @signal submitUrlError(str) emitted with the error string, if the URL scan |
31 submission returned an error. |
31 submission returned an error. |
32 @signal urlScanReport(str) emitted with the URL of the URL scan report page |
32 @signal urlScanReport(str) emitted with the URL of the URL scan report page |
33 @signal fileScanReport(str) emitted with the URL of the file scan report |
33 @signal fileScanReport(str) emitted with the URL of the file scan report |
34 page |
34 page |
35 """ |
35 """ |
|
36 |
36 checkServiceKeyFinished = pyqtSignal(bool, str) |
37 checkServiceKeyFinished = pyqtSignal(bool, str) |
37 submitUrlError = pyqtSignal(str) |
38 submitUrlError = pyqtSignal(str) |
38 urlScanReport = pyqtSignal(str) |
39 urlScanReport = pyqtSignal(str) |
39 fileScanReport = pyqtSignal(str) |
40 fileScanReport = pyqtSignal(str) |
40 |
41 |
41 TestServiceKeyScanID = ( |
42 TestServiceKeyScanID = ( |
42 "4feed2c2e352f105f6188efd1d5a558f24aee6971bdf96d5fdb19c197d6d3fad" |
43 "4feed2c2e352f105f6188efd1d5a558f24aee6971bdf96d5fdb19c197d6d3fad" |
43 ) |
44 ) |
44 |
45 |
45 ServiceResult_ItemQueued = -2 |
46 ServiceResult_ItemQueued = -2 |
46 ServiceResult_ItemNotPresent = 0 |
47 ServiceResult_ItemNotPresent = 0 |
47 ServiceResult_ItemPresent = 1 |
48 ServiceResult_ItemPresent = 1 |
48 |
49 |
49 # HTTP Status Codes |
50 # HTTP Status Codes |
50 ServiceCode_InvalidKey = 202 |
51 ServiceCode_InvalidKey = 202 |
51 ServiceCode_RateLimitExceeded = 204 |
52 ServiceCode_RateLimitExceeded = 204 |
52 ServiceCode_InvalidPrivilege = 403 |
53 ServiceCode_InvalidPrivilege = 403 |
53 |
54 |
54 GetFileReportPattern = "{0}://www.virustotal.com/vtapi/v2/file/report" |
55 GetFileReportPattern = "{0}://www.virustotal.com/vtapi/v2/file/report" |
55 ScanUrlPattern = "{0}://www.virustotal.com/vtapi/v2/url/scan" |
56 ScanUrlPattern = "{0}://www.virustotal.com/vtapi/v2/url/scan" |
56 GetUrlReportPattern = "{0}://www.virustotal.com/vtapi/v2/url/report" |
57 GetUrlReportPattern = "{0}://www.virustotal.com/vtapi/v2/url/report" |
57 GetIpAddressReportPattern = ( |
58 GetIpAddressReportPattern = "{0}://www.virustotal.com/vtapi/v2/ip-address/report" |
58 "{0}://www.virustotal.com/vtapi/v2/ip-address/report" |
|
59 ) |
|
60 GetDomainReportPattern = "{0}://www.virustotal.com/vtapi/v2/domain/report" |
59 GetDomainReportPattern = "{0}://www.virustotal.com/vtapi/v2/domain/report" |
61 |
60 |
62 def __init__(self, parent=None): |
61 def __init__(self, parent=None): |
63 """ |
62 """ |
64 Constructor |
63 Constructor |
65 |
64 |
66 @param parent reference to the parent object (QObject) |
65 @param parent reference to the parent object (QObject) |
67 """ |
66 """ |
68 super().__init__(parent) |
67 super().__init__(parent) |
69 |
68 |
70 self.__replies = [] |
69 self.__replies = [] |
71 |
70 |
72 self.__loadSettings() |
71 self.__loadSettings() |
73 |
72 |
74 self.__lastIP = "" |
73 self.__lastIP = "" |
75 self.__lastDomain = "" |
74 self.__lastDomain = "" |
76 self.__ipReportDlg = None |
75 self.__ipReportDlg = None |
77 self.__domainReportDlg = None |
76 self.__domainReportDlg = None |
78 |
77 |
79 def __loadSettings(self): |
78 def __loadSettings(self): |
80 """ |
79 """ |
81 Private method to load the settings. |
80 Private method to load the settings. |
82 """ |
81 """ |
83 protocol = ( |
82 protocol = "https" if Preferences.getWebBrowser("VirusTotalSecure") else "http" |
84 "https" |
|
85 if Preferences.getWebBrowser("VirusTotalSecure") else |
|
86 "http" |
|
87 ) |
|
88 self.GetFileReportUrl = self.GetFileReportPattern.format(protocol) |
83 self.GetFileReportUrl = self.GetFileReportPattern.format(protocol) |
89 self.ScanUrlUrl = self.ScanUrlPattern.format(protocol) |
84 self.ScanUrlUrl = self.ScanUrlPattern.format(protocol) |
90 self.GetUrlReportUrl = self.GetUrlReportPattern.format(protocol) |
85 self.GetUrlReportUrl = self.GetUrlReportPattern.format(protocol) |
91 self.GetIpAddressReportUrl = self.GetIpAddressReportPattern.format( |
86 self.GetIpAddressReportUrl = self.GetIpAddressReportPattern.format(protocol) |
92 protocol) |
|
93 self.GetDomainReportUrl = self.GetDomainReportPattern.format(protocol) |
87 self.GetDomainReportUrl = self.GetDomainReportPattern.format(protocol) |
94 |
88 |
95 self.errorMessages = { |
89 self.errorMessages = { |
96 204: self.tr("Request limit has been reached."), |
90 204: self.tr("Request limit has been reached."), |
97 0: self.tr("Requested item is not present."), |
91 0: self.tr("Requested item is not present."), |
98 -2: self.tr("Requested item is still queued."), |
92 -2: self.tr("Requested item is still queued."), |
99 } |
93 } |
100 |
94 |
101 def preferencesChanged(self): |
95 def preferencesChanged(self): |
102 """ |
96 """ |
103 Public slot to handle a change of preferences. |
97 Public slot to handle a change of preferences. |
104 """ |
98 """ |
105 self.__loadSettings() |
99 self.__loadSettings() |
106 |
100 |
107 def checkServiceKeyValidity(self, key, protocol=""): |
101 def checkServiceKeyValidity(self, key, protocol=""): |
108 """ |
102 """ |
109 Public method to check the validity of the given service key. |
103 Public method to check the validity of the given service key. |
110 |
104 |
111 @param key service key (string) |
105 @param key service key (string) |
112 @param protocol protocol used to access VirusTotal (string) |
106 @param protocol protocol used to access VirusTotal (string) |
113 """ |
107 """ |
114 urlStr = ( |
108 urlStr = ( |
115 self.GetFileReportUrl |
109 self.GetFileReportUrl |
116 if protocol == "" else |
110 if protocol == "" |
117 self.GetFileReportPattern.format(protocol) |
111 else self.GetFileReportPattern.format(protocol) |
118 ) |
112 ) |
119 request = QNetworkRequest(QUrl(urlStr)) |
113 request = QNetworkRequest(QUrl(urlStr)) |
120 request.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, |
114 request.setHeader( |
121 "application/x-www-form-urlencoded") |
115 QNetworkRequest.KnownHeaders.ContentTypeHeader, |
122 params = QByteArray("apikey={0}&resource={1}".format( |
116 "application/x-www-form-urlencoded", |
123 key, self.TestServiceKeyScanID).encode("utf-8")) |
117 ) |
124 |
118 params = QByteArray( |
125 import WebBrowser.WebBrowserWindow |
119 "apikey={0}&resource={1}".format(key, self.TestServiceKeyScanID).encode( |
126 nam = ( |
120 "utf-8" |
127 WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
121 ) |
128 ) |
122 ) |
|
123 |
|
124 import WebBrowser.WebBrowserWindow |
|
125 |
|
126 nam = WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
129 reply = nam.post(request, params) |
127 reply = nam.post(request, params) |
130 reply.finished.connect( |
128 reply.finished.connect(lambda: self.__checkServiceKeyValidityFinished(reply)) |
131 lambda: self.__checkServiceKeyValidityFinished(reply)) |
129 self.__replies.append(reply) |
132 self.__replies.append(reply) |
130 |
133 |
|
134 def __checkServiceKeyValidityFinished(self, reply): |
131 def __checkServiceKeyValidityFinished(self, reply): |
135 """ |
132 """ |
136 Private slot to determine the result of the service key validity check. |
133 Private slot to determine the result of the service key validity check. |
137 |
134 |
138 @param reply reference to the network reply |
135 @param reply reference to the network reply |
139 @type QNetworkReply |
136 @type QNetworkReply |
140 """ |
137 """ |
141 res = False |
138 res = False |
142 msg = "" |
139 msg = "" |
143 |
140 |
144 if reply.error() == QNetworkReply.NetworkError.NoError: |
141 if reply.error() == QNetworkReply.NetworkError.NoError: |
145 res = True |
142 res = True |
146 elif reply.error() == self.ServiceCode_InvalidKey: |
143 elif reply.error() == self.ServiceCode_InvalidKey: |
147 res = False |
144 res = False |
148 else: |
145 else: |
149 msg = reply.errorString() |
146 msg = reply.errorString() |
150 self.__replies.remove(reply) |
147 self.__replies.remove(reply) |
151 reply.deleteLater() |
148 reply.deleteLater() |
152 |
149 |
153 self.checkServiceKeyFinished.emit(res, msg) |
150 self.checkServiceKeyFinished.emit(res, msg) |
154 |
151 |
155 def submitUrl(self, url): |
152 def submitUrl(self, url): |
156 """ |
153 """ |
157 Public method to submit an URL to be scanned. |
154 Public method to submit an URL to be scanned. |
158 |
155 |
159 @param url url to be scanned (QUrl) |
156 @param url url to be scanned (QUrl) |
160 """ |
157 """ |
161 request = QNetworkRequest(QUrl(self.ScanUrlUrl)) |
158 request = QNetworkRequest(QUrl(self.ScanUrlUrl)) |
162 request.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, |
159 request.setHeader( |
163 "application/x-www-form-urlencoded") |
160 QNetworkRequest.KnownHeaders.ContentTypeHeader, |
164 params = QByteArray("apikey={0}&url=".format( |
161 "application/x-www-form-urlencoded", |
165 Preferences.getWebBrowser("VirusTotalServiceKey")) |
162 ) |
166 .encode("utf-8")).append(QUrl.toPercentEncoding(url.toString())) |
163 params = QByteArray( |
167 |
164 "apikey={0}&url=".format( |
168 import WebBrowser.WebBrowserWindow |
165 Preferences.getWebBrowser("VirusTotalServiceKey") |
169 nam = ( |
166 ).encode("utf-8") |
170 WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
167 ).append(QUrl.toPercentEncoding(url.toString())) |
171 ) |
168 |
|
169 import WebBrowser.WebBrowserWindow |
|
170 |
|
171 nam = WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
172 reply = nam.post(request, params) |
172 reply = nam.post(request, params) |
173 reply.finished.connect(lambda: self.__submitUrlFinished(reply)) |
173 reply.finished.connect(lambda: self.__submitUrlFinished(reply)) |
174 self.__replies.append(reply) |
174 self.__replies.append(reply) |
175 |
175 |
176 def __submitUrlFinished(self, reply): |
176 def __submitUrlFinished(self, reply): |
177 """ |
177 """ |
178 Private slot to determine the result of the URL scan submission. |
178 Private slot to determine the result of the URL scan submission. |
179 |
179 |
180 @param reply reference to the network reply |
180 @param reply reference to the network reply |
181 @type QNetworkReply |
181 @type QNetworkReply |
182 """ |
182 """ |
183 if reply.error() == QNetworkReply.NetworkError.NoError: |
183 if reply.error() == QNetworkReply.NetworkError.NoError: |
184 result = json.loads(str(reply.readAll(), "utf-8")) |
184 result = json.loads(str(reply.readAll(), "utf-8")) |
191 else: |
191 else: |
192 msg = result["verbose_msg"] |
192 msg = result["verbose_msg"] |
193 self.submitUrlError.emit(msg) |
193 self.submitUrlError.emit(msg) |
194 elif reply.error() == self.ServiceCode_RateLimitExceeded: |
194 elif reply.error() == self.ServiceCode_RateLimitExceeded: |
195 self.submitUrlError.emit( |
195 self.submitUrlError.emit( |
196 self.errorMessages[result[self.ServiceCode_RateLimitExceeded]]) |
196 self.errorMessages[result[self.ServiceCode_RateLimitExceeded]] |
|
197 ) |
197 else: |
198 else: |
198 self.submitUrlError.emit(reply.errorString()) |
199 self.submitUrlError.emit(reply.errorString()) |
199 self.__replies.remove(reply) |
200 self.__replies.remove(reply) |
200 reply.deleteLater() |
201 reply.deleteLater() |
201 |
202 |
202 def __getUrlScanReportUrl(self, scanId): |
203 def __getUrlScanReportUrl(self, scanId): |
203 """ |
204 """ |
204 Private method to get the report URL for a URL scan. |
205 Private method to get the report URL for a URL scan. |
205 |
206 |
206 @param scanId ID of the scan to get the report URL for (string) |
207 @param scanId ID of the scan to get the report URL for (string) |
207 """ |
208 """ |
208 request = QNetworkRequest(QUrl(self.GetUrlReportUrl)) |
209 request = QNetworkRequest(QUrl(self.GetUrlReportUrl)) |
209 request.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, |
210 request.setHeader( |
210 "application/x-www-form-urlencoded") |
211 QNetworkRequest.KnownHeaders.ContentTypeHeader, |
211 params = QByteArray("apikey={0}&resource={1}".format( |
212 "application/x-www-form-urlencoded", |
212 Preferences.getWebBrowser("VirusTotalServiceKey"), scanId) |
213 ) |
213 .encode("utf-8")) |
214 params = QByteArray( |
214 |
215 "apikey={0}&resource={1}".format( |
215 import WebBrowser.WebBrowserWindow |
216 Preferences.getWebBrowser("VirusTotalServiceKey"), scanId |
216 nam = ( |
217 ).encode("utf-8") |
217 WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
218 ) |
218 ) |
219 |
|
220 import WebBrowser.WebBrowserWindow |
|
221 |
|
222 nam = WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
219 reply = nam.post(request, params) |
223 reply = nam.post(request, params) |
220 reply.finished.connect( |
224 reply.finished.connect(lambda: self.__getUrlScanReportUrlFinished(reply)) |
221 lambda: self.__getUrlScanReportUrlFinished(reply)) |
225 self.__replies.append(reply) |
222 self.__replies.append(reply) |
226 |
223 |
|
224 def __getUrlScanReportUrlFinished(self, reply): |
227 def __getUrlScanReportUrlFinished(self, reply): |
225 """ |
228 """ |
226 Private slot to determine the result of the URL scan report URL. |
229 Private slot to determine the result of the URL scan report URL. |
227 |
230 |
228 @param reply reference to the network reply |
231 @param reply reference to the network reply |
229 @type QNetworkReply |
232 @type QNetworkReply |
230 request. |
233 request. |
231 """ |
234 """ |
232 if reply.error() == QNetworkReply.NetworkError.NoError: |
235 if reply.error() == QNetworkReply.NetworkError.NoError: |
233 result = json.loads(str(reply.readAll(), "utf-8")) |
236 result = json.loads(str(reply.readAll(), "utf-8")) |
234 if "filescan_id" in result and result["filescan_id"] is not None: |
237 if "filescan_id" in result and result["filescan_id"] is not None: |
235 self.__getFileScanReportUrl(result["filescan_id"]) |
238 self.__getFileScanReportUrl(result["filescan_id"]) |
236 self.__replies.remove(reply) |
239 self.__replies.remove(reply) |
237 reply.deleteLater() |
240 reply.deleteLater() |
238 |
241 |
239 def __getFileScanReportUrl(self, scanId): |
242 def __getFileScanReportUrl(self, scanId): |
240 """ |
243 """ |
241 Private method to get the report URL for a file scan. |
244 Private method to get the report URL for a file scan. |
242 |
245 |
243 @param scanId ID of the scan to get the report URL for (string) |
246 @param scanId ID of the scan to get the report URL for (string) |
244 """ |
247 """ |
245 request = QNetworkRequest(QUrl(self.GetFileReportUrl)) |
248 request = QNetworkRequest(QUrl(self.GetFileReportUrl)) |
246 request.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, |
249 request.setHeader( |
247 "application/x-www-form-urlencoded") |
250 QNetworkRequest.KnownHeaders.ContentTypeHeader, |
248 params = QByteArray("apikey={0}&resource={1}".format( |
251 "application/x-www-form-urlencoded", |
249 Preferences.getWebBrowser("VirusTotalServiceKey"), scanId) |
252 ) |
250 .encode("utf-8")) |
253 params = QByteArray( |
251 |
254 "apikey={0}&resource={1}".format( |
252 import WebBrowser.WebBrowserWindow |
255 Preferences.getWebBrowser("VirusTotalServiceKey"), scanId |
253 nam = ( |
256 ).encode("utf-8") |
254 WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
257 ) |
255 ) |
258 |
|
259 import WebBrowser.WebBrowserWindow |
|
260 |
|
261 nam = WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
256 reply = nam.post(request, params) |
262 reply = nam.post(request, params) |
257 reply.finished.connect( |
263 reply.finished.connect(lambda: self.__getFileScanReportUrlFinished(reply)) |
258 lambda: self.__getFileScanReportUrlFinished(reply)) |
264 self.__replies.append(reply) |
259 self.__replies.append(reply) |
265 |
260 |
|
261 def __getFileScanReportUrlFinished(self, reply): |
266 def __getFileScanReportUrlFinished(self, reply): |
262 """ |
267 """ |
263 Private slot to determine the result of the file scan report URL |
268 Private slot to determine the result of the file scan report URL |
264 request. |
269 request. |
265 |
270 |
266 @param reply reference to the network reply |
271 @param reply reference to the network reply |
267 @type QNetworkReply |
272 @type QNetworkReply |
268 """ |
273 """ |
269 if reply.error() == QNetworkReply.NetworkError.NoError: |
274 if reply.error() == QNetworkReply.NetworkError.NoError: |
270 result = json.loads(str(reply.readAll(), "utf-8")) |
275 result = json.loads(str(reply.readAll(), "utf-8")) |
271 self.fileScanReport.emit(result["permalink"]) |
276 self.fileScanReport.emit(result["permalink"]) |
272 self.__replies.remove(reply) |
277 self.__replies.remove(reply) |
273 reply.deleteLater() |
278 reply.deleteLater() |
274 |
279 |
275 def getIpAddressReport(self, ipAddress): |
280 def getIpAddressReport(self, ipAddress): |
276 """ |
281 """ |
277 Public method to retrieve a report for an IP address. |
282 Public method to retrieve a report for an IP address. |
278 |
283 |
279 @param ipAddress valid IPv4 address in dotted quad notation |
284 @param ipAddress valid IPv4 address in dotted quad notation |
280 @type str |
285 @type str |
281 """ |
286 """ |
282 self.__lastIP = ipAddress |
287 self.__lastIP = ipAddress |
283 |
288 |
284 queryItems = [ |
289 queryItems = [ |
285 ("apikey", Preferences.getWebBrowser("VirusTotalServiceKey")), |
290 ("apikey", Preferences.getWebBrowser("VirusTotalServiceKey")), |
286 ("ip", ipAddress), |
291 ("ip", ipAddress), |
287 ] |
292 ] |
288 url = QUrl(self.GetIpAddressReportUrl) |
293 url = QUrl(self.GetIpAddressReportUrl) |
289 query = QUrlQuery() |
294 query = QUrlQuery() |
290 query.setQueryItems(queryItems) |
295 query.setQueryItems(queryItems) |
291 url.setQuery(query) |
296 url.setQuery(query) |
292 request = QNetworkRequest(url) |
297 request = QNetworkRequest(url) |
293 |
298 |
294 import WebBrowser.WebBrowserWindow |
299 import WebBrowser.WebBrowserWindow |
295 nam = ( |
300 |
296 WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
301 nam = WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
297 ) |
|
298 reply = nam.get(request) |
302 reply = nam.get(request) |
299 reply.finished.connect( |
303 reply.finished.connect(lambda: self.__getIpAddressReportFinished(reply)) |
300 lambda: self.__getIpAddressReportFinished(reply)) |
304 self.__replies.append(reply) |
301 self.__replies.append(reply) |
305 |
302 |
|
303 def __getIpAddressReportFinished(self, reply): |
306 def __getIpAddressReportFinished(self, reply): |
304 """ |
307 """ |
305 Private slot to process the IP address report data. |
308 Private slot to process the IP address report data. |
306 |
309 |
307 @param reply reference to the network reply |
310 @param reply reference to the network reply |
308 @type QNetworkReply |
311 @type QNetworkReply |
309 """ |
312 """ |
310 if reply.error() == QNetworkReply.NetworkError.NoError: |
313 if reply.error() == QNetworkReply.NetworkError.NoError: |
311 result = json.loads(str(reply.readAll(), "utf-8")) |
314 result = json.loads(str(reply.readAll(), "utf-8")) |
312 if result["response_code"] == 0: |
315 if result["response_code"] == 0: |
313 EricMessageBox.information( |
316 EricMessageBox.information( |
314 None, |
317 None, |
315 self.tr("VirusTotal IP Address Report"), |
318 self.tr("VirusTotal IP Address Report"), |
316 self.tr("""VirusTotal does not have any information for""" |
319 self.tr( |
317 """ the given IP address.""")) |
320 """VirusTotal does not have any information for""" |
|
321 """ the given IP address.""" |
|
322 ), |
|
323 ) |
318 elif result["response_code"] == -1: |
324 elif result["response_code"] == -1: |
319 EricMessageBox.information( |
325 EricMessageBox.information( |
320 None, |
326 None, |
321 self.tr("VirusTotal IP Address Report"), |
327 self.tr("VirusTotal IP Address Report"), |
322 self.tr("""The submitted IP address is invalid.""")) |
328 self.tr("""The submitted IP address is invalid."""), |
|
329 ) |
323 else: |
330 else: |
324 owner = result["as_owner"] |
331 owner = result["as_owner"] |
325 resolutions = result["resolutions"] |
332 resolutions = result["resolutions"] |
326 try: |
333 try: |
327 urls = result["detected_urls"] |
334 urls = result["detected_urls"] |
328 except KeyError: |
335 except KeyError: |
329 urls = [] |
336 urls = [] |
330 |
337 |
331 from .VirusTotalIpReportDialog import VirusTotalIpReportDialog |
338 from .VirusTotalIpReportDialog import VirusTotalIpReportDialog |
|
339 |
332 self.__ipReportDlg = VirusTotalIpReportDialog( |
340 self.__ipReportDlg = VirusTotalIpReportDialog( |
333 self.__lastIP, owner, resolutions, urls) |
341 self.__lastIP, owner, resolutions, urls |
|
342 ) |
334 self.__ipReportDlg.show() |
343 self.__ipReportDlg.show() |
335 self.__replies.remove(reply) |
344 self.__replies.remove(reply) |
336 reply.deleteLater() |
345 reply.deleteLater() |
337 |
346 |
338 def getDomainReport(self, domain): |
347 def getDomainReport(self, domain): |
339 """ |
348 """ |
340 Public method to retrieve a report for a domain. |
349 Public method to retrieve a report for a domain. |
341 |
350 |
342 @param domain domain name |
351 @param domain domain name |
343 @type str |
352 @type str |
344 """ |
353 """ |
345 self.__lastDomain = domain |
354 self.__lastDomain = domain |
346 |
355 |
347 queryItems = [ |
356 queryItems = [ |
348 ("apikey", Preferences.getWebBrowser("VirusTotalServiceKey")), |
357 ("apikey", Preferences.getWebBrowser("VirusTotalServiceKey")), |
349 ("domain", domain), |
358 ("domain", domain), |
350 ] |
359 ] |
351 url = QUrl(self.GetDomainReportUrl) |
360 url = QUrl(self.GetDomainReportUrl) |
352 query = QUrlQuery() |
361 query = QUrlQuery() |
353 query.setQueryItems(queryItems) |
362 query.setQueryItems(queryItems) |
354 url.setQuery(query) |
363 url.setQuery(query) |
355 request = QNetworkRequest(url) |
364 request = QNetworkRequest(url) |
356 |
365 |
357 import WebBrowser.WebBrowserWindow |
366 import WebBrowser.WebBrowserWindow |
358 nam = ( |
367 |
359 WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
368 nam = WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() |
360 ) |
|
361 reply = nam.get(request) |
369 reply = nam.get(request) |
362 reply.finished.connect(lambda: self.__getDomainReportFinished(reply)) |
370 reply.finished.connect(lambda: self.__getDomainReportFinished(reply)) |
363 self.__replies.append(reply) |
371 self.__replies.append(reply) |
364 |
372 |
365 def __getDomainReportFinished(self, reply): |
373 def __getDomainReportFinished(self, reply): |
366 """ |
374 """ |
367 Private slot to process the IP address report data. |
375 Private slot to process the IP address report data. |
368 |
376 |
369 @param reply reference to the network reply |
377 @param reply reference to the network reply |
370 @type QNetworkReply |
378 @type QNetworkReply |
371 """ |
379 """ |
372 if reply.error() == QNetworkReply.NetworkError.NoError: |
380 if reply.error() == QNetworkReply.NetworkError.NoError: |
373 result = json.loads(str(reply.readAll(), "utf-8")) |
381 result = json.loads(str(reply.readAll(), "utf-8")) |
374 if result["response_code"] == 0: |
382 if result["response_code"] == 0: |
375 EricMessageBox.information( |
383 EricMessageBox.information( |
376 None, |
384 None, |
377 self.tr("VirusTotal Domain Report"), |
385 self.tr("VirusTotal Domain Report"), |
378 self.tr("""VirusTotal does not have any information for""" |
386 self.tr( |
379 """ the given domain.""")) |
387 """VirusTotal does not have any information for""" |
|
388 """ the given domain.""" |
|
389 ), |
|
390 ) |
380 elif result["response_code"] == -1: |
391 elif result["response_code"] == -1: |
381 EricMessageBox.information( |
392 EricMessageBox.information( |
382 None, |
393 None, |
383 self.tr("VirusTotal Domain Report"), |
394 self.tr("VirusTotal Domain Report"), |
384 self.tr("""The submitted domain address is invalid.""")) |
395 self.tr("""The submitted domain address is invalid."""), |
|
396 ) |
385 else: |
397 else: |
386 resolutions = result["resolutions"] |
398 resolutions = result["resolutions"] |
387 try: |
399 try: |
388 urls = result["detected_urls"] |
400 urls = result["detected_urls"] |
389 except KeyError: |
401 except KeyError: |
390 urls = [] |
402 urls = [] |
391 try: |
403 try: |
392 subdomains = result["subdomains"] |
404 subdomains = result["subdomains"] |
393 except KeyError: |
405 except KeyError: |
394 subdomains = [] |
406 subdomains = [] |
395 |
407 |
396 categoriesMapping = { |
408 categoriesMapping = { |
397 "bitdefender": ("BitDefender category",), |
409 "bitdefender": ("BitDefender category",), |
398 "sophos": ("sophos category", "Sophos category"), |
410 "sophos": ("sophos category", "Sophos category"), |
399 "valkyrie": ("Comodo Valkyrie Verdict category",), |
411 "valkyrie": ("Comodo Valkyrie Verdict category",), |
400 "alpha": ("alphaMountain.ai category",), |
412 "alpha": ("alphaMountain.ai category",), |