src/eric7/WebBrowser/SafeBrowsing/SafeBrowsingAPIClient.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
9 9
10 import json 10 import json
11 import base64 11 import base64
12 12
13 from PyQt6.QtCore import ( 13 from PyQt6.QtCore import (
14 pyqtSignal, QObject, QDateTime, QUrl, QByteArray, QCoreApplication, 14 pyqtSignal,
15 QEventLoop 15 QObject,
16 QDateTime,
17 QUrl,
18 QByteArray,
19 QCoreApplication,
20 QEventLoop,
16 ) 21 )
17 from PyQt6.QtNetwork import QNetworkRequest, QNetworkReply 22 from PyQt6.QtNetwork import QNetworkRequest, QNetworkReply
18 23
19 from WebBrowser.WebBrowserWindow import WebBrowserWindow 24 from WebBrowser.WebBrowserWindow import WebBrowserWindow
20 25
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 ]

eric ide

mercurial