WebBrowser/SafeBrowsing/SafeBrowsingAPIClient.py

changeset 6234
fb1f9e681848
parent 6233
a64b986abb54
child 6645
ad476851d7e0
diff -r a64b986abb54 -r fb1f9e681848 WebBrowser/SafeBrowsing/SafeBrowsingAPIClient.py
--- a/WebBrowser/SafeBrowsing/SafeBrowsingAPIClient.py	Wed Apr 11 19:57:23 2018 +0200
+++ b/WebBrowser/SafeBrowsing/SafeBrowsingAPIClient.py	Thu Apr 12 19:12:36 2018 +0200
@@ -62,7 +62,7 @@
         # key: URL as string
         # value: dictionary with these entries:
         #   "validUntil": (QDateTime)
-        #   "threatInfo": (ThreatList)
+        #   "threatInfo": (list of ThreatList)
     
     def setApiKey(self, apiKey):
         """
@@ -77,9 +77,9 @@
         """
         Public method to retrieve all available threat lists.
         
-        @return list of threat lists
-        @rtype list of dict containing 'threatType', 'platformType' and
-            'threatEntryType'
+        @return tuple containing list of threat lists and an error message
+        @rtype tuple of (list of dict containing 'threatType', 'platformType'
+            and 'threatEntryType', bool)
         """
         url = QUrl(self.GsbUrlTemplate.format("threatLists", self.__apiKey))
         req = QNetworkRequest(url)
@@ -90,14 +90,16 @@
             # max. 200 ms processing
         
         res = None
+        error = ""
         if reply.error() != QNetworkReply.NoError:
-            self.networkError.emit(reply.errorString())
+            error = reply.errorString()
+            self.networkError.emit(error)
         else:
             result = self.__extractData(reply)
             res = result["threatLists"]
         
         reply.deleteLater()
-        return res
+        return res, error
     
     #######################################################################
     ## Methods below implement the 'Update API (v4)'
@@ -110,8 +112,9 @@
         @param clientStates dictionary of client states with keys like
             (threatType, platformType, threatEntryType)
         @type dict
-        @return list of threat updates
-        @rtype list of dict
+        @return tuple containing the list of threat updates and an error
+            message
+        @rtype tuple of (list of dict, bool)
         """
         requestBody = {
             "client": {
@@ -147,14 +150,16 @@
             # max. 200 ms processing
         
         res = None
+        error = ""
         if reply.error() != QNetworkReply.NoError:
-            self.networkError.emit(reply.errorString())
+            error = reply.errorString()
+            self.networkError.emit(error)
         else:
             result = self.__extractData(reply)
             res = result["listUpdateResponses"]
         
         reply.deleteLater()
-        return res
+        return res, error
     
     def getFullHashes(self, prefixes, clientState):
         """
@@ -212,7 +217,7 @@
             QCoreApplication.processEvents(QEventLoop.AllEvents, 200)
             # max. 200 ms processing
         
-        res = None
+        res = []
         if reply.error() != QNetworkReply.NoError:
             self.networkError.emit(reply.errorString())
         else:
@@ -281,34 +286,38 @@
         @type QUrl
         @param platforms list of platform types to check against
         @type list of str
-        @return list of threat list info objects
-        @rtype list of ThreatList
+        @return tuple containing the list of threat list info objects and
+            an error message
+        @rtype tuple of (list of ThreatList, str)
         """
+        error = ""
+        
         # sanitize the URL by removing user info and query data
         url = url.adjusted(
             QUrl.RemoveUserInfo | QUrl.RemoveQuery | QUrl.RemoveFragment
         )
         urlStr = url.toString()
+        
+        # check the local cache first
         if urlStr in self.__lookupApiCache:
             if self.__lookupApiCache[urlStr]["validUntil"] > \
                QDateTime.currentDateTime():
                 # cached entry is still valid
-                return self.__lookupApiCache[urlStr]["threatInfo"]
+                return self.__lookupApiCache[urlStr]["threatInfo"], error
             else:
                 del self.__lookupApiCache[urlStr]
         
+        # no valid entry found, ask the safe browsing server
         requestBody = {
             "client": {
                 "clientId": self.ClientId,
                 "clientVersion": self.ClientVersion,
             },
             "threatInfo": {
-                "threatTypes": [
-                    "MALWARE", "SOCIAL_ENGINEERING", "UNWANTED_SOFTWARE",
-                    "POTENTIALLY_HARMFUL_APPLICATION",
-                ],
+                "threatTypes": SafeBrowsingAPIClient.definedThreatTypes(),
                 "platformTypes": platforms,
-                "threatEntryTypes": ["URL", "EXECUTABLE"],
+                "threatEntryTypes":
+                    SafeBrowsingAPIClient.definedThreatEntryTypes(),
                 "threatEntries": [
                     {"url": urlStr},
                 ],
@@ -328,7 +337,8 @@
         
         threats = []
         if reply.error() != QNetworkReply.NoError:
-            self.networkError.emit(reply.errorString())
+            error = reply.errorString()
+            self.networkError.emit(error)
         else:
             res = json.loads(str(reply.readAll(), "utf-8"))
             if res and "matches" in res:
@@ -355,7 +365,7 @@
                     }
         
         reply.deleteLater()
-        return threats
+        return threats, error
     
     #######################################################################
     ## Methods below implement global (class wide) functionality
@@ -449,6 +459,50 @@
         return displayString
     
     @classmethod
+    def definedThreatTypes(cls):
+        """
+        Class method to get all threat types defined in API v4.
+        
+        @return list of defined threat types
+        @rtype list of str
+        """
+        return [
+            "THREAT_TYPE_UNSPECIFIED", "MALWARE", "SOCIAL_ENGINEERING",
+            "UNWANTED_SOFTWARE", "POTENTIALLY_HARMFUL_APPLICATION",
+        ]
+    
+    @classmethod
+    def getThreatEntryString(cls, threatEntry):
+        """
+        Class method to get the threat entry string.
+        
+        @param threatEntry threat entry type as defined in the v4 API
+        @type str
+        @return threat entry string
+        @rtype str
+        """
+        if threatEntry == "URL":
+            return "URL"
+        elif threatEntry == "EXECUTABLE":
+            return QCoreApplication.translate(
+                "SafeBrowsingAPI", "executable program")
+        else:
+            return QCoreApplication.translate(
+                "SafeBrowsingAPI", "unknown type")
+    
+    @classmethod
+    def definedThreatEntryTypes(cls):
+        """
+        Class method to get all threat entry types defined in API v4.
+        
+        @return list of all defined threat entry types
+        @rtype list of str
+        """
+        return [
+            "THREAT_ENTRY_TYPE_UNSPECIFIED", "URL", "EXECUTABLE",
+        ]
+    
+    @classmethod
     def getPlatformString(cls, platformType):
         """
         Class method to get the platform string for a given platform type.
@@ -480,25 +534,6 @@
                 "SafeBrowsingAPI", "unknown platform")
     
     @classmethod
-    def getThreatEntryString(cls, threatEntry):
-        """
-        Class method to get the threat entry string.
-        
-        @param threatEntry threat entry type as defined in the v4 API
-        @type str
-        @return threat entry string
-        @rtype str
-        """
-        if threatEntry == "URL":
-            return "URL"
-        elif threatEntry == "EXECUTABLE":
-            return QCoreApplication.translate(
-                "SafeBrowsingAPI", "executable program")
-        else:
-            return QCoreApplication.translate(
-                "SafeBrowsingAPI", "unknown type")
-    
-    @classmethod
     def getPlatformTypes(cls, platform):
         """
         Class method to get the platform types for a given platform.
@@ -523,3 +558,16 @@
             raise ValueError("Unsupported platform")
         
         return platformTypes
+    
+    @classmethod
+    def definedPlatformTypes(cls):
+        """
+        Class method to get all platform types defined in API v4.
+        
+        @return list of all defined platform types
+        @rtype list of str
+        """
+        return [
+            "PLATFORM_TYPE_UNSPECIFIED", "WINDOWS", "LINUX", "ANDROID", "OSX",
+            "IOS", "ANY_PLATFORM", "ALL_PLATFORMS", "CHROME",
+        ]

eric ide

mercurial