Add support for reduced initial build count for new possible abusing users
If configured, we now check the IP address of the user signing up and, if they are a possible threat, we further reduce their number of allowed maximum builds to the configured value.
This commit is contained in:
parent
8d5e8fc685
commit
3309daa32e
7 changed files with 81 additions and 28 deletions
|
@ -1,16 +1,16 @@
|
|||
import logging
|
||||
import json
|
||||
import requests
|
||||
|
||||
from collections import namedtuple, defaultdict
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from six import add_metaclass
|
||||
|
||||
from cachetools import ttl_cache, lru_cache
|
||||
from collections import namedtuple, defaultdict
|
||||
from netaddr import IPNetwork, IPAddress, IPSet, AddrFormatError
|
||||
|
||||
import geoip2.database
|
||||
import geoip2.errors
|
||||
import requests
|
||||
|
||||
from util.abchelpers import nooper
|
||||
|
||||
|
@ -44,6 +44,13 @@ class IPResolverInterface(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def is_ip_possible_threat(self, ip_address):
|
||||
""" Attempts to return whether the given IP address is a possible abuser or spammer.
|
||||
Returns False if the IP address information could not be looked up.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
@nooper
|
||||
class NoopIPResolver(IPResolverInterface):
|
||||
|
@ -56,14 +63,39 @@ class IPResolver(IPResolverInterface):
|
|||
self.app = app
|
||||
self.geoip_db = geoip2.database.Reader('util/ipresolver/GeoLite2-Country.mmdb')
|
||||
|
||||
@ttl_cache(maxsize=100, ttl=600)
|
||||
def is_ip_possible_threat(self, ip_address):
|
||||
if self.app.config.get('THREAT_NAMESPACE_MAXIMUM_BUILD_COUNT') is None:
|
||||
return False
|
||||
|
||||
if not ip_address:
|
||||
return False
|
||||
|
||||
try:
|
||||
logger.debug('Requesting IP data for IP %s', ip_address)
|
||||
r = requests.get('https://api.ipdata.co/%s/en' % ip_address, timeout=1)
|
||||
if r.status_code != 200:
|
||||
logger.debug('Got non-200 response for IP %s: %s', ip_address, r.status_code)
|
||||
return False
|
||||
|
||||
logger.debug('Got IP data for IP %s: %s => %s', ip_address, r.status_code, r.json)
|
||||
threat_data = r.json.get('threat', {})
|
||||
return threat_data.get('is_threat', False) or threat_data.get('is_bogon', False)
|
||||
except requests.RequestException:
|
||||
logger.exception('Got exception when trying to lookup IP Address')
|
||||
except ValueError:
|
||||
logger.exception('Got exception when trying to lookup IP Address')
|
||||
|
||||
return False
|
||||
|
||||
def resolve_ip(self, ip_address):
|
||||
""" Attempts to return resolved information about the specified IP Address. If such an attempt fails,
|
||||
returns None.
|
||||
""" Attempts to return resolved information about the specified IP Address. If such an attempt
|
||||
fails, returns None.
|
||||
"""
|
||||
location_function = self._get_location_function()
|
||||
if not ip_address or not location_function:
|
||||
return None
|
||||
|
||||
|
||||
return location_function(ip_address)
|
||||
|
||||
def _get_aws_ip_ranges(self):
|
||||
|
@ -79,7 +111,7 @@ class IPResolver(IPResolverInterface):
|
|||
except TypeError:
|
||||
logger.exception('Could not load AWS IP Ranges')
|
||||
return None
|
||||
|
||||
|
||||
@ttl_cache(maxsize=1, ttl=600)
|
||||
def _get_location_function(self):
|
||||
aws_ip_range_json = self._get_aws_ip_ranges()
|
||||
|
@ -88,7 +120,8 @@ class IPResolver(IPResolverInterface):
|
|||
|
||||
sync_token = aws_ip_range_json['syncToken']
|
||||
all_amazon, regions, services = IPResolver._parse_amazon_ranges(aws_ip_range_json)
|
||||
return IPResolver._build_location_function(sync_token, all_amazon, regions, services, self.geoip_db)
|
||||
return IPResolver._build_location_function(sync_token, all_amazon, regions, services,
|
||||
self.geoip_db)
|
||||
|
||||
@staticmethod
|
||||
def _build_location_function(sync_token, all_amazon, regions, country, country_db):
|
||||
|
|
Reference in a new issue