Varken/varken/helpers.py
2019-12-31 17:25:10 -05:00

220 lines
8 KiB
Python

from hashlib import md5
from datetime import date, timedelta
from time import sleep
from logging import getLogger
from ipaddress import IPv4Address
from urllib.error import HTTPError, URLError
from geoip2.database import Reader
from tarfile import open as taropen
from urllib3 import disable_warnings
from os import stat, remove, makedirs
from urllib.request import urlretrieve
from json.decoder import JSONDecodeError
from os.path import abspath, join, basename, isdir
from urllib3.exceptions import InsecureRequestWarning
from requests.exceptions import InvalidSchema, SSLError, ConnectionError, ChunkedEncodingError
logger = getLogger()
class GeoIPHandler(object):
def __init__(self, data_folder, maxmind_license_key):
self.data_folder = data_folder
self.maxmind_license_key = maxmind_license_key
self.dbfile = abspath(join(self.data_folder, 'GeoLite2-City.mmdb'))
self.logger = getLogger()
self.reader = None
self.reader_manager(action='open')
self.logger.info('Opening persistent connection to the MaxMind DB...')
def reader_manager(self, action=None):
if action == 'open':
try:
self.reader = Reader(self.dbfile)
except FileNotFoundError:
self.logger.error("Could not find MaxMind DB! Downloading!")
result_status = self.download()
if result_status:
self.logger.error("Could not download MaxMind DB! You may need to manually install it.")
exit(1)
else:
self.reader = Reader(self.dbfile)
else:
self.reader.close()
def lookup(self, ipaddress):
ip = ipaddress
self.logger.debug('Getting lat/long for Tautulli stream using ip with last octet ending in %s',
ip.split('.')[-1:][0])
return self.reader.city(ip)
def update(self):
today = date.today()
try:
dbdate = date.fromtimestamp(stat(self.dbfile).st_mtime)
db_next_update = date.fromtimestamp(stat(self.dbfile).st_mtime) + timedelta(days=30)
except FileNotFoundError:
self.logger.error("Could not find MaxMind DB as: %s", self.dbfile)
self.download()
dbdate = date.fromtimestamp(stat(self.dbfile).st_mtime)
db_next_update = date.fromtimestamp(stat(self.dbfile).st_mtime) + timedelta(days=30)
if db_next_update < today:
self.logger.info("Newer MaxMind DB available, Updating...")
self.logger.debug("MaxMind DB date %s, DB updates after: %s, Today: %s",
dbdate, db_next_update, today)
self.reader_manager(action='close')
self.download()
self.reader_manager(action='open')
else:
db_days_update = db_next_update - today
self.logger.debug("MaxMind DB will update in %s days", abs(db_days_update.days))
self.logger.debug("MaxMind DB date %s, DB updates after: %s, Today: %s",
dbdate, db_next_update, today)
def download(self):
tar_dbfile = abspath(join(self.data_folder, 'GeoLite2-City.tar.gz'))
maxmind_url = ('https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City'
f'&suffix=tar.gz&license_key={self.maxmind_license_key}')
downloaded = False
retry_counter = 0
while not downloaded:
self.logger.info('Downloading GeoLite2 DB from MaxMind...')
try:
urlretrieve(maxmind_url, tar_dbfile)
downloaded = True
except URLError as e:
self.logger.error("Problem downloading new MaxMind DB: %s", e)
result_status = 1
return result_status
except HTTPError as e:
if e.code == 401:
self.logger.error("Your MaxMind license key is incorect! Check your config: %s", e)
result_status = 1
return result_status
else:
self.logger.error("Problem downloading new MaxMind DB... Trying again: %s", e)
sleep(2)
retry_counter = (retry_counter + 1)
if retry_counter >= 3:
self.logger.error("Retried downloading the new MaxMind DB 3 times and failed... Aborting!")
result_status = 1
return result_status
try:
remove(self.dbfile)
except FileNotFoundError:
self.logger.warning("Cannot remove MaxMind DB as it does not exist!")
self.logger.debug("Opening MaxMind tar file : %s", tar_dbfile)
tar = taropen(tar_dbfile, 'r:gz')
for files in tar.getmembers():
if 'GeoLite2-City.mmdb' in files.name:
self.logger.debug('"GeoLite2-City.mmdb" FOUND in tar file')
files.name = basename(files.name)
tar.extract(files, self.data_folder)
self.logger.debug('%s has been extracted to %s', files, self.data_folder)
tar.close()
try:
remove(tar_dbfile)
self.logger.debug('Removed the MaxMind DB tar file.')
except FileNotFoundError:
self.logger.warning("Cannot remove MaxMind DB TAR file as it does not exist!")
def hashit(string):
encoded = string.encode()
hashed = md5(encoded).hexdigest()
return hashed
def rfc1918_ip_check(ip):
rfc1918_ip = IPv4Address(ip).is_private
return rfc1918_ip
def connection_handler(session, request, verify, as_is_reply=False):
air = as_is_reply
s = session
r = request
v = verify
return_json = False
disable_warnings(InsecureRequestWarning)
try:
get = s.send(r, verify=v)
if get.status_code == 401:
if 'NoSiteContext' in str(get.content):
logger.info('Your Site is incorrect for %s', r.url)
elif 'LoginRequired' in str(get.content):
logger.info('Your login credentials are incorrect for %s', r.url)
else:
logger.info('Your api key is incorrect for %s', r.url)
elif get.status_code == 404:
logger.info('This url doesnt even resolve: %s', r.url)
elif get.status_code == 200:
try:
return_json = get.json()
except JSONDecodeError:
logger.error('No JSON response. Response is: %s', get.text)
if air:
return get
except InvalidSchema:
logger.error("You added http(s):// in the config file. Don't do that.")
except SSLError as e:
logger.error('Either your host is unreachable or you have an SSL issue. : %s', e)
except ConnectionError as e:
logger.error('Cannot resolve the url/ip/port. Check connectivity. Error: %s', e)
except ChunkedEncodingError as e:
logger.error('Broken connection during request... oops? Error: %s', e)
return return_json
def mkdir_p(path):
templogger = getLogger('temp')
try:
if not isdir(path):
templogger.info('Creating folder %s ', path)
makedirs(path, exist_ok=True)
except Exception as e:
templogger.error('Could not create folder %s : %s ', path, e)
def clean_sid_check(server_id_list, server_type=None):
t = server_type
sid_list = server_id_list
cleaned_list = sid_list.replace(' ', '').split(',')
valid_sids = []
for sid in cleaned_list:
try:
valid_sids.append(int(sid))
except ValueError:
logger.error("%s is not a valid server id number", sid)
if valid_sids:
logger.info('%s : %s', t.upper(), valid_sids)
return valid_sids
else:
logger.error('No valid %s', t.upper())
return False
def boolcheck(var):
if var.lower() in ['true', 'yes']:
return True
else:
return False
def itemgetter_with_default(**defaults):
return lambda obj: tuple(obj.get(k, v) for k, v in defaults.items())