diff --git a/CHANGELOG.md b/CHANGELOG.md index 561ce7b..db52e7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ * Added new network utilities to fetch IP and country information from a host. - The country information is fetched using the free `ip-api.com` service. NOTE! This service is rate limited to 150 requests per minute and requires a paid plan for commercial usage. Please make sure to respect the terms. + The country information is fetched using the free `ipdata.co` service. NOTE! This service is rate limited to 1500 requests per day. ### Changed diff --git a/federation/tests/utils/test_network.py b/federation/tests/utils/test_network.py index d1520c9..7c4543b 100644 --- a/federation/tests/utils/test_network.py +++ b/federation/tests/utils/test_network.py @@ -8,17 +8,14 @@ from federation.utils.network import ( fetch_document, USER_AGENT, send_document, fetch_country_by_ip, fetch_host_ip_and_country) -@patch('federation.utils.network.requests.get', autospec=True, return_value=Mock( - status_code=200, json=Mock(return_value={'countryCode': 'FI'}), -)) +@patch('federation.utils.network.ipdata', autospec=True) class TestFetchCountryByIp: - def test_calls_ip_api_endpoint(self, mock_get): - fetch_country_by_ip('127.0.0.1') - mock_get.assert_called_once_with('http://ip-api.com/json/127.0.0.1"') - - def test_returns_country_code(self, mock_get): - result = fetch_country_by_ip('127.0.0.1') - assert result == 'FI' + def test_calls_ip_api_endpoint(self, mock_ipdata): + mock_lookup = Mock(lookup=Mock(return_value={'status': 200, 'response': {'country_code': 'DE'}})) + mock_ipdata.ipdata.return_value = mock_lookup + country = fetch_country_by_ip('127.0.0.1') + mock_lookup.lookup.assert_called_once_with('127.0.0.1') + assert country == 'DE' class TestFetchDocument: diff --git a/federation/utils/network.py b/federation/utils/network.py index fafdea5..367a2c2 100644 --- a/federation/utils/network.py +++ b/federation/utils/network.py @@ -2,6 +2,7 @@ import logging import socket import requests +from ipdata import ipdata from requests.exceptions import RequestException, HTTPError, SSLError from requests.exceptions import ConnectionError from requests.structures import CaseInsensitiveDict @@ -19,19 +20,18 @@ def fetch_country_by_ip(ip): Returns empty string if the request fails in non-200 code. - Uses the ip-api.com service which has the following rules: + Uses the ipdata.co service which has the following rules: - * Max 150 requests per minute - * Non-commercial use only without a paid plan! + * Max 1500 requests per day - See: http://ip-api.com/docs/api:json + See: https://ipdata.co/docs.html#python-library """ - result = requests.get("http://ip-api.com/json/%s" % ip) - if result.status_code != 200: + iplookup = ipdata.ipdata() + data = iplookup.lookup(ip) + if data.get('status') != 200: return '' - result = result.json() - return result['countryCode'] + return data.get('response', {}).get('country_code', '') def fetch_document(url=None, host=None, path="/", timeout=10, raise_ssl_errors=True): diff --git a/setup.py b/setup.py index 4d0a051..fe15c91 100644 --- a/setup.py +++ b/setup.py @@ -30,6 +30,7 @@ setup( "cssselect>=0.9.2", "dirty-validators>=0.3.0", "lxml>=3.4.0", + "ipdata>=2.6", "jsonschema>=2.0.0", "pycrypto>=2.6.0", "python-dateutil>=2.4.0", @@ -52,5 +53,5 @@ setup( 'Topic :: Internet', 'Topic :: Software Development :: Libraries :: Python Modules', ], - keywords='federation diaspora federate social', + keywords='federation diaspora activitypub federate social', )