import ipaddress import json from datetime import datetime from flask import (Blueprint, request, current_app, jsonify, render_template, abort) import strict_rfc3339 import pygeoip from ennstatus.status.functions import (single_server, all_servers, all_servers_by_type) from .model import Server api_page = Blueprint('api', __name__) gi4 = pygeoip.GeoIP('/usr/share/GeoIP/GeoIP.dat', pygeoip.MEMORY_CACHE) gi6 = pygeoip.GeoIP('/usr/share/GeoIP/GeoIPv6.dat', pygeoip.MEMORY_CACHE) @api_page.route('/update', methods=('POST',)) def update(): current_app.logger.info('Handling update') if current_app.debug: accepted_ips = ['127.0.0.1'] else: accepted_ips = current_app.config.get('ENNSTATUS_ACCEPTED_IPS', []) if request.remote_addr not in accepted_ips: current_app.logger.warn('Unallowed IP %s tried to update data!' % request.remote_addr) return 'IP not allowed!\n', 403, {'Content-Type': 'text/plain'} data = request.get_json() if data is None: current_app.logger.info('No JSON data supplied!') return 'No JSON data supplied!\n', 400, {'Content-Type': 'text/plain'} if 'ip' in data: ip = data['ip'] elif 'ip6' in data: ip = data['ip6'] else: ip = request.remote_addr try: ip = ipaddress.ip_address(ip) except ipaddress.AddressValueError: return 'IP not allowed!\n', 403, {'Content-Type': 'text/plain'} if ip.version == 4: data['country'] = gi4.country_name_by_addr(str(ip)) elif ip.version == 6: data['country'] = gi6.country_name_by_addr(str(ip)) else: data['country'] = None data['last_updated'] = strict_rfc3339.timestamp_to_rfc3339_utcoffset( datetime.utcnow().timestamp() ) data['status'] = True try: server = Server.from_json(json.dumps(data)) except Exception as e: current_app.logger.warning(' '.join([str(e), str(data)])) return str(e), 409, {'Content-Type': 'text/plain'} if server.type in ('exit', 'relay'): server.update_weights() try: server.save() except Exception as e: current_app.logger.error(str(e)) return str(e), 500, {'Content-Type': 'text/plain'} current_app.logger.info('Return result') return (server.json(), 201, {'Location': '/api/export/json/single?server_name=%s' % server.name}) @api_page.route('/export', defaults={'server_type': 'all', 'export_format': 'json'}) @api_page.route('/export/', defaults={'server_type': 'all'}) @api_page.route(('/export/' '/')) def export(export_format, server_type): current_app.logger.info('Handling export') if server_type == 'single': server_name = request.args.get('server_name', None) if server_name is not None: server = single_server(server_name) if server: if export_format == 'json': current_app.logger.info('Returning server as json!') return (server.json(), 200, {'Content-Type': 'application/json'}) else: current_app.logger.info('Returning server as xml!') return ( render_template( 'api/export/xml/single_server.xml', server=server), 200, {'Content-Type': 'text/xml'}) else: current_app.logger.warning('Server not found!') return ('Server not found!\n', 404, {'Content-Type': 'text/plain'}) else: current_app.logger.warning('No server_name specified!') return ('No server_name specified!\n', 400, {'Content-Type': 'text/plain'}) else: if server_type == 'all': current_app.logger.info('Getting all servers!') servers = [server.json() for server in all_servers()] else: current_app.logger.info('Getting all %s!' % server_type) servers = list(all_servers_by_type(server_type.lower())) if export_format == 'json': current_app.logger.info('Returning as json!') return str(servers) else: current_app.logger.info('Returning as xml!') return (render_template('api/export/xml/network.xml', servers=servers), 200, {'Content-Type': 'text/xml'})