#!/usr/bin/env python3 USERLENGTH = 50 import ipaddress import random import sys import etcd import ungleichapi import json import datetime from flask import Flask, abort, request, Response from flask_restful import Resource, Api from flask_restful import reqparse app = Flask(__name__) api = Api(app) def get_random_ip(network): net = ipaddress.IPv6Network(network) addr_offset = random.randrange(2**64) addr = net[0] + addr_offset return addr class Level(Resource): points = 0 def test(self): pass class Ping6(Level): points = 10 def test(self): """ ping6 -c3 """ class Game(object): def __init__(self, name): self.client = etcd.Client(port=2379) self.app = Flask(name) self.app.add_url_rule('/', 'highscore', self.highscore) def highscore(self): return Response("A lof of points") @app.route("/") def high_score(): return "High score!" @app.route("/register", methods=['POST']) def register(): parser = reqparse.RequestParser() parser.add_argument('network', required=True) parser.add_argument('user', required=True) args = parser.parse_args() # Needs to be fixed with ungleich-otp username=args['user'] try: net = ipaddress.IPv6Network(args['network']) network = args['network'] except Exception as e: return Response(status=400, response="Cannot register network {}: {}".format(network, e)) if not net.prefixlen == 64: return Response(status=400, response="{} mask is not /64 - please use a /64 network".format(net)) client = etcd.Client(port=2379) client.write("/ungleichgame/v1/{}/network".format(username), network) data = client.read("/ungleichgame/v1/{}/network".format(username)) return json.dumps("All good, go to /level/1 to start with level 1! - {}".format(data.value)) @app.route("/level/1", methods=['GET', 'POST']) # post for username def get_ip_address(): parser = reqparse.RequestParser() parser.add_argument('user', required=True) args = parser.parse_args() # Needs to be fixed with ungleich-otp username=args['user'] if request.method == 'GET': return Response(""" This is an easy level - just register any /64 network that you fully control. After submission the game server will generate a random IPv6 address in this network. """) client = etcd.Client(port=2379) try: data = client.read("/ungleichgame/v1/{}/network".format(username)) # FIXME: differentiate keynotfound and other errors except Exception as e: return Response(status=400, response="Cannot read your network, try registering first (error: {})".format(e)) return Response("data={}".format(data.value)) address = get_random_ip(data.value) # FIXME: catch errors client.write("/ungleichgame/v1/{}/address".format(username), address) return Response("Your IPv6 address for this game is {}. Make it pingable and post to /level/1/result".format(address)) @app.route("/level/2", methods=['GET', 'POST']) # post for username def pingme(): parser = reqparse.RequestParser() parser.add_argument('user', required=True) args = parser.parse_args() # Needs to be fixed with ungleich-otp username=args['user'] if request.method == 'GET': return Response(""" Proof that you can really control the network that you submitted: - Setup the IPv6 address to be ping6 able globally - POST to this address when it is configured """) if request.method == 'POST': try: data = client.read("/ungleichgame/v1/{}/address".format(username), address) except Exception as e: return Response(status=400, response=""" You need to register a network before trying to be reachable. Please go back to Level 1 for registering your network. """) return Response("something good") if __name__ == '__main__': net_base = "2a0a:e5c1:{:x}::/64" net_offset = random.randrange(0xffff) net = ipaddress.IPv6Network(net_base.format(net_offset)) username = 'nico{}'.format(net_offset) print("{} has {}".format(username, net)) g = Game(__name__) g.app.run(port='5002') app.run(port='5002')