add ability to delete peerings

+ format all files
This commit is contained in:
lare 2022-12-07 17:00:52 +01:00
parent ff4865f4b6
commit 85f8c936be
10 changed files with 455 additions and 236 deletions

View file

@ -1,15 +1,20 @@
#! /usr/bin/env python3
import base64, os, json, time, logging
import base64
import os
import json
import time
import logging
import OpenSSL
from OpenSSL.crypto import load_publickey, FILETYPE_PEM, verify, X509
PUBKEY_FILE = os.path.dirname(__file__)+"/kioubit-auth-pubkey.pem"
class AuthVerifyer ():
def __init__(self,domain, pubkey=PUBKEY_FILE):
def __init__(self, domain, pubkey=PUBKEY_FILE):
self.domain = domain
with open(pubkey) as pk:
pk_content = ""
@ -24,8 +29,8 @@ class AuthVerifyer ():
def verify(self, params, signature):
# logging.debug(type(sig))
#OpenSSL_verify(self.pubkey, sig
#, base64.b64decode(params), "sha512")
# OpenSSL_verify(self.pubkey, sig
# , base64.b64decode(params), "sha512")
sig = base64.b64decode(signature)
logging.info(f"sig: {sig}")
logging.info(f"params: {params}")
@ -36,7 +41,7 @@ class AuthVerifyer ():
try:
user_data = json.loads(base64.b64decode(params))
if (time.time() - user_data["time"] )> 60:
if (time.time() - user_data["time"]) > 60:
return False, "Signature to old"
except json.decoder.JSONDecodeError:
# we shouldn't get here unless kioubit's service is misbehaving
@ -46,11 +51,12 @@ class AuthVerifyer ():
logging.debug(user_data)
return True, user_data
if __name__ == "__main__":
example_com_verifier = AuthVerifyer("example.com")
logging.info (example_com_verifier.verify(
logging.info(example_com_verifier.verify(
params=b"eyJhc24iOiI0MjQyNDIzMDM1IiwidGltZSI6MTY2ODI2NjkyNiwiYWxsb3dlZDQiOiIxNzIuMjIuMTI1LjEyOFwvMjYsMTcyLjIwLjAuODFcLzMyIiwiYWxsb3dlZDYiOiJmZDYzOjVkNDA6NDdlNTo6XC80OCxmZDQyOmQ0MjpkNDI6ODE6OlwvNjQiLCJtbnQiOiJMQVJFLU1OVCIsImF1dGh0eXBlIjoibG9naW5jb2RlIiwiZG9tYWluIjoic3ZjLmJ1cmJsZS5kbjQyIn0=",
signature=b"MIGIAkIBAmwz3sQ1vOkH8+8e0NJ8GsUqKSaazIWmYDp60sshlTo7gCAopZOZ6/+tD6s+oEGM1i5mKGbHgK9ROATQLHxUZecCQgCa2N828uNn76z1Yg63/c7veMVIiK4l1X9TCUepJnJ3mCto+7ogCP+2vQm6GHipSNRF4wnt6tZbir0HZvrqEnRAmA=="
) )
))
#params = "eyJhc24iOiI0MjQyNDIzMDM1IiwidGltZSI6MTY2ODI1NjI5NSwiYWxsb3dlZDQiOiIxNzIuMjIuMTI1LjEyOFwvMjYsMTcyLjIwLjAuODFcLzMyIiwiYWxsb3dlZDYiOiJmZDYzOjVkNDA6NDdlNTo6XC80OCxmZDQyOmQ0MjpkNDI6ODE6OlwvNjQiLCJtbnQiOiJMQVJFLU1OVCIsImF1dGh0eXBlIjoibG9naW5jb2RlIiwiZG9tYWluIjoic3ZjLmJ1cmJsZS5kbjQyIn0=",
#signature = 'MIGHAkFy1m+9ahjIc5cJk/p+RiXJbhbWT5rPSJNg9Q3c8UTAM4F7lz2OqdWHw6GZN5NQgvqm6OB3Y751djYwCd54y2Kn4wJCAcBaOrtSclxkGIleVx183PhTnSr97r2F089PsDzNXIBvH5pYUwvJX7hG0op0f5tPm7fl12HOOrr8Q6kWW+XTrgGX'

View file

@ -2,21 +2,30 @@
from flask import Flask, Response, redirect, render_template, request, session, abort
import werkzeug.exceptions as werkzeug_exceptions
import json, os, base64, logging, random
import json
import os
import base64
import logging
import random
from functools import wraps
from ipaddress import ip_address, ip_network, IPv4Network, IPv6Network
import kioubit_verify
app = Flask(__name__)
class Config (dict):
def __init__(self, configfile:str = None):
def __init__(self, configfile: str = None):
if configfile:
self.configfile = configfile
else:
if os.path.exists("./config.json"): self.configfile = "./config.json"
elif os.path.exists("/etc/dn42-autopeer/config.json"): self.configfile = "/etc/dn42-autopeer/config,json"
else: raise FileNotFoundError("no config file found in ./config.json or /etc/dn42-autopeer/config.json")
if os.path.exists("./config.json"):
self.configfile = "./config.json"
elif os.path.exists("/etc/dn42-autopeer/config.json"):
self.configfile = "/etc/dn42-autopeer/config,json"
else:
raise FileNotFoundError(
"no config file found in ./config.json or /etc/dn42-autopeer/config.json")
self._load_config()
self.keys = self._config.keys
#self.__getitem__ = self._config.__getitem__
@ -27,7 +36,8 @@ class Config (dict):
def __delitem__(self, v):
raise NotImplementedError()
super().__delitem__(self,v)
super().__delitem__(self, v)
def __getitem__(self, k):
return self._config[k]
@ -50,6 +60,7 @@ class Config (dict):
self._config["peering-data"] = "./peerings"
logging.info(self._config)
class PeeringManager:
def __init__(self, peerings_file):
@ -60,14 +71,14 @@ class PeeringManager:
def _load_peerings(self):
if not os.path.exists(self._peering_file):
with open(self._peering_file, "x") as p:
json.dump({"mnter":{},"asn":{}}, p)
json.dump({"mnter": {}, "asn": {}}, p)
try:
with open(self._peering_file,"r") as p:
with open(self._peering_file, "r") as p:
self.peerings = json.load(p)
except json.decoder.JSONDecodeError:
with open(self._peering_file, "w") as p:
json.dump({"mnter":{},"asn":{}}, p)
with open(self._peering_file,"r") as p:
json.dump({"mnter": {}, "asn": {}}, p)
with open(self._peering_file, "r") as p:
self.peerings = json.load(p)
# self.peerings = {}
@ -87,6 +98,30 @@ class PeeringManager:
with open(self._peering_file, "w") as p:
json.dump(self.peerings, p, indent=4)
def _update_nodes(mode, peering, new_peering=None):
"""mode: "add","update","delete
peering: peering to send to node (included in peering)
new_peering: if mode=="update" the new peering to update to
"""
pass
def exists(self, asn, node, mnt=None, wg_key=None, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
"""checks if a peerings with specific data already exists"""
# check if mnt is specified, already exists in the database and if that mnt has the specified ASn -> if not: return False
if mnt and not (mnt in self.peerings["mnter"] and asn in self.peerings["mnter"][mnt]):
return False
selected_peerings = self.peerings["asn"][asn]
# check if the ASn even has peerings
if len(selected_peerings) == 0:
return False
for p in selected_peerings:
if p["node"] == node:
if (not wg_key or p["wg_key"] == wg_key) and (not endpoint or p["endpoint"] == endpoint) \
and (not ipv6ll or p["ipv6ll"] == ipv6ll) and (not ipv4 or p["ipv4"] == ipv4) and (not ipv6 or p["ipv6"] == ipv6)\
and (not bgp_mp or p["bgp_mp"] == bgp_mp) and (not bgp_enh or p["bgp_enh"] == bgp_enh):
return True
return False
def get_peerings_by_mnt(self, mnt):
# print(self.peerings)
try:
@ -101,7 +136,7 @@ class PeeringManager:
except KeyError:
return {}
def add_peering(self, mnt, asn, node, wg_key, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
def add_peering(self, asn, node, mnt, wg_key, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
# check if this MNT already has a/this asn
try:
if not asn in self.peerings["mnter"][mnt]:
@ -118,13 +153,16 @@ class PeeringManager:
# deny more than one peering per ASN to one node
for peering in self.peerings["asn"][asn]:
if peering["node"] == node: return False
if peering["node"] == node:
return False
self.peerings["asn"][asn].append({"MNT":mnt,"ASN":asn, "node": node, "wg_key":wg_key, "endpoint": endpoint,"ipv6ll":ipv6ll,"ipv4":ipv4,"ipv6":ipv6, "bgp_mp":bgp_mp, "bgp_enh":bgp_enh})
self.peerings["asn"][asn].append({"MNT": mnt, "ASN": asn, "node": node, "wg_key": wg_key, "endpoint": endpoint,
"ipv6ll": ipv6ll, "ipv4": ipv4, "ipv6": ipv6, "bgp_mp": bgp_mp, "bgp_enh": bgp_enh})
self._save_peerings()
return True
def update_peering(self, mnt, asn, node, wg_key, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
def update_peering(self, asn, node, mnt, wg_key, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
# check if this MNT already has a/this asn
try:
if not asn in self.peerings["mnter"][mnt]:
@ -142,22 +180,38 @@ class PeeringManager:
success = False
for pNr in range(len(self.peerings["asn"][asn])):
if self.peerings["asn"][asn][pNr]["node"] == node:
self.peerings["asn"][asn][pNr] = {"MNT":mnt,"ASN":asn, "node": node, "wg_key":wg_key, "endpoint": endpoint,"ipv6ll":ipv6ll,"ipv4":ipv4,"ipv6":ipv6, "bgp_mp":bgp_mp, "bgp_enh":bgp_enh}
self.peerings["asn"][asn][pNr] = {"MNT": mnt, "ASN": asn, "node": node, "wg_key": wg_key,
"endpoint": endpoint, "ipv6ll": ipv6ll, "ipv4": ipv4, "ipv6": ipv6, "bgp_mp": bgp_mp, "bgp_enh": bgp_enh}
success = True
if not success: return False
if not success:
return False
self._save_peerings()
return True
def delete_peering(self, asn, node, mnt, wg_key=None):
if not self.exists(asn, node, mnt=mnt, wg_key=wg_key):
return False
for p in self.peerings["asn"][asn]:
if p["node"] == node:
if wg_key and p["wg_key"] != wg_key:
continue
self.peerings["asn"][asn].remove(p)
self._save_peerings()
return True
# if nothing got found (should have been catched by self.exists)
return False
config = Config()
peerings = PeeringManager(config["peerings"])
kverifyer = kioubit_verify.AuthVerifyer(config["domain"])
def check_peering_data(form):
new_peering = {}
# errors = 0
## check if all required (and enabled) options are specified
# check if all required (and enabled) options are specified
try:
new_peering["peer-asn"] = session["user-data"]["asn"]
new_peering["peer-wgkey"] = form["peer-wgkey"]
@ -197,7 +251,7 @@ def check_peering_data(form):
print(new_peering)
## check wireguard key
# check wireguard key
wg_key_invalid = False
if len(new_peering["peer-wgkey"]) != 44:
wg_key_invalid = True
@ -208,29 +262,32 @@ def check_peering_data(form):
if wg_key_invalid:
return False, "invalid wireguard Key"
## check endpoint
# check endpoint
if new_peering["peer-endpoint"]:
if not new_peering["peer-endpoint"].split(":")[-1].isnumeric():
return False, "no port number in endpoint"
elif len(new_peering["peer-endpoint"].split(":")) < 2 and not "." in new_peering["peer-endpoint"]:
return False, "endpoint doesn't look like a ip address or fqdn"
## check if at least one ip is specified/enabled
# check if at least one ip is specified/enabled
try:
if not (new_peering["peer-v6ll"] or new_peering["peer-v4"] or new_peering["peer-v6"]):
return False, "at least one of the ip addresses must be enabled and specified"
except KeyError:
return False, "one of the values isn't valid"
## check if supplied ip addresses are valid
# check if supplied ip addresses are valid
try:
if new_peering["peer-v6ll"]:
ipv6ll = ip_address(new_peering["peer-v6ll"])
if not ipv6ll.version == 6: raise ValueError()
if not ipv6ll.is_link_local: raise ValueError()
if not ipv6ll.version == 6:
raise ValueError()
if not ipv6ll.is_link_local:
raise ValueError()
if new_peering["peer-v4"]:
ipv4 = ip_address(new_peering["peer-v4"])
if not ipv4.version == 4: raise ValueError()
if not ipv4.version == 4:
raise ValueError()
if ipv4.is_link_local:
pass
elif ipv4.is_private:
@ -243,12 +300,16 @@ def check_peering_data(form):
is_in_allowed = True
if not is_in_allowed:
return False, "supplied ipv4 addr not in allowed ip range"
else: raise ValueError()
else:
raise ValueError()
if new_peering["peer-v6"]:
ipv6 = ip_address(new_peering["peer-v6"])
if not ipv6.version == 6: raise ValueError()
if not ipv6.is_private: raise ValueError()
if ipv6.is_link_local: raise ValueError()
if not ipv6.version == 6:
raise ValueError()
if not ipv6.is_private:
raise ValueError()
if ipv6.is_link_local:
raise ValueError()
is_in_allowed = False
if session["user-data"]["allowed6"]:
for allowed6 in session["user-data"]["allowed6"].split(","):
@ -269,6 +330,8 @@ def check_peering_data(form):
except ValueError:
...
return True, new_peering
def auth_required():
def wrapper(f):
@wraps(f)
@ -287,13 +350,13 @@ def kioubit_auth():
params = request.args["params"]
signature = request.args["signature"]
except KeyError:
return render_template("login.html", session=session,config=config,return_addr=session["return_url"], msg='"params" or "signature" missing')
return render_template("login.html", session=session, config=config, return_addr=session["return_url"], msg='"params" or "signature" missing')
success, msg = kverifyer.verify(params, signature)
try: logging.debug(base64.b64decode(params))
except: logging.debug("invalid Base64 data provided")
try:
logging.debug(base64.b64decode(params))
except:
logging.debug("invalid Base64 data provided")
if success:
session["user-data"] = msg
@ -304,16 +367,18 @@ def kioubit_auth():
return redirect(f"{config['base-dir']}peerings")
else:
try:
return render_template("login.html", session=session,config=config,return_addr=session["return_url"], msg=msg)
return render_template("login.html", session=session, config=config, return_addr=session["return_url"], msg=msg)
except KeyError:
return render_template("login.html", session=session,config=config,return_addr=f"{config['base-dir']}peerings", msg=msg)
return render_template("login.html", session=session, config=config, return_addr=f"{config['base-dir']}peerings", msg=msg)
@app.route("/logout")
def logout():
session.clear()
return redirect("/")
@app.route("/login",methods=["GET","POST"])
@app.route("/login", methods=["GET", "POST"])
def login():
print(session)
if request.method == "GET":
@ -325,47 +390,66 @@ def login():
print(request.form)
if request.form["theanswer"] != "42":
msg = "what is the answer for everything?"
return render_template("login.html", session=session,config=config,return_addr=session["return_url"], msg=msg)
return render_template("login.html", session=session, config=config, return_addr=session["return_url"], msg=msg)
mnt = request.form["mnt"]
if not mnt.upper().endswith("-MNT"): raise ValueError
if not mnt.upper().endswith("-MNT"):
raise ValueError
asn = request.form["asn"]
asn = asn[2:] if asn[:2].lower() == "as" else asn
int(asn)
if "allowed4" in request.form:
allowed4 = request.form["allowed4"]
v4_ranges = allowed4.split(",") if "," in allowed4 else [allowed4]
v4_ranges = allowed4.split(
",") if "," in allowed4 else [allowed4]
for v4_range in v4_ranges:
IPv4Network(v4_range)
else:
allowed4 = None
if "allowed6" in request.form:
allowed6 = request.form["allowed6"]
v6_ranges = allowed6.split(",") if "," in allowed6 else [allowed6]
v6_ranges = allowed6.split(
",") if "," in allowed6 else [allowed6]
for v6_range in v6_ranges:
IPv6Network(v6_range)
else:
allowed6 = None
session["user-data"] = {'asn':asn,'allowed4': allowed4, 'allowed6': allowed6,'mnt':mnt, 'authtype': "debug"}
session["user-data"] = {'asn': asn, 'allowed4': allowed4,
'allowed6': allowed6, 'mnt': mnt, 'authtype': "debug"}
session["login"] = mnt
return redirect(session["return_url"])
except ValueError:
msg = "at least one of the values provided is wrong/invalid"
return render_template("login.html", session=session,config=config,return_addr=session["return_url"], msg=msg)
return render_template("login.html", session=session, config=config, return_addr=session["return_url"], msg=msg)
except KeyError:
msg = "not all required field were specified"
return render_template("login.html", session=session,config=config,return_addr=session["return_url"], msg=msg)
return render_template("login.html", session=session, config=config, return_addr=session["return_url"], msg=msg)
elif request.method == "POST" and not config["debug-mode"]:
abort(405)
return redirect(request.args["return"])
@app.route("/peerings/delete", methods=["GET","DELETE"])
@app.route("/peerings/delete", methods=["GET", "POST", "DELETE"])
@auth_required()
def peerings_delete():
if request.method == "GET":
return render_template("peerings-delete.html", session=session, config=config, request_args=request.args)
return f"{request.method} /peerings/delete?{str(request.args)}{str(request.form)}"
elif request.method in ["POST", "DELETE"]:
if not request.form["confirm"] == "on":
return render_template("peerings-delete.html", session=session, config=config, request_args=request.args, msg="you have to confirm the deletion first")
if not peerings.exists(request.args["asn"], request.args["node"], mnt=session["login"]):
return render_template("peerings-delete.html", session=session, config=config, request_args=request.args, msg="the peering you requested to delete doesn't exist (anymore) or you are not authorized to delete it")
print(str(request))
if not peerings.delete_peering(request.args["asn"], request.args["node"], mnt=session["login"]):
return render_template("peerings-delete.html", session=session, config=config, request_args=request.args, msg="deletion of the peering requested failed, maybe you are not authorized or that peering doesn't exist")
session["msg"] = {"msg": "peer-del",
"node": request.args["node"], "asn": request.args["asn"]}
return redirect("../peerings")
return f"{request.method} /peerings/delete {request.args} {request.form}"
@app.route("/peerings/edit", methods=["GET","POST"])
@app.route("/peerings/edit", methods=["GET", "POST"])
@auth_required()
def peerings_edit():
print(session)
@ -386,19 +470,21 @@ def peerings_edit():
print(request.args)
print(request.form)
if not "node" in request.args or not request.args["node"]:
return render_template("peerings-edit.html", session=session,config=config, peerings=peerings, msg="no node specified, please click one of the buttons above")
return render_template("peerings-edit.html", session=session, config=config, peerings=peerings, msg="no node specified, please click one of the buttons above")
peering_valid, peering_or_msg = check_peering_data(request.form)
print(peering_valid)
print(peering_or_msg)
if not peering_valid:
return render_template("peerings-edit.html", session=session,config=config, peerings=peerings, msg=peering_or_msg), 400
return render_template("peerings-edit.html", session=session, config=config, peerings=peerings, msg=peering_or_msg), 400
if not peerings.update_peering(session["user-data"]["mnt"], session["user-data"]["asn"], request.args["node"], peering_or_msg["peer-wgkey"], peering_or_msg["peer-endpoint"], peering_or_msg["peer-v6ll"], peering_or_msg["peer-v4"], peering_or_msg["peer-v6"], peering_or_msg["bgp-mp"], peering_or_msg["bgp-enh"]):
return render_template("peerings-edit.html", session=session,config=config, peerings=peerings, msg="such a peering doesn't exist(yet)"), 400
return render_template("peerings-edit.html", session=session, config=config, peerings=peerings, msg="such a peering doesn't exist(yet)"), 400
return redirect(f"{config['base-dir']}peerings")
return f"{request.method} /peerings/edit?{str(request.args)}{str(request.form)}"
@app.route("/peerings/new", methods=["GET","POST"])
@app.route("/peerings/new", methods=["GET", "POST"])
@auth_required()
def peerings_new():
print(session)
@ -406,23 +492,24 @@ def peerings_new():
if "node" in request.args and request.args["node"] in config["nodes"]:
return render_template("peerings-new.html", config=config, selected_node=request.args["node"], peerings=peerings)
else:
return render_template("peerings-new.html", session=session,config=config, peerings=peerings)
return render_template("peerings-new.html", session=session, config=config, peerings=peerings)
elif request.method == "POST":
print(request.args)
print(request.form)
if not "node" in request.args or not request.args["node"]:
return render_template("peerings-new.html", session=session,config=config, peerings=peerings, msg="no node specified, please click one of the buttons above")
return render_template("peerings-new.html", session=session, config=config, peerings=peerings, msg="no node specified, please click one of the buttons above")
peering_valid, peering_or_msg = check_peering_data(request.form)
if not peering_valid:
return render_template("peerings-new.html", session=session,config=config, peerings=peerings, msg=peering_or_msg), 400
return render_template("peerings-new.html", session=session, config=config, peerings=peerings, msg=peering_or_msg), 400
if not peerings.add_peering(session["user-data"]["mnt"], session["user-data"]["asn"], request.args["node"], peering_or_msg["peer-wgkey"], peering_or_msg["peer-endpoint"], peering_or_msg["peer-v6ll"], peering_or_msg["peer-v4"], peering_or_msg["peer-v6"], peering_or_msg["bgp-mp"], peering_or_msg["bgp-enh"]):
return render_template("peerings-new.html", session=session,config=config, peerings=peerings, msg="this ASN already has a peering with the requested node"), 400
return render_template("peerings-new.html", session=session, config=config, peerings=peerings, msg="this ASN already has a peering with the requested node"), 400
return redirect(f"{config['base-dir']}peerings")
@app.route("/peerings", methods=["GET","POST","DELETE"])
@app.route("/peerings", methods=["GET", "POST", "DELETE"])
@auth_required()
def peerings_view():
print(session)
@ -430,7 +517,7 @@ def peerings_view():
if "node" in request.args and request.args["node"] in config["nodes"]:
return render_template("peerings.html", config=config, selected_node=request.args["node"], peerings=peerings)
else:
return render_template("peerings.html", session=session,config=config, peerings=peerings)
return render_template("peerings.html", session=session, config=config, peerings=peerings)
elif request.method == "POST":
return peerings_new()
elif request.method == "DELETE":
@ -438,6 +525,7 @@ def peerings_view():
else:
abort(405)
@app.route("/")
def index():
print(session)
@ -446,19 +534,20 @@ def index():
# print (node)
return render_template("index.html", session=session, config=config._config)
def main():
app.static_folder= config["flask-template-dir"]+"/static/"
app.template_folder=config["flask-template-dir"]
app.static_folder = config["flask-template-dir"]+"/static/"
app.template_folder = config["flask-template-dir"]
app.secret_key = config["flask-secret-key"]
if "production" in config and config["production"] == False:
logging.getLogger(__name__).setLevel(0)
app.run(host=config["listen"], port=config["port"], debug=config["debug-mode"], threaded=True)
app.run(host=config["listen"], port=config["port"],
debug=config["debug-mode"], threaded=True)
else:
from waitress import serve
logging.getLogger(__name__).setLevel(logging.INFO)
serve(app, host=config["listen"], port=config["port"])
if __name__ == "__main__":
main()

View file

@ -1,22 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{config["MNT"]}} Autopeering</title>
<link rel="stylesheet" href="{{config['base-dir']}}static/style.css">
</head>
<body>
<header class="flex flex-row"><div></div><a href="{{config['base-dir']}}">{{config["MNT"]}} Autopeering</a>{% if "login" in session %} <div><a href="{{config['base-dir']}}peerings">manage</a> <a href="{{config['base-dir']}}logout">logout</a></div>{% else %} <a href="{{config['base-dir']}}login?return=/peerings">login</a>{%endif%}</header>
<div class="content flex">
{% block content %}
{% endblock %}
<link rel="stylesheet" href="{{config['base-dir']}}static/style.css" />
</head>
<body>
<header class="flex flex-row">
<div></div>
<a href="{{config['base-dir']}}">{{config["MNT"]}} Autopeering</a>{% if
"login" in session %}
<div>
<a href="{{config['base-dir']}}peerings">manage</a>
<a href="{{config['base-dir']}}logout">logout</a>
</div>
{% else %}
<a href="{{config['base-dir']}}login?return=/peerings">login</a>{%endif%}
</header>
<div class="content flex">{% block content %} {% endblock %}</div>
<footer class="flex">
<div></div>
<div></div>
<div> &#127279; LARE-MNT</div>
<div>&#127279; LARE-MNT</div>
</footer>
</body>
</body>
</html>

View file

@ -1,8 +1,5 @@
{% extends 'base.html' %}
{% block content %}
<div>
</div>
{% extends 'base.html' %} {% block content %}
<div></div>
<div>
<table>
<thead>

View file

@ -1,31 +1,64 @@
{% extends 'base.html' %}
{% block content %}
{% if msg %}
<div style="background-color: red;">
{{msg}}
</div>
{% extends 'base.html' %} {% block content %} {% if msg %}
<div style="background-color: red">{{msg}}</div>
{% endif %}
<form action="https://dn42.g-load.eu/auth/">
<link rel="stylesheet" href="https://dn42.g-load.eu/auth/assets/button-font/auth.css">
<input type="hidden" id="return" name="return" value='{{"http://"+config["domain"]+"/api/auth/kverify"}}'>
<button type="submit" class="kioubit-btn kioubit-btn-primary kioubit-btn-dark kioubit-btn-main">
<link
rel="stylesheet"
href="https://dn42.g-load.eu/auth/assets/button-font/auth.css"
/>
<input
type="hidden"
id="return"
name="return"
value='{{"http://"+config["domain"]+"/api/auth/kverify"}}'
/>
<button
type="submit"
class="kioubit-btn kioubit-btn-primary kioubit-btn-dark kioubit-btn-main"
>
<span class="icon-kioubit-auth"></span>Authenticate with Kioubit.dn42
</button>
</form>
{% if config["debug-mode"] %}
<form action="" method="post" class="flex">
<label for="debug">Debug login, if you see this in Production contact {{config["MNT"]}}</label><br>
<input type="text" name="mnt" id="mnt" placeholder="YOUR-MNT" required><br>
<input type="text" name="asn" id="asn" placeholder="AS4242420000" required><br>
<input type="text" name="allowed4" id="allowed4" placeholder="ipv4 subnet (optional)"><br>
<input type="text" name="allowed6" id="allowed6" placeholder="ipv6 subnet (optional)"><br>
<input type="number" name="theanswer" id="theanswer" placeholder="The answer for everything" required><br>
<input type="submit" value="login">
<label for="debug"
>Debug login, if you see this in Production contact {{config["MNT"]}}</label
><br />
<input
type="text"
name="mnt"
id="mnt"
placeholder="YOUR-MNT"
required
/><br />
<input
type="text"
name="asn"
id="asn"
placeholder="AS4242420000"
required
/><br />
<input
type="text"
name="allowed4"
id="allowed4"
placeholder="ipv4 subnet (optional)"
/><br />
<input
type="text"
name="allowed6"
id="allowed6"
placeholder="ipv6 subnet (optional)"
/><br />
<input
type="number"
name="theanswer"
id="theanswer"
placeholder="The answer for everything"
required
/><br />
<input type="submit" value="login" />
</form>
{% endif %}
{% endblock %}
{% endif %} {% endblock %}

View file

@ -0,0 +1,45 @@
{% extends 'base.html' %} {% block content %}
<form class="flex" action="" method="post">
<div id="warning" style="background-color: yellow">
{% if msg %}{{msg}}{% else %}confirm the deletion of this peering{% endif %}
</div>
<table>
<tr>
<td><label for="asn">ASn</label></td>
<td>
<input
type="text"
id="asn"
readonly="readonly"
value="{{request_args['asn']}}"
/>
</td>
</tr>
<tr>
<td><label for="node">node</label></td>
<td>
<input
type="text"
id="node"
readonly="readonly"
value="{{request_args['node']}}"
/>
</td>
</tr>
<tr>
<td><label for="confirm">confirm</label></td>
<td>
<input type="checkbox" name="confirm" id="delete-confirm" required />
</td>
</tr>
</table>
<div>
<a href="../peerings">
<input type="button" class="button-green" value="back"
/></a>
<button type="submit" class="button-red">confirm</button>
</div>
</form>
{% endblock %}

View file

@ -182,7 +182,7 @@
{% endfor %}
</div>
<form action="" method="post" class="flex" onsubmit="return form_validate(this)">
<div id="peer-invalid-note" style="background-color:red;">{% if msg %}{{msg}}{%endif%}</div>
<div id="peer-invalid-note" style="background-color:red;">{% if msg %}{{msg}}{%elif not selected_node%}please select one of the nodes above{%endif%}</div>
<table>
<tr>
<td><label for="peer-asn">Your ASN</label></td>
@ -284,7 +284,7 @@ protocol bgp dn42_{{config["MNT"][:-4].lower()}}_v6 from dnpeers {
};
}
</pre>
</div>
</div>
<script>
document.onload();

View file

@ -1,39 +1,58 @@
{% extends 'base.html' %}
{% block content %}
{% extends 'base.html' %} {% block content %}
<div>
<a href="peerings/new"><button>add new</button></a>
<a href="peerings/new"
><button class="button-green default-border-color">add new</button></a
>
</div>
<div class="flex flex-row">
{% for peering in peerings.get_peerings_by_mnt(session["login"]) %}
{% for peering in peerings.get_peerings_by_mnt(session["login"]) %}
<div class="peering">
<div>
<div>Node: {{peering["node"]}}</div>
</div>
<div>
<table>
<tr><td>ASN:</td><td>{{peering["ASN"]}}</td></tr>
<tr><td>WG-PublicKey:</td><td>{{peering["wg_key"][:8]}}...</td></tr>
<tr>
<td>ASN:</td>
<td>{{peering["ASN"]}}</td>
</tr>
<tr>
<td>WG-PublicKey:</td>
<td>{{peering["wg_key"][:8]}}...</td>
</tr>
</table>
</div>
<div>
<table>
{% if peering["ipv6ll"] %}<tr><td>ipv6 linklocal:</td><td>{{peering["ipv6ll"]}}</td></tr>{% endif %}
{% if peering["ipv4"] %}<tr><td>ipv4:</td><td>{{peering["ipv4"]}}</td></tr>{% endif %}
{% if peering["ipv6"] %}<tr><td>ipv6:</td><td>{{peering["ipv6"]}}</td></tr>{% endif %}
{% if peering["ipv6ll"] %}
<tr>
<td>ipv6 linklocal:</td>
<td>{{peering["ipv6ll"]}}</td>
</tr>
{% endif %} {% if peering["ipv4"] %}
<tr>
<td>ipv4:</td>
<td>{{peering["ipv4"]}}</td>
</tr>
{% endif %} {% if peering["ipv6"] %}
<tr>
<td>ipv6:</td>
<td>{{peering["ipv6"]}}</td>
</tr>
{% endif %}
</table>
</div>
<!-- <div>{{peering}}</div> -->
<div>
<a href="peerings/edit?node={{peering['node']}}&asn={{peering['ASN']}}">
<button class="peering-edit">edit</button>
<button class="button-blue">edit</button>
</a>
<a href="peerings/delete?node={{peering['node']}}&asn={{peering['ASN']}}">
<button class="peering-delete">delete</button>
<button class="button-red">delete</button>
</a>
</div>
</div>
{% endfor %}
{% endfor %}
</div>
{% endblock %}

View file

@ -17,6 +17,7 @@ header {
background-color: var(--other-background);
height: 50px;
}
a {
color: var(--text-color);
}
@ -27,6 +28,7 @@ a {
margin: auto;
padding-bottom: 50px;
}
.content>* {
padding: 5%;
}
@ -35,6 +37,7 @@ a {
display: flex;
flex-direction: column;
}
.flex-row {
flex-direction: row;
}
@ -54,6 +57,7 @@ footer {
height: 40px;
background: var(--other-background);
}
footer.flex {
flex-direction: row;
}
@ -63,14 +67,14 @@ footer.flex {
padding: 1%;
}
.example-config > pre{
.example-config>pre {
border-color: var(--other-background);
border-radius: 10px;
padding: 10px;
border-style: groove;
}
form > div > * {
form>div>* {
margin: 10px;
}
@ -85,40 +89,59 @@ form > div > * {
width: 100%;
margin: 10px;
}
.peering > div {
.peering>div {
display: flex;
flex-direction: column;
}
.peering > div > * {
.peering>div>* {
padding: 10px;
}
button {
button,
input[type=button] {
background-color: #00000020;
border-color: var(--text-color);
border-width: 5px;
padding: 10px;
}
button.button-selected{
button.button-selected,
input[type=button].button-selected {
background-color: var(--other-background);
color: var(--text-color-dark);
}
.peering>* {
width:auto;
width: auto;
align-items: center;
}
.peering-edit {
.button-blue {
border-color: lightblue;
}
.peering-edit:hover {
.button-blue:hover {
background-color: #87cefaaa;
}
.peering-delete {
.button-red {
border-color: darkred;
}
.peering-delete:hover {
.button-red:hover {
background-color: #ff0000aa;
}
.button-green {
border-color: lightgreen;
}
.button-green:hover {
background-color: greenyellow;
}
.default-border-color {
border-color: inherit;
}