WebBrowser/SafeBrowsing/SafeBrowsingAPIClient.py

changeset 6234
fb1f9e681848
parent 6233
a64b986abb54
child 6645
ad476851d7e0
equal deleted inserted replaced
6233:a64b986abb54 6234:fb1f9e681848
60 self.__lookupApiCache = {} 60 self.__lookupApiCache = {}
61 # Temporary cache used by the lookup API (v4) 61 # Temporary cache used by the lookup API (v4)
62 # key: URL as string 62 # key: URL as string
63 # value: dictionary with these entries: 63 # value: dictionary with these entries:
64 # "validUntil": (QDateTime) 64 # "validUntil": (QDateTime)
65 # "threatInfo": (ThreatList) 65 # "threatInfo": (list of ThreatList)
66 66
67 def setApiKey(self, apiKey): 67 def setApiKey(self, apiKey):
68 """ 68 """
69 Public method to set the API key. 69 Public method to set the API key.
70 70
75 75
76 def getThreatLists(self): 76 def getThreatLists(self):
77 """ 77 """
78 Public method to retrieve all available threat lists. 78 Public method to retrieve all available threat lists.
79 79
80 @return list of threat lists 80 @return tuple containing list of threat lists and an error message
81 @rtype list of dict containing 'threatType', 'platformType' and 81 @rtype tuple of (list of dict containing 'threatType', 'platformType'
82 'threatEntryType' 82 and 'threatEntryType', bool)
83 """ 83 """
84 url = QUrl(self.GsbUrlTemplate.format("threatLists", self.__apiKey)) 84 url = QUrl(self.GsbUrlTemplate.format("threatLists", self.__apiKey))
85 req = QNetworkRequest(url) 85 req = QNetworkRequest(url)
86 reply = WebBrowserWindow.networkManager().get(req) 86 reply = WebBrowserWindow.networkManager().get(req)
87 87
88 while reply.isRunning(): 88 while reply.isRunning():
89 QCoreApplication.processEvents(QEventLoop.AllEvents, 200) 89 QCoreApplication.processEvents(QEventLoop.AllEvents, 200)
90 # max. 200 ms processing 90 # max. 200 ms processing
91 91
92 res = None 92 res = None
93 error = ""
93 if reply.error() != QNetworkReply.NoError: 94 if reply.error() != QNetworkReply.NoError:
94 self.networkError.emit(reply.errorString()) 95 error = reply.errorString()
96 self.networkError.emit(error)
95 else: 97 else:
96 result = self.__extractData(reply) 98 result = self.__extractData(reply)
97 res = result["threatLists"] 99 res = result["threatLists"]
98 100
99 reply.deleteLater() 101 reply.deleteLater()
100 return res 102 return res, error
101 103
102 ####################################################################### 104 #######################################################################
103 ## Methods below implement the 'Update API (v4)' 105 ## Methods below implement the 'Update API (v4)'
104 ####################################################################### 106 #######################################################################
105 107
108 Public method to fetch hash prefix updates for the given threat list. 110 Public method to fetch hash prefix updates for the given threat list.
109 111
110 @param clientStates dictionary of client states with keys like 112 @param clientStates dictionary of client states with keys like
111 (threatType, platformType, threatEntryType) 113 (threatType, platformType, threatEntryType)
112 @type dict 114 @type dict
113 @return list of threat updates 115 @return tuple containing the list of threat updates and an error
114 @rtype list of dict 116 message
117 @rtype tuple of (list of dict, bool)
115 """ 118 """
116 requestBody = { 119 requestBody = {
117 "client": { 120 "client": {
118 "clientId": self.ClientId, 121 "clientId": self.ClientId,
119 "clientVersion": self.ClientVersion, 122 "clientVersion": self.ClientVersion,
145 while reply.isRunning(): 148 while reply.isRunning():
146 QCoreApplication.processEvents(QEventLoop.AllEvents, 200) 149 QCoreApplication.processEvents(QEventLoop.AllEvents, 200)
147 # max. 200 ms processing 150 # max. 200 ms processing
148 151
149 res = None 152 res = None
153 error = ""
150 if reply.error() != QNetworkReply.NoError: 154 if reply.error() != QNetworkReply.NoError:
151 self.networkError.emit(reply.errorString()) 155 error = reply.errorString()
156 self.networkError.emit(error)
152 else: 157 else:
153 result = self.__extractData(reply) 158 result = self.__extractData(reply)
154 res = result["listUpdateResponses"] 159 res = result["listUpdateResponses"]
155 160
156 reply.deleteLater() 161 reply.deleteLater()
157 return res 162 return res, error
158 163
159 def getFullHashes(self, prefixes, clientState): 164 def getFullHashes(self, prefixes, clientState):
160 """ 165 """
161 Public method to find full hashes matching hash prefixes. 166 Public method to find full hashes matching hash prefixes.
162 167
210 215
211 while reply.isRunning(): 216 while reply.isRunning():
212 QCoreApplication.processEvents(QEventLoop.AllEvents, 200) 217 QCoreApplication.processEvents(QEventLoop.AllEvents, 200)
213 # max. 200 ms processing 218 # max. 200 ms processing
214 219
215 res = None 220 res = []
216 if reply.error() != QNetworkReply.NoError: 221 if reply.error() != QNetworkReply.NoError:
217 self.networkError.emit(reply.errorString()) 222 self.networkError.emit(reply.errorString())
218 else: 223 else:
219 res = self.__extractData(reply) 224 res = self.__extractData(reply)
220 225
279 284
280 @param url URL to be checked 285 @param url URL to be checked
281 @type QUrl 286 @type QUrl
282 @param platforms list of platform types to check against 287 @param platforms list of platform types to check against
283 @type list of str 288 @type list of str
284 @return list of threat list info objects 289 @return tuple containing the list of threat list info objects and
285 @rtype list of ThreatList 290 an error message
286 """ 291 @rtype tuple of (list of ThreatList, str)
292 """
293 error = ""
294
287 # sanitize the URL by removing user info and query data 295 # sanitize the URL by removing user info and query data
288 url = url.adjusted( 296 url = url.adjusted(
289 QUrl.RemoveUserInfo | QUrl.RemoveQuery | QUrl.RemoveFragment 297 QUrl.RemoveUserInfo | QUrl.RemoveQuery | QUrl.RemoveFragment
290 ) 298 )
291 urlStr = url.toString() 299 urlStr = url.toString()
300
301 # check the local cache first
292 if urlStr in self.__lookupApiCache: 302 if urlStr in self.__lookupApiCache:
293 if self.__lookupApiCache[urlStr]["validUntil"] > \ 303 if self.__lookupApiCache[urlStr]["validUntil"] > \
294 QDateTime.currentDateTime(): 304 QDateTime.currentDateTime():
295 # cached entry is still valid 305 # cached entry is still valid
296 return self.__lookupApiCache[urlStr]["threatInfo"] 306 return self.__lookupApiCache[urlStr]["threatInfo"], error
297 else: 307 else:
298 del self.__lookupApiCache[urlStr] 308 del self.__lookupApiCache[urlStr]
299 309
310 # no valid entry found, ask the safe browsing server
300 requestBody = { 311 requestBody = {
301 "client": { 312 "client": {
302 "clientId": self.ClientId, 313 "clientId": self.ClientId,
303 "clientVersion": self.ClientVersion, 314 "clientVersion": self.ClientVersion,
304 }, 315 },
305 "threatInfo": { 316 "threatInfo": {
306 "threatTypes": [ 317 "threatTypes": SafeBrowsingAPIClient.definedThreatTypes(),
307 "MALWARE", "SOCIAL_ENGINEERING", "UNWANTED_SOFTWARE",
308 "POTENTIALLY_HARMFUL_APPLICATION",
309 ],
310 "platformTypes": platforms, 318 "platformTypes": platforms,
311 "threatEntryTypes": ["URL", "EXECUTABLE"], 319 "threatEntryTypes":
320 SafeBrowsingAPIClient.definedThreatEntryTypes(),
312 "threatEntries": [ 321 "threatEntries": [
313 {"url": urlStr}, 322 {"url": urlStr},
314 ], 323 ],
315 }, 324 },
316 } 325 }
326 QCoreApplication.processEvents(QEventLoop.AllEvents, 200) 335 QCoreApplication.processEvents(QEventLoop.AllEvents, 200)
327 # max. 200 ms processing 336 # max. 200 ms processing
328 337
329 threats = [] 338 threats = []
330 if reply.error() != QNetworkReply.NoError: 339 if reply.error() != QNetworkReply.NoError:
331 self.networkError.emit(reply.errorString()) 340 error = reply.errorString()
341 self.networkError.emit(error)
332 else: 342 else:
333 res = json.loads(str(reply.readAll(), "utf-8")) 343 res = json.loads(str(reply.readAll(), "utf-8"))
334 if res and "matches" in res: 344 if res and "matches" in res:
335 cacheDuration = 0 345 cacheDuration = 0
336 for match in res["matches"]: 346 for match in res["matches"]:
353 "validUntil": validUntil, 363 "validUntil": validUntil,
354 "threatInfo": threats 364 "threatInfo": threats
355 } 365 }
356 366
357 reply.deleteLater() 367 reply.deleteLater()
358 return threats 368 return threats, error
359 369
360 ####################################################################### 370 #######################################################################
361 ## Methods below implement global (class wide) functionality 371 ## Methods below implement global (class wide) functionality
362 ####################################################################### 372 #######################################################################
363 373
447 "SafeBrowsingAPI", "Unknown Threat") 457 "SafeBrowsingAPI", "Unknown Threat")
448 458
449 return displayString 459 return displayString
450 460
451 @classmethod 461 @classmethod
462 def definedThreatTypes(cls):
463 """
464 Class method to get all threat types defined in API v4.
465
466 @return list of defined threat types
467 @rtype list of str
468 """
469 return [
470 "THREAT_TYPE_UNSPECIFIED", "MALWARE", "SOCIAL_ENGINEERING",
471 "UNWANTED_SOFTWARE", "POTENTIALLY_HARMFUL_APPLICATION",
472 ]
473
474 @classmethod
475 def getThreatEntryString(cls, threatEntry):
476 """
477 Class method to get the threat entry string.
478
479 @param threatEntry threat entry type as defined in the v4 API
480 @type str
481 @return threat entry string
482 @rtype str
483 """
484 if threatEntry == "URL":
485 return "URL"
486 elif threatEntry == "EXECUTABLE":
487 return QCoreApplication.translate(
488 "SafeBrowsingAPI", "executable program")
489 else:
490 return QCoreApplication.translate(
491 "SafeBrowsingAPI", "unknown type")
492
493 @classmethod
494 def definedThreatEntryTypes(cls):
495 """
496 Class method to get all threat entry types defined in API v4.
497
498 @return list of all defined threat entry types
499 @rtype list of str
500 """
501 return [
502 "THREAT_ENTRY_TYPE_UNSPECIFIED", "URL", "EXECUTABLE",
503 ]
504
505 @classmethod
452 def getPlatformString(cls, platformType): 506 def getPlatformString(cls, platformType):
453 """ 507 """
454 Class method to get the platform string for a given platform type. 508 Class method to get the platform string for a given platform type.
455 509
456 @param platformType platform type as defined in the v4 API 510 @param platformType platform type as defined in the v4 API
478 else: 532 else:
479 return QCoreApplication.translate( 533 return QCoreApplication.translate(
480 "SafeBrowsingAPI", "unknown platform") 534 "SafeBrowsingAPI", "unknown platform")
481 535
482 @classmethod 536 @classmethod
483 def getThreatEntryString(cls, threatEntry):
484 """
485 Class method to get the threat entry string.
486
487 @param threatEntry threat entry type as defined in the v4 API
488 @type str
489 @return threat entry string
490 @rtype str
491 """
492 if threatEntry == "URL":
493 return "URL"
494 elif threatEntry == "EXECUTABLE":
495 return QCoreApplication.translate(
496 "SafeBrowsingAPI", "executable program")
497 else:
498 return QCoreApplication.translate(
499 "SafeBrowsingAPI", "unknown type")
500
501 @classmethod
502 def getPlatformTypes(cls, platform): 537 def getPlatformTypes(cls, platform):
503 """ 538 """
504 Class method to get the platform types for a given platform. 539 Class method to get the platform types for a given platform.
505 540
506 @param platform platform string 541 @param platform platform string
521 platformTypes.append("OSX") 556 platformTypes.append("OSX")
522 else: 557 else:
523 raise ValueError("Unsupported platform") 558 raise ValueError("Unsupported platform")
524 559
525 return platformTypes 560 return platformTypes
561
562 @classmethod
563 def definedPlatformTypes(cls):
564 """
565 Class method to get all platform types defined in API v4.
566
567 @return list of all defined platform types
568 @rtype list of str
569 """
570 return [
571 "PLATFORM_TYPE_UNSPECIFIED", "WINDOWS", "LINUX", "ANDROID", "OSX",
572 "IOS", "ANY_PLATFORM", "ALL_PLATFORMS", "CHROME",
573 ]

eric ide

mercurial