From 70cb4f77d4b5fa2dbf0c0506031215b1af9b2888 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 25 Sep 2020 09:06:36 -0700 Subject: [PATCH 1/3] Upgrade to geoip2 with is_residential_proxy --- HISTORY.rst | 8 ++++++++ setup.py | 2 +- tests/data/factors-response.json | 1 + tests/data/insights-response.json | 1 + tests/test_models.py | 2 ++ tests/test_webservice.py | 1 + 6 files changed, 14 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index fce583b..8b5b317 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,6 +3,14 @@ History ------- +2.1.0 +++++++++++++++++++ + +* Added ``response.ip_address.traits.is_residential_proxy`` to the + minFraud Insights and Factors models. This indicates whether the IP + address is on a suspected anonymizing network and belongs to a + residential ISP. + 2.0.3 (2020-07-28) ++++++++++++++++++ diff --git a/setup.py b/setup.py index 4478436..05ec838 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ requirements = [ "aiohttp>=3.6.2,<4.0.0", "email_validator>=1.1.1,<2.0.0", - "geoip2>=4.0.0,<5.0.0", + "geoip2>=4.1.0,<5.0.0", "requests>=2.24.0,<3.0.0", "urllib3>=1.25.2,<2.0.0", "voluptuous", diff --git a/tests/data/factors-response.json b/tests/data/factors-response.json index 7b93b66..acd4d86 100644 --- a/tests/data/factors-response.json +++ b/tests/data/factors-response.json @@ -94,6 +94,7 @@ "is_anonymous_vpn": true, "is_hosting_provider": true, "is_public_proxy": true, + "is_residential_proxy": true, "is_satellite_provider": true, "is_tor_exit_node": true, "isp": "Andrews & Arnold Ltd", diff --git a/tests/data/insights-response.json b/tests/data/insights-response.json index fe0043d..b9d73b0 100644 --- a/tests/data/insights-response.json +++ b/tests/data/insights-response.json @@ -94,6 +94,7 @@ "is_anonymous_vpn": true, "is_hosting_provider": true, "is_public_proxy": true, + "is_residential_proxy": true, "is_satellite_provider": true, "is_tor_exit_node": true, "isp": "Andrews & Arnold Ltd", diff --git a/tests/test_models.py b/tests/test_models.py index f8963e8..cbf96c6 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -160,6 +160,7 @@ def test_ip_address(self): "is_anonymous_vpn": True, "is_hosting_provider": True, "is_public_proxy": True, + "is_residential_proxy": True, "is_satellite_provider": True, "is_tor_exit_node": True, }, @@ -175,6 +176,7 @@ def test_ip_address(self): self.assertEqual(True, address.traits.is_anonymous_vpn) self.assertEqual(True, address.traits.is_hosting_provider) self.assertEqual(True, address.traits.is_public_proxy) + self.assertEqual(True, address.traits.is_residential_proxy) self.assertEqual(True, address.traits.is_satellite_provider) self.assertEqual(True, address.traits.is_tor_exit_node) self.assertEqual(True, address.country.is_high_risk) diff --git a/tests/test_webservice.py b/tests/test_webservice.py index e69f9c3..2d786e3 100644 --- a/tests/test_webservice.py +++ b/tests/test_webservice.py @@ -195,6 +195,7 @@ def test_200(self): self.assertEqual(self.cls(response), model) if self.has_ip_location(): self.assertEqual("United Kingdom", model.ip_address.country.name) + self.assertEqual(True, model.ip_address.traits.is_residential_proxy) @httprettified def test_200_on_request_with_nones(self): From a7706189b9ac0f3424032a1ddba5f466a9eb0678 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 25 Sep 2020 09:14:21 -0700 Subject: [PATCH 2/3] Include the decode response content in HTTPError exceptions --- HISTORY.rst | 2 ++ minfraud/errors.py | 17 ++++++++++++++++- minfraud/webservice.py | 23 ++++++++++++++++++----- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 8b5b317..598ee47 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -10,6 +10,8 @@ History minFraud Insights and Factors models. This indicates whether the IP address is on a suspected anonymizing network and belongs to a residential ISP. +* ``HTTPError`` now provides the decoded response content in the + ``decoded_content`` attribute. 2.0.3 (2020-07-28) ++++++++++++++++++ diff --git a/minfraud/errors.py b/minfraud/errors.py index 4e8d93c..ad30b01 100644 --- a/minfraud/errors.py +++ b/minfraud/errors.py @@ -39,14 +39,29 @@ class HTTPError(MinFraudError): :type: str + .. attribute:: decoded_content: + + The decoded response content + + :type: str + """ + http_status: Optional[int] + uri: Optional[str] + decoded_content: Optional[str] + def __init__( - self, message: str, http_status: Optional[int] = None, uri: Optional[str] = None + self, + message: str, + http_status: Optional[int] = None, + uri: Optional[str] = None, + decoded_content: Optional[str] = None, ) -> None: super().__init__(message) self.http_status = http_status self.uri = uri + self.decoded_content = decoded_content class InvalidRequestError(MinFraudError): diff --git a/minfraud/webservice.py b/minfraud/webservice.py index 093feb1..00898c5 100644 --- a/minfraud/webservice.py +++ b/minfraud/webservice.py @@ -136,8 +136,8 @@ def _exception_for_error( if 400 <= status < 500: return self._exception_for_4xx_status(status, content_type, body, uri) if 500 <= status < 600: - return self._exception_for_5xx_status(status, uri) - return self._exception_for_unexpected_status(status, uri) + return self._exception_for_5xx_status(status, body, uri) + return self._exception_for_unexpected_status(status, body, uri) def _exception_for_4xx_status( self, status: int, content_type: str, body: str, uri: str @@ -151,13 +151,14 @@ def _exception_for_4xx_status( """Returns exception for error responses with 4xx status codes.""" if not body: return HTTPError( - "Received a {0} error with no body".format(status), status, uri + "Received a {0} error with no body".format(status), status, uri, body ) if content_type.find("json") == -1: return HTTPError( "Received a {0} with the following " "body: {1}".format(status, body), status, uri, + body, ) try: decoded_body = json.loads(body) @@ -169,6 +170,7 @@ def _exception_for_4xx_status( ), status, uri, + body, ) else: if "code" in decoded_body and "error" in decoded_body: @@ -180,6 +182,7 @@ def _exception_for_4xx_status( " or error keys: {0}".format(body), status, uri, + body, ) @staticmethod @@ -207,21 +210,31 @@ def _exception_for_web_service_error( return InvalidRequestError(message, code, status, uri) @staticmethod - def _exception_for_5xx_status(status: int, uri: str) -> HTTPError: + def _exception_for_5xx_status( + status: int, + body: Optional[str], + uri: str, + ) -> HTTPError: """Returns exception for error response with 5xx status codes.""" return HTTPError( u"Received a server error ({0}) for " u"{1}".format(status, uri), status, uri, + body, ) @staticmethod - def _exception_for_unexpected_status(status: int, uri: str) -> HTTPError: + def _exception_for_unexpected_status( + status: int, + body: Optional[str], + uri: str, + ) -> HTTPError: """Returns exception for responses with unexpected status codes.""" return HTTPError( u"Received an unexpected HTTP status " u"({0}) for {1}".format(status, uri), status, uri, + body, ) From 21f61e942d5cc2a9f621a8b69ed6c3323082d410 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 25 Sep 2020 09:23:22 -0700 Subject: [PATCH 3/3] Set release date --- HISTORY.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 598ee47..cb68783 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,7 +3,7 @@ History ------- -2.1.0 +2.1.0 (2020-09-25) ++++++++++++++++++ * Added ``response.ip_address.traits.is_residential_proxy`` to the