# Ënnstatus # Copyright (C) 2015 Dennis Fink # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import ipaddress import json from datetime import datetime from flask import (Blueprint, request, current_app, jsonify, render_template, abort) from werkzeug.exceptions import BadRequest import strict_rfc3339 import pygeoip from ennstatus import csrf from ennstatus.status.functions import (single_server, all_servers, all_servers_by_type) from .model import Server from .auth import httpauth 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) @csrf.exempt @api_page.route('/update', methods=('POST',)) @httpauth.login_required def update(): current_app.logger.info('Handling update') try: servers = current_app.config['ENNSTATUS_SERVERS'] except KeyError as e: current_app.logger.error(str(e)) return abort(500) username = httpauth.username() try: if request.remote_addr not in servers[username]['IPS']: current_app.logger.warn( 'Unallowed IP {} tried to update data!'.format( request.remote_addr ) ) return 'IP not allowed!\n', 403, {'Content-Type': 'text/plain'} except KeyError as e: current_app.logger.error(str(e)) return abort(500) try: data = request.get_json() except BadRequest: current_app.logger.info('No JSON data supplied!') return 'No JSON data supplied!\n', 400, {'Content-Type': 'text/plain'} try: if username != data['name'].lower(): current_app.logger.warn( 'Unallowed user {} tried to update {}!'.format( username, data['name'] ) ) return ('You are not allowed to update this server\n', 403, {'Content-Type': 'text/plain'}) except KeyError: return abort(409) if 'ip' in data: ip = data['ip'] elif 'ip6' in data: ip = data['ip6'] else: ip = request.remote_addr try: temp_ip = ipaddress.ip_address(ip) except ipaddress.AddressValueError: return 'IP not allowed!\n', 403, {'Content-Type': 'text/plain'} else: if temp_ip.version == 4: data['ip'] = ip elif temp_ip.verison == 6: data['ip6'] = ip try: country = gi4.country_name_by_addr(ip) except pygeoip.GeoIPError: country = gi6.country_name_by_addr(ip) data['country'] = country data['last_updated'] = strict_rfc3339.timestamp_to_rfc3339_utcoffset( datetime.utcnow().timestamp() ) try: server = Server.from_dict(data) except Exception as e: current_app.logger.warning(' '.join([str(e), str(data)])) return str(e), 409, {'Content-Type': 'text/plain'} try: server.update_weights() except NotImplementedError: pass try: server.update_flags() except NotImplementedError: pass 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={}'.format( server.name ) } ) @api_page.route('/export', defaults={'server_type': 'all'}) @api_page.route(('/export/')) def export(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: return server.json(), 200, {'Content-Type': 'application/json'} 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 = [ json.loads( server.json() ) for server in all_servers() ] else: current_app.logger.info('Getting all {}!'.format(server_type)) servers = [ json.loads( server.json() ) for server in all_servers_by_type(server_type.lower()) ] return json.dumps(servers), 200, {'Content-Type': 'application/json'} @api_page.route('/fingerprints', defaults={'server_type': 'all'}) @api_page.route('/fingerprints/') def fingerprint(server_type): if server_type == 'all': servers = [server.fingerprint for server in all_servers() if server.type != 'bridge'] else: servers = [server.fingerprint for server in all_servers_by_type(server_type.lower())] return '\n'.join(servers), 200, {'Content-Type': 'text/plain'}