From 64a5bc57d73fbe6128a6f47535ce64290b43b6df Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 26 May 2019 00:21:37 +0200 Subject: [PATCH] add first levels, begin class based view --- game-etcd.py | 123 ++++++++++++++++++++++++++++++++++++++++++------- test-etcd.py | 9 +++- ungleichapi.py | 9 +++- 3 files changed, 122 insertions(+), 19 deletions(-) diff --git a/game-etcd.py b/game-etcd.py index 87ed09a..aae9b13 100644 --- a/game-etcd.py +++ b/game-etcd.py @@ -6,14 +6,25 @@ import ipaddress import random import sys import etcd +import ungleichapi +import json +import datetime -from flask import Flask +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 @@ -29,35 +40,115 @@ class Ping6(Level): ping6 -c3 """ -class Game(Resource): - def get(self): - return {'hello': 'list of levels'} +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") - -api.add_resource(Game, '/game') - @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)) - name = 'nico{}'.format(net_offset) + username = 'nico{}'.format(net_offset) - print(net) + print("{} has {}".format(username, net)) - print(n) + g = Game(__name__) + g.app.run(port='5002') - addr_offset = random.randrange(0, 2**64) - addr = net[0] + addr_offset - a = Address('nico{}'.format(net_offset), str(addr)) - print(a) - - sys.exit(0) app.run(port='5002') diff --git a/test-etcd.py b/test-etcd.py index 8c6515a..2e449ed 100644 --- a/test-etcd.py +++ b/test-etcd.py @@ -10,16 +10,21 @@ some_vm['network']['ipv6'].append("2a0a:e5c0:4::42/64") some_vm['network']['ipv6'].append("2a0a:e5c0:1::42/64") -#for node in range(20000): +#for node in range(200): # client.delete('/nodes/n{}'.format(node)) -for node in range(200): +for node in range(10): ip = some_vm['network']['ipv6'].append("2a0a:e5c0:3::{}/64".format(node)) j = json.dumps(some_vm) client.write('/nodes/n{}'.format(node), j) +for node in range(10): + x = client.write("/dir/name", "value", append=True) + print("generated key: " + x.key) + print("stored value: " + x.value) + result = client.read('/nodes', recursive=True, sorted=True) print(result) for child in result.children: diff --git a/ungleichapi.py b/ungleichapi.py index 7bcec2a..b68a313 100644 --- a/ungleichapi.py +++ b/ungleichapi.py @@ -5,4 +5,11 @@ ungleich_api = {} class ungleichAPI(object): def __init__(self, version='v1'): - pass + self.version = version + + def create_vm(self, id): + vm = {} + vm['ipv6'] = [] + + def create_user(self): + user = {}