22 |
27 |
23 |
28 |
24 class SafeBrowsingAPIClient(QObject): |
29 class SafeBrowsingAPIClient(QObject): |
25 """ |
30 """ |
26 Class implementing the low level interface for Google Safe Browsing. |
31 Class implementing the low level interface for Google Safe Browsing. |
27 |
32 |
28 @signal networkError(str) emitted to indicate a network error |
33 @signal networkError(str) emitted to indicate a network error |
29 """ |
34 """ |
|
35 |
30 ClientId = "eric7_API_client" |
36 ClientId = "eric7_API_client" |
31 ClientVersion = "2.0.0" |
37 ClientVersion = "2.0.0" |
32 |
38 |
33 GsbUrlTemplate = "https://safebrowsing.googleapis.com/v4/{0}?key={1}" |
39 GsbUrlTemplate = "https://safebrowsing.googleapis.com/v4/{0}?key={1}" |
34 |
40 |
35 networkError = pyqtSignal(str) |
41 networkError = pyqtSignal(str) |
36 |
42 |
37 def __init__(self, apiKey, fairUse=True, parent=None): |
43 def __init__(self, apiKey, fairUse=True, parent=None): |
38 """ |
44 """ |
39 Constructor |
45 Constructor |
40 |
46 |
41 @param apiKey API key to be used |
47 @param apiKey API key to be used |
42 @type str |
48 @type str |
43 @param fairUse flag indicating to follow the fair use policy |
49 @param fairUse flag indicating to follow the fair use policy |
44 @type bool |
50 @type bool |
45 @param parent reference to the parent object |
51 @param parent reference to the parent object |
46 @type QObject |
52 @type QObject |
47 """ |
53 """ |
48 super().__init__(parent) |
54 super().__init__(parent) |
49 |
55 |
50 self.__apiKey = apiKey |
56 self.__apiKey = apiKey |
51 self.__fairUse = fairUse |
57 self.__fairUse = fairUse |
52 |
58 |
53 self.__nextRequestNoSoonerThan = QDateTime() |
59 self.__nextRequestNoSoonerThan = QDateTime() |
54 self.__failCount = 0 |
60 self.__failCount = 0 |
55 |
61 |
56 self.__lookupApiCache = {} |
62 self.__lookupApiCache = {} |
57 # Temporary cache used by the lookup API (v4) |
63 # Temporary cache used by the lookup API (v4) |
58 # key: URL as string |
64 # key: URL as string |
59 # value: dictionary with these entries: |
65 # value: dictionary with these entries: |
60 # "validUntil": (QDateTime) |
66 # "validUntil": (QDateTime) |
61 # "threatInfo": (list of ThreatList) |
67 # "threatInfo": (list of ThreatList) |
62 |
68 |
63 def setApiKey(self, apiKey): |
69 def setApiKey(self, apiKey): |
64 """ |
70 """ |
65 Public method to set the API key. |
71 Public method to set the API key. |
66 |
72 |
67 @param apiKey API key to be set |
73 @param apiKey API key to be set |
68 @type str |
74 @type str |
69 """ |
75 """ |
70 self.__apiKey = apiKey |
76 self.__apiKey = apiKey |
71 |
77 |
72 def getThreatLists(self): |
78 def getThreatLists(self): |
73 """ |
79 """ |
74 Public method to retrieve all available threat lists. |
80 Public method to retrieve all available threat lists. |
75 |
81 |
76 @return tuple containing list of threat lists and an error message |
82 @return tuple containing list of threat lists and an error message |
77 @rtype tuple of (list of dict containing 'threatType', 'platformType' |
83 @rtype tuple of (list of dict containing 'threatType', 'platformType' |
78 and 'threatEntryType', bool) |
84 and 'threatEntryType', bool) |
79 """ |
85 """ |
80 url = QUrl(self.GsbUrlTemplate.format("threatLists", self.__apiKey)) |
86 url = QUrl(self.GsbUrlTemplate.format("threatLists", self.__apiKey)) |
81 req = QNetworkRequest(url) |
87 req = QNetworkRequest(url) |
82 reply = WebBrowserWindow.networkManager().get(req) |
88 reply = WebBrowserWindow.networkManager().get(req) |
83 |
89 |
84 while reply.isRunning(): |
90 while reply.isRunning(): |
85 QCoreApplication.processEvents( |
91 QCoreApplication.processEvents(QEventLoop.ProcessEventsFlag.AllEvents, 200) |
86 QEventLoop.ProcessEventsFlag.AllEvents, 200) |
|
87 # max. 200 ms processing |
92 # max. 200 ms processing |
88 |
93 |
89 res = None |
94 res = None |
90 error = "" |
95 error = "" |
91 if reply.error() != QNetworkReply.NetworkError.NoError: |
96 if reply.error() != QNetworkReply.NetworkError.NoError: |
92 error = reply.errorString() |
97 error = reply.errorString() |
93 self.networkError.emit(error) |
98 self.networkError.emit(error) |
94 else: |
99 else: |
95 result = self.__extractData(reply) |
100 result = self.__extractData(reply) |
96 res = result["threatLists"] |
101 res = result["threatLists"] |
97 |
102 |
98 reply.deleteLater() |
103 reply.deleteLater() |
99 return res, error |
104 return res, error |
100 |
105 |
101 ####################################################################### |
106 ####################################################################### |
102 ## Methods below implement the 'Update API (v4)' |
107 ## Methods below implement the 'Update API (v4)' |
103 ####################################################################### |
108 ####################################################################### |
104 |
109 |
105 def getThreatsUpdate(self, clientStates): |
110 def getThreatsUpdate(self, clientStates): |
106 """ |
111 """ |
107 Public method to fetch hash prefix updates for the given threat list. |
112 Public method to fetch hash prefix updates for the given threat list. |
108 |
113 |
109 @param clientStates dictionary of client states with keys like |
114 @param clientStates dictionary of client states with keys like |
110 (threatType, platformType, threatEntryType) |
115 (threatType, platformType, threatEntryType) |
111 @type dict |
116 @type dict |
112 @return tuple containing the list of threat updates and an error |
117 @return tuple containing the list of threat updates and an error |
113 message |
118 message |
118 "clientId": self.ClientId, |
123 "clientId": self.ClientId, |
119 "clientVersion": self.ClientVersion, |
124 "clientVersion": self.ClientVersion, |
120 }, |
125 }, |
121 "listUpdateRequests": [], |
126 "listUpdateRequests": [], |
122 } |
127 } |
123 |
128 |
124 for (threatType, platformType, threatEntryType), currentState in ( |
129 for ( |
125 clientStates.items() |
130 threatType, |
126 ): |
131 platformType, |
|
132 threatEntryType, |
|
133 ), currentState in clientStates.items(): |
127 requestBody["listUpdateRequests"].append( |
134 requestBody["listUpdateRequests"].append( |
128 { |
135 { |
129 "threatType": threatType, |
136 "threatType": threatType, |
130 "platformType": platformType, |
137 "platformType": platformType, |
131 "threatEntryType": threatEntryType, |
138 "threatEntryType": threatEntryType, |
132 "state": currentState, |
139 "state": currentState, |
133 "constraints": { |
140 "constraints": { |
134 "supportedCompressions": ["RAW"], |
141 "supportedCompressions": ["RAW"], |
135 } |
142 }, |
136 } |
143 } |
137 ) |
144 ) |
138 |
145 |
139 data = QByteArray(json.dumps(requestBody).encode("utf-8")) |
146 data = QByteArray(json.dumps(requestBody).encode("utf-8")) |
140 url = QUrl(self.GsbUrlTemplate.format("threatListUpdates:fetch", |
147 url = QUrl(self.GsbUrlTemplate.format("threatListUpdates:fetch", self.__apiKey)) |
141 self.__apiKey)) |
|
142 req = QNetworkRequest(url) |
148 req = QNetworkRequest(url) |
143 req.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, |
149 req.setHeader( |
144 "application/json") |
150 QNetworkRequest.KnownHeaders.ContentTypeHeader, "application/json" |
|
151 ) |
145 reply = WebBrowserWindow.networkManager().post(req, data) |
152 reply = WebBrowserWindow.networkManager().post(req, data) |
146 |
153 |
147 while reply.isRunning(): |
154 while reply.isRunning(): |
148 QCoreApplication.processEvents( |
155 QCoreApplication.processEvents(QEventLoop.ProcessEventsFlag.AllEvents, 200) |
149 QEventLoop.ProcessEventsFlag.AllEvents, 200) |
|
150 # max. 200 ms processing |
156 # max. 200 ms processing |
151 |
157 |
152 res = None |
158 res = None |
153 error = "" |
159 error = "" |
154 if reply.error() != QNetworkReply.NetworkError.NoError: |
160 if reply.error() != QNetworkReply.NetworkError.NoError: |
155 error = reply.errorString() |
161 error = reply.errorString() |
156 self.networkError.emit(error) |
162 self.networkError.emit(error) |
157 else: |
163 else: |
158 result = self.__extractData(reply) |
164 result = self.__extractData(reply) |
159 res = result["listUpdateResponses"] |
165 res = result["listUpdateResponses"] |
160 |
166 |
161 reply.deleteLater() |
167 reply.deleteLater() |
162 return res, error |
168 return res, error |
163 |
169 |
164 def getFullHashes(self, prefixes, clientState): |
170 def getFullHashes(self, prefixes, clientState): |
165 """ |
171 """ |
166 Public method to find full hashes matching hash prefixes. |
172 Public method to find full hashes matching hash prefixes. |
167 |
173 |
168 @param prefixes list of hash prefixes to find |
174 @param prefixes list of hash prefixes to find |
169 @type list of bytes |
175 @type list of bytes |
170 @param clientState dictionary of client states with keys like |
176 @param clientState dictionary of client states with keys like |
171 (threatType, platformType, threatEntryType) |
177 (threatType, platformType, threatEntryType) |
172 @type dict |
178 @type dict |
185 "platformTypes": [], |
191 "platformTypes": [], |
186 "threatEntryTypes": [], |
192 "threatEntryTypes": [], |
187 "threatEntries": [], |
193 "threatEntries": [], |
188 }, |
194 }, |
189 } |
195 } |
190 |
196 |
191 for prefix in prefixes: |
197 for prefix in prefixes: |
192 requestBody["threatInfo"]["threatEntries"].append( |
198 requestBody["threatInfo"]["threatEntries"].append( |
193 {"hash": base64.b64encode(prefix).decode("ascii")}) |
199 {"hash": base64.b64encode(prefix).decode("ascii")} |
194 |
200 ) |
195 for (threatType, platformType, threatEntryType), currentState in ( |
201 |
196 clientState.items() |
202 for ( |
197 ): |
203 threatType, |
|
204 platformType, |
|
205 threatEntryType, |
|
206 ), currentState in clientState.items(): |
198 requestBody["clientStates"].append(currentState) |
207 requestBody["clientStates"].append(currentState) |
199 if threatType not in requestBody["threatInfo"]["threatTypes"]: |
208 if threatType not in requestBody["threatInfo"]["threatTypes"]: |
200 requestBody["threatInfo"]["threatTypes"].append(threatType) |
209 requestBody["threatInfo"]["threatTypes"].append(threatType) |
201 if ( |
210 if platformType not in requestBody["threatInfo"]["platformTypes"]: |
202 platformType not in |
211 requestBody["threatInfo"]["platformTypes"].append(platformType) |
203 requestBody["threatInfo"]["platformTypes"] |
212 if threatEntryType not in requestBody["threatInfo"]["threatEntryTypes"]: |
204 ): |
213 requestBody["threatInfo"]["threatEntryTypes"].append(threatEntryType) |
205 requestBody["threatInfo"]["platformTypes"].append( |
214 |
206 platformType) |
|
207 if ( |
|
208 threatEntryType not in |
|
209 requestBody["threatInfo"]["threatEntryTypes"] |
|
210 ): |
|
211 requestBody["threatInfo"]["threatEntryTypes"].append( |
|
212 threatEntryType) |
|
213 |
|
214 data = QByteArray(json.dumps(requestBody).encode("utf-8")) |
215 data = QByteArray(json.dumps(requestBody).encode("utf-8")) |
215 url = QUrl(self.GsbUrlTemplate.format("fullHashes:find", |
216 url = QUrl(self.GsbUrlTemplate.format("fullHashes:find", self.__apiKey)) |
216 self.__apiKey)) |
|
217 req = QNetworkRequest(url) |
217 req = QNetworkRequest(url) |
218 req.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, |
218 req.setHeader( |
219 "application/json") |
219 QNetworkRequest.KnownHeaders.ContentTypeHeader, "application/json" |
|
220 ) |
220 reply = WebBrowserWindow.networkManager().post(req, data) |
221 reply = WebBrowserWindow.networkManager().post(req, data) |
221 |
222 |
222 while reply.isRunning(): |
223 while reply.isRunning(): |
223 QCoreApplication.processEvents( |
224 QCoreApplication.processEvents(QEventLoop.ProcessEventsFlag.AllEvents, 200) |
224 QEventLoop.ProcessEventsFlag.AllEvents, 200) |
|
225 # max. 200 ms processing |
225 # max. 200 ms processing |
226 |
226 |
227 res = [] |
227 res = [] |
228 if reply.error() != QNetworkReply.NetworkError.NoError: |
228 if reply.error() != QNetworkReply.NetworkError.NoError: |
229 self.networkError.emit(reply.errorString()) |
229 self.networkError.emit(reply.errorString()) |
230 else: |
230 else: |
231 res = self.__extractData(reply) |
231 res = self.__extractData(reply) |
232 |
232 |
233 reply.deleteLater() |
233 reply.deleteLater() |
234 return res |
234 return res |
235 |
235 |
236 def __extractData(self, reply): |
236 def __extractData(self, reply): |
237 """ |
237 """ |
238 Private method to extract the data of a network reply. |
238 Private method to extract the data of a network reply. |
239 |
239 |
240 @param reply reference to the network reply object |
240 @param reply reference to the network reply object |
241 @type QNetworkReply |
241 @type QNetworkReply |
242 @return extracted data |
242 @return extracted data |
243 @rtype list or dict |
243 @rtype list or dict |
244 """ |
244 """ |
245 result = json.loads(str(reply.readAll(), "utf-8")) |
245 result = json.loads(str(reply.readAll(), "utf-8")) |
246 self.__setWaitDuration(result.get("minimumWaitDuration")) |
246 self.__setWaitDuration(result.get("minimumWaitDuration")) |
247 return result |
247 return result |
248 |
248 |
249 def __setWaitDuration(self, minimumWaitDuration): |
249 def __setWaitDuration(self, minimumWaitDuration): |
250 """ |
250 """ |
251 Private method to set the minimum wait duration. |
251 Private method to set the minimum wait duration. |
252 |
252 |
253 @param minimumWaitDuration duration to be set |
253 @param minimumWaitDuration duration to be set |
254 @type str |
254 @type str |
255 """ |
255 """ |
256 if not self.__fairUse or minimumWaitDuration is None: |
256 if not self.__fairUse or minimumWaitDuration is None: |
257 self.__nextRequestNoSoonerThan = QDateTime() |
257 self.__nextRequestNoSoonerThan = QDateTime() |
258 else: |
258 else: |
259 waitDuration = int(float(minimumWaitDuration.rstrip("s"))) |
259 waitDuration = int(float(minimumWaitDuration.rstrip("s"))) |
260 self.__nextRequestNoSoonerThan = ( |
260 self.__nextRequestNoSoonerThan = QDateTime.currentDateTime().addSecs( |
261 QDateTime.currentDateTime().addSecs(waitDuration) |
261 waitDuration |
262 ) |
262 ) |
263 |
263 |
264 def fairUseDelayExpired(self): |
264 def fairUseDelayExpired(self): |
265 """ |
265 """ |
266 Public method to check, if the fair use wait period has expired. |
266 Public method to check, if the fair use wait period has expired. |
267 |
267 |
268 @return flag indicating expiration |
268 @return flag indicating expiration |
269 @rtype bool |
269 @rtype bool |
270 """ |
270 """ |
271 return ( |
271 return ( |
272 self.__fairUse and |
272 self.__fairUse |
273 QDateTime.currentDateTime() >= self.__nextRequestNoSoonerThan |
273 and QDateTime.currentDateTime() >= self.__nextRequestNoSoonerThan |
274 ) or not self.__fairUse |
274 ) or not self.__fairUse |
275 |
275 |
276 def getFairUseDelayExpirationDateTime(self): |
276 def getFairUseDelayExpirationDateTime(self): |
277 """ |
277 """ |
278 Public method to get the date and time the fair use delay will expire. |
278 Public method to get the date and time the fair use delay will expire. |
279 |
279 |
280 @return fair use delay expiration date and time |
280 @return fair use delay expiration date and time |
281 @rtype QDateTime |
281 @rtype QDateTime |
282 """ |
282 """ |
283 return self.__nextRequestNoSoonerThan |
283 return self.__nextRequestNoSoonerThan |
284 |
284 |
285 ####################################################################### |
285 ####################################################################### |
286 ## Methods below implement the 'Lookup API (v4)' |
286 ## Methods below implement the 'Lookup API (v4)' |
287 ####################################################################### |
287 ####################################################################### |
288 |
288 |
289 def lookupUrl(self, url, platforms): |
289 def lookupUrl(self, url, platforms): |
290 """ |
290 """ |
291 Public method to send an URL to Google for checking. |
291 Public method to send an URL to Google for checking. |
292 |
292 |
293 @param url URL to be checked |
293 @param url URL to be checked |
294 @type QUrl |
294 @type QUrl |
295 @param platforms list of platform types to check against |
295 @param platforms list of platform types to check against |
296 @type list of str |
296 @type list of str |
297 @return tuple containing the list of threat list info objects and |
297 @return tuple containing the list of threat list info objects and |
298 an error message |
298 an error message |
299 @rtype tuple of (list of ThreatList, str) |
299 @rtype tuple of (list of ThreatList, str) |
300 """ |
300 """ |
301 error = "" |
301 error = "" |
302 |
302 |
303 # sanitize the URL by removing user info and query data |
303 # sanitize the URL by removing user info and query data |
304 url = url.adjusted( |
304 url = url.adjusted( |
305 QUrl.UrlFormattingOption.RemoveUserInfo | |
305 QUrl.UrlFormattingOption.RemoveUserInfo |
306 QUrl.UrlFormattingOption.RemoveQuery | |
306 | QUrl.UrlFormattingOption.RemoveQuery |
307 QUrl.UrlFormattingOption.RemoveFragment |
307 | QUrl.UrlFormattingOption.RemoveFragment |
308 ) |
308 ) |
309 urlStr = url.toString() |
309 urlStr = url.toString() |
310 |
310 |
311 # check the local cache first |
311 # check the local cache first |
312 if urlStr in self.__lookupApiCache: |
312 if urlStr in self.__lookupApiCache: |
313 if ( |
313 if ( |
314 self.__lookupApiCache[urlStr]["validUntil"] > |
314 self.__lookupApiCache[urlStr]["validUntil"] |
315 QDateTime.currentDateTime() |
315 > QDateTime.currentDateTime() |
316 ): |
316 ): |
317 # cached entry is still valid |
317 # cached entry is still valid |
318 return self.__lookupApiCache[urlStr]["threatInfo"], error |
318 return self.__lookupApiCache[urlStr]["threatInfo"], error |
319 else: |
319 else: |
320 del self.__lookupApiCache[urlStr] |
320 del self.__lookupApiCache[urlStr] |
321 |
321 |
322 # no valid entry found, ask the safe browsing server |
322 # no valid entry found, ask the safe browsing server |
323 requestBody = { |
323 requestBody = { |
324 "client": { |
324 "client": { |
325 "clientId": self.ClientId, |
325 "clientId": self.ClientId, |
326 "clientVersion": self.ClientVersion, |
326 "clientVersion": self.ClientVersion, |
327 }, |
327 }, |
328 "threatInfo": { |
328 "threatInfo": { |
329 "threatTypes": SafeBrowsingAPIClient.definedThreatTypes(), |
329 "threatTypes": SafeBrowsingAPIClient.definedThreatTypes(), |
330 "platformTypes": platforms, |
330 "platformTypes": platforms, |
331 "threatEntryTypes": |
331 "threatEntryTypes": SafeBrowsingAPIClient.definedThreatEntryTypes(), |
332 SafeBrowsingAPIClient.definedThreatEntryTypes(), |
|
333 "threatEntries": [ |
332 "threatEntries": [ |
334 {"url": urlStr}, |
333 {"url": urlStr}, |
335 ], |
334 ], |
336 }, |
335 }, |
337 } |
336 } |
338 |
337 |
339 data = QByteArray(json.dumps(requestBody).encode("utf-8")) |
338 data = QByteArray(json.dumps(requestBody).encode("utf-8")) |
340 url = QUrl(self.GsbUrlTemplate.format("threatMatches:find", |
339 url = QUrl(self.GsbUrlTemplate.format("threatMatches:find", self.__apiKey)) |
341 self.__apiKey)) |
|
342 req = QNetworkRequest(url) |
340 req = QNetworkRequest(url) |
343 req.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, |
341 req.setHeader( |
344 "application/json") |
342 QNetworkRequest.KnownHeaders.ContentTypeHeader, "application/json" |
|
343 ) |
345 reply = WebBrowserWindow.networkManager().post(req, data) |
344 reply = WebBrowserWindow.networkManager().post(req, data) |
346 |
345 |
347 while reply.isRunning(): |
346 while reply.isRunning(): |
348 QCoreApplication.processEvents( |
347 QCoreApplication.processEvents(QEventLoop.ProcessEventsFlag.AllEvents, 200) |
349 QEventLoop.ProcessEventsFlag.AllEvents, 200) |
|
350 # max. 200 ms processing |
348 # max. 200 ms processing |
351 |
349 |
352 threats = [] |
350 threats = [] |
353 if reply.error() != QNetworkReply.NetworkError.NoError: |
351 if reply.error() != QNetworkReply.NetworkError.NoError: |
354 error = reply.errorString() |
352 error = reply.errorString() |
355 self.networkError.emit(error) |
353 self.networkError.emit(error) |
356 else: |
354 else: |
364 match["threatEntryType"], |
362 match["threatEntryType"], |
365 ) |
363 ) |
366 threats.append(threatInfo) |
364 threats.append(threatInfo) |
367 if "cacheDuration" in match: |
365 if "cacheDuration" in match: |
368 cacheDurationSec = int( |
366 cacheDurationSec = int( |
369 match["cacheDuration"].strip().rstrip("s") |
367 match["cacheDuration"].strip().rstrip("s").split(".")[0] |
370 .split(".")[0]) |
368 ) |
371 if cacheDurationSec > cacheDuration: |
369 if cacheDurationSec > cacheDuration: |
372 cacheDuration = cacheDurationSec |
370 cacheDuration = cacheDurationSec |
373 if cacheDuration > 0 and bool(threats): |
371 if cacheDuration > 0 and bool(threats): |
374 validUntil = QDateTime.currentDateTime().addSecs( |
372 validUntil = QDateTime.currentDateTime().addSecs(cacheDuration) |
375 cacheDuration) |
|
376 self.__lookupApiCache[urlStr] = { |
373 self.__lookupApiCache[urlStr] = { |
377 "validUntil": validUntil, |
374 "validUntil": validUntil, |
378 "threatInfo": threats |
375 "threatInfo": threats, |
379 } |
376 } |
380 |
377 |
381 reply.deleteLater() |
378 reply.deleteLater() |
382 return threats, error |
379 return threats, error |
383 |
380 |
384 ####################################################################### |
381 ####################################################################### |
385 ## Methods below implement global (class wide) functionality |
382 ## Methods below implement global (class wide) functionality |
386 ####################################################################### |
383 ####################################################################### |
387 |
384 |
388 @classmethod |
385 @classmethod |
389 def getThreatMessage(cls, threatType): |
386 def getThreatMessage(cls, threatType): |
390 """ |
387 """ |
391 Class method to get a warning message for the given threat type. |
388 Class method to get a warning message for the given threat type. |
392 |
389 |
393 @param threatType threat type to get the message for |
390 @param threatType threat type to get the message for |
394 @type str |
391 @type str |
395 @return threat message |
392 @return threat message |
396 @rtype str |
393 @rtype str |
397 """ |
394 """ |
400 msg = QCoreApplication.translate( |
397 msg = QCoreApplication.translate( |
401 "SafeBrowsingAPI", |
398 "SafeBrowsingAPI", |
402 "<h3>Malware Warning</h3>" |
399 "<h3>Malware Warning</h3>" |
403 "<p>The web site you are about to visit may try to install" |
400 "<p>The web site you are about to visit may try to install" |
404 " harmful programs on your computer in order to steal or" |
401 " harmful programs on your computer in order to steal or" |
405 " destroy your data.</p>") |
402 " destroy your data.</p>", |
|
403 ) |
406 elif threatType == "social_engineering": |
404 elif threatType == "social_engineering": |
407 msg = QCoreApplication.translate( |
405 msg = QCoreApplication.translate( |
408 "SafeBrowsingAPI", |
406 "SafeBrowsingAPI", |
409 "<h3>Phishing Warning</h3>" |
407 "<h3>Phishing Warning</h3>" |
410 "<p>The web site you are about to visit may try to trick you" |
408 "<p>The web site you are about to visit may try to trick you" |
411 " into doing something dangerous online, such as revealing" |
409 " into doing something dangerous online, such as revealing" |
412 " passwords or personal information, usually through a fake" |
410 " passwords or personal information, usually through a fake" |
413 " website.</p>") |
411 " website.</p>", |
|
412 ) |
414 elif threatType == "unwanted_software": |
413 elif threatType == "unwanted_software": |
415 msg = QCoreApplication.translate( |
414 msg = QCoreApplication.translate( |
416 "SafeBrowsingAPI", |
415 "SafeBrowsingAPI", |
417 "<h3>Unwanted Software Warning</h3>" |
416 "<h3>Unwanted Software Warning</h3>" |
418 "<p>The software you are about to download may negatively" |
417 "<p>The software you are about to download may negatively" |
419 " affect your browsing or computing experience.</p>") |
418 " affect your browsing or computing experience.</p>", |
|
419 ) |
420 elif threatType == "potentially_harmful_application": |
420 elif threatType == "potentially_harmful_application": |
421 msg = QCoreApplication.translate( |
421 msg = QCoreApplication.translate( |
422 "SafeBrowsingAPI", |
422 "SafeBrowsingAPI", |
423 "<h3>Potentially Harmful Application</h3>" |
423 "<h3>Potentially Harmful Application</h3>" |
424 "<p>The web site you are about to visit may try to trick you" |
424 "<p>The web site you are about to visit may try to trick you" |
425 " into installing applications, that may negatively affect" |
425 " into installing applications, that may negatively affect" |
426 " your browsing experience.</p>") |
426 " your browsing experience.</p>", |
|
427 ) |
427 elif threatType == "malicious_binary": |
428 elif threatType == "malicious_binary": |
428 msg = QCoreApplication.translate( |
429 msg = QCoreApplication.translate( |
429 "SafeBrowsingAPI", |
430 "SafeBrowsingAPI", |
430 "<h3>Malicious Binary Warning</h3>" |
431 "<h3>Malicious Binary Warning</h3>" |
431 "<p>The software you are about to download may be harmful" |
432 "<p>The software you are about to download may be harmful" |
432 " to your computer.</p>") |
433 " to your computer.</p>", |
|
434 ) |
433 else: |
435 else: |
434 # unknow threat |
436 # unknow threat |
435 msg = QCoreApplication.translate( |
437 msg = QCoreApplication.translate( |
436 "SafeBrowsingAPI", |
438 "SafeBrowsingAPI", |
437 "<h3>Unknown Threat Warning</h3>" |
439 "<h3>Unknown Threat Warning</h3>" |
438 "<p>The web site you are about to visit was found in the Safe" |
440 "<p>The web site you are about to visit was found in the Safe" |
439 " Browsing Database but was not classified yet.</p>") |
441 " Browsing Database but was not classified yet.</p>", |
440 |
442 ) |
|
443 |
441 return msg |
444 return msg |
442 |
445 |
443 @classmethod |
446 @classmethod |
444 def getThreatType(cls, threatType): |
447 def getThreatType(cls, threatType): |
445 """ |
448 """ |
446 Class method to get a display string for a given threat type. |
449 Class method to get a display string for a given threat type. |
447 |
450 |
448 @param threatType threat type to get display string for |
451 @param threatType threat type to get display string for |
449 @type str |
452 @type str |
450 @return display string |
453 @return display string |
451 @rtype str |
454 @rtype str |
452 """ |
455 """ |
453 threatType = threatType.lower() |
456 threatType = threatType.lower() |
454 if threatType == "malware": |
457 if threatType == "malware": |
455 displayString = QCoreApplication.translate( |
458 displayString = QCoreApplication.translate("SafeBrowsingAPI", "Malware") |
456 "SafeBrowsingAPI", "Malware") |
|
457 elif threatType == "social_engineering": |
459 elif threatType == "social_engineering": |
458 displayString = QCoreApplication.translate( |
460 displayString = QCoreApplication.translate("SafeBrowsingAPI", "Phishing") |
459 "SafeBrowsingAPI", "Phishing") |
|
460 elif threatType == "unwanted_software": |
461 elif threatType == "unwanted_software": |
461 displayString = QCoreApplication.translate( |
462 displayString = QCoreApplication.translate( |
462 "SafeBrowsingAPI", "Unwanted Software") |
463 "SafeBrowsingAPI", "Unwanted Software" |
|
464 ) |
463 elif threatType == "potentially_harmful_application": |
465 elif threatType == "potentially_harmful_application": |
464 displayString = QCoreApplication.translate( |
466 displayString = QCoreApplication.translate( |
465 "SafeBrowsingAPI", "Harmful Application") |
467 "SafeBrowsingAPI", "Harmful Application" |
|
468 ) |
466 elif threatType == "malcious_binary": |
469 elif threatType == "malcious_binary": |
467 displayString = QCoreApplication.translate( |
470 displayString = QCoreApplication.translate( |
468 "SafeBrowsingAPI", "Malicious Binary") |
471 "SafeBrowsingAPI", "Malicious Binary" |
|
472 ) |
469 else: |
473 else: |
470 displayString = QCoreApplication.translate( |
474 displayString = QCoreApplication.translate( |
471 "SafeBrowsingAPI", "Unknown Threat") |
475 "SafeBrowsingAPI", "Unknown Threat" |
472 |
476 ) |
|
477 |
473 return displayString |
478 return displayString |
474 |
479 |
475 @classmethod |
480 @classmethod |
476 def definedThreatTypes(cls): |
481 def definedThreatTypes(cls): |
477 """ |
482 """ |
478 Class method to get all threat types defined in API v4. |
483 Class method to get all threat types defined in API v4. |
479 |
484 |
480 @return list of defined threat types |
485 @return list of defined threat types |
481 @rtype list of str |
486 @rtype list of str |
482 """ |
487 """ |
483 return [ |
488 return [ |
484 "THREAT_TYPE_UNSPECIFIED", "MALWARE", "SOCIAL_ENGINEERING", |
489 "THREAT_TYPE_UNSPECIFIED", |
485 "UNWANTED_SOFTWARE", "POTENTIALLY_HARMFUL_APPLICATION", |
490 "MALWARE", |
|
491 "SOCIAL_ENGINEERING", |
|
492 "UNWANTED_SOFTWARE", |
|
493 "POTENTIALLY_HARMFUL_APPLICATION", |
486 ] |
494 ] |
487 |
495 |
488 @classmethod |
496 @classmethod |
489 def getThreatEntryString(cls, threatEntry): |
497 def getThreatEntryString(cls, threatEntry): |
490 """ |
498 """ |
491 Class method to get the threat entry string. |
499 Class method to get the threat entry string. |
492 |
500 |
493 @param threatEntry threat entry type as defined in the v4 API |
501 @param threatEntry threat entry type as defined in the v4 API |
494 @type str |
502 @type str |
495 @return threat entry string |
503 @return threat entry string |
496 @rtype str |
504 @rtype str |
497 """ |
505 """ |
498 if threatEntry == "URL": |
506 if threatEntry == "URL": |
499 return "URL" |
507 return "URL" |
500 elif threatEntry == "EXECUTABLE": |
508 elif threatEntry == "EXECUTABLE": |
501 return QCoreApplication.translate( |
509 return QCoreApplication.translate("SafeBrowsingAPI", "executable program") |
502 "SafeBrowsingAPI", "executable program") |
510 else: |
503 else: |
511 return QCoreApplication.translate("SafeBrowsingAPI", "unknown type") |
504 return QCoreApplication.translate( |
512 |
505 "SafeBrowsingAPI", "unknown type") |
|
506 |
|
507 @classmethod |
513 @classmethod |
508 def definedThreatEntryTypes(cls): |
514 def definedThreatEntryTypes(cls): |
509 """ |
515 """ |
510 Class method to get all threat entry types defined in API v4. |
516 Class method to get all threat entry types defined in API v4. |
511 |
517 |
512 @return list of all defined threat entry types |
518 @return list of all defined threat entry types |
513 @rtype list of str |
519 @rtype list of str |
514 """ |
520 """ |
515 return [ |
521 return [ |
516 "THREAT_ENTRY_TYPE_UNSPECIFIED", "URL", "EXECUTABLE", |
522 "THREAT_ENTRY_TYPE_UNSPECIFIED", |
|
523 "URL", |
|
524 "EXECUTABLE", |
517 ] |
525 ] |
518 |
526 |
519 @classmethod |
527 @classmethod |
520 def getPlatformString(cls, platformType): |
528 def getPlatformString(cls, platformType): |
521 """ |
529 """ |
522 Class method to get the platform string for a given platform type. |
530 Class method to get the platform string for a given platform type. |
523 |
531 |
524 @param platformType platform type as defined in the v4 API |
532 @param platformType platform type as defined in the v4 API |
525 @type str |
533 @type str |
526 @return platform string |
534 @return platform string |
527 @rtype str |
535 @rtype str |
528 """ |
536 """ |
534 "IOS": "iOS", |
542 "IOS": "iOS", |
535 "CHROME": "Chrome OS", |
543 "CHROME": "Chrome OS", |
536 } |
544 } |
537 if platformType in platformStrings: |
545 if platformType in platformStrings: |
538 return platformStrings[platformType] |
546 return platformStrings[platformType] |
539 |
547 |
540 if platformType == "ANY_PLATFORM": |
548 if platformType == "ANY_PLATFORM": |
541 return QCoreApplication.translate( |
549 return QCoreApplication.translate("SafeBrowsingAPI", "any defined platform") |
542 "SafeBrowsingAPI", "any defined platform") |
|
543 elif platformType == "ALL_PLATFORMS": |
550 elif platformType == "ALL_PLATFORMS": |
544 return QCoreApplication.translate( |
551 return QCoreApplication.translate( |
545 "SafeBrowsingAPI", "all defined platforms") |
552 "SafeBrowsingAPI", "all defined platforms" |
546 else: |
553 ) |
547 return QCoreApplication.translate( |
554 else: |
548 "SafeBrowsingAPI", "unknown platform") |
555 return QCoreApplication.translate("SafeBrowsingAPI", "unknown platform") |
549 |
556 |
550 @classmethod |
557 @classmethod |
551 def getPlatformTypes(cls, platform): |
558 def getPlatformTypes(cls, platform): |
552 """ |
559 """ |
553 Class method to get the platform types for a given platform. |
560 Class method to get the platform types for a given platform. |
554 |
561 |
555 @param platform platform string |
562 @param platform platform string |
556 @type str (one of 'linux', 'windows', 'macos') |
563 @type str (one of 'linux', 'windows', 'macos') |
557 @return list of platform types as defined in the v4 API for the |
564 @return list of platform types as defined in the v4 API for the |
558 given platform |
565 given platform |
559 @rtype list of str |
566 @rtype list of str |
560 @exception ValueError raised to indicate an invalid platform string |
567 @exception ValueError raised to indicate an invalid platform string |
561 """ |
568 """ |
562 platform = platform.lower() |
569 platform = platform.lower() |
563 |
570 |
564 if platform not in ("linux", "windows", "macos"): |
571 if platform not in ("linux", "windows", "macos"): |
565 raise ValueError("Unsupported platform") |
572 raise ValueError("Unsupported platform") |
566 |
573 |
567 platformTypes = ["ANY_PLATFORM", "ALL_PLATFORMS"] |
574 platformTypes = ["ANY_PLATFORM", "ALL_PLATFORMS"] |
568 if platform == "linux": |
575 if platform == "linux": |
569 platformTypes.append("LINUX") |
576 platformTypes.append("LINUX") |
570 elif platform == "windows": |
577 elif platform == "windows": |
571 platformTypes.append("WINDOWS") |
578 platformTypes.append("WINDOWS") |
572 else: |
579 else: |
573 platformTypes.append("OSX") |
580 platformTypes.append("OSX") |
574 |
581 |
575 return platformTypes |
582 return platformTypes |
576 |
583 |
577 @classmethod |
584 @classmethod |
578 def definedPlatformTypes(cls): |
585 def definedPlatformTypes(cls): |
579 """ |
586 """ |
580 Class method to get all platform types defined in API v4. |
587 Class method to get all platform types defined in API v4. |
581 |
588 |
582 @return list of all defined platform types |
589 @return list of all defined platform types |
583 @rtype list of str |
590 @rtype list of str |
584 """ |
591 """ |
585 return [ |
592 return [ |
586 "PLATFORM_TYPE_UNSPECIFIED", "WINDOWS", "LINUX", "ANDROID", "OSX", |
593 "PLATFORM_TYPE_UNSPECIFIED", |
587 "IOS", "ANY_PLATFORM", "ALL_PLATFORMS", "CHROME", |
594 "WINDOWS", |
|
595 "LINUX", |
|
596 "ANDROID", |
|
597 "OSX", |
|
598 "IOS", |
|
599 "ANY_PLATFORM", |
|
600 "ALL_PLATFORMS", |
|
601 "CHROME", |
588 ] |
602 ] |