add ability to delete peerings
+ format all files + fix "selected_peering" not being defined in /peerings/edit
This commit is contained in:
parent
ff4865f4b6
commit
537400f77a
10 changed files with 464 additions and 238 deletions
|
@ -1,29 +1,29 @@
|
|||
{
|
||||
"nodes": {
|
||||
"<nodename>": {
|
||||
"endpoint": "<clearnet-fqdn/ip-address>", //optional, recommended, default: None/null
|
||||
"api-con": "http://<node-(internal)-ip/hostname>:<port>/", // required
|
||||
"#comment": "/* from here: data to be displayed on the webinterface */",
|
||||
"country": "...", // Countrycode: 2 capital letters
|
||||
"city": "...",
|
||||
"wg-key": "...=", // pubkey of node; required
|
||||
"internal-v4": "172.2x.xxx.xxx", //at least one ipv{4,6} addr required
|
||||
"internal-v6": "fdxx:...",
|
||||
"internal-v4ll": "169.254.xxx.xxx",
|
||||
"internal-v6ll": "fe80::...",
|
||||
"note": "...", //optional, special precausions, like only supporting a specific amount of peers/ipv{4,6} in clearnet, etc
|
||||
"capacity": 100 //optional, default: -1 (infinite); estimated capacity of that node (i.e. OPENVZ(7) only has userspace WG (which consumes memory for every interface created))
|
||||
}
|
||||
},
|
||||
"MNT": "YOUR-MNT", // your MNT tag
|
||||
"ASN": "424242000", //Your ASN (used to generate default peer ListenPorts)
|
||||
"listen": "0.0.0.0",
|
||||
"port": 8042,
|
||||
"domain": "example.org", // domain to use for kioubit verification service
|
||||
"base-dir": "/", //optional:directury for which it is reachable (if behind some sort of reverse proxy) default "/"
|
||||
"peerings": "/path/to/peering-config.json", // optional; default "$PWD/peerings", directory to save existing peerings to
|
||||
"production": true, //optional, default true;
|
||||
"debug-mode": false, // optional; whethet to enable debugging; default false
|
||||
"flask-secret-key": "<secret-please-replace>", // secret key for session cookies
|
||||
"flask-template-dir": "../frontend/" // optional; default "../frontend"
|
||||
}
|
||||
"nodes": {
|
||||
"<nodename>": {
|
||||
"endpoint": "<clearnet-fqdn/ip-address>", //optional, recommended, default: None/null
|
||||
"api-con": "http://<node-(internal)-ip/hostname>:<port>/", // required
|
||||
"#comment": "/* from here: data to be displayed on the webinterface */",
|
||||
"country": "...", // Countrycode: 2 capital letters
|
||||
"city": "...",
|
||||
"wg-key": "...=", // pubkey of node; required
|
||||
"internal-v4": "172.2x.xxx.xxx", //at least one ipv{4,6} addr required
|
||||
"internal-v6": "fdxx:...",
|
||||
"internal-v4ll": "169.254.xxx.xxx",
|
||||
"internal-v6ll": "fe80::...",
|
||||
"note": "...", //optional, special precausions, like only supporting a specific amount of peers/ipv{4,6} in clearnet, etc
|
||||
"capacity": 100 //optional, default: -1 (infinite); estimated capacity of that node (i.e. OPENVZ(7) only has userspace WG (which consumes memory for every interface created))
|
||||
}
|
||||
},
|
||||
"MNT": "YOUR-MNT", // your MNT tag
|
||||
"ASN": "424242000", //Your ASN (used to generate default peer ListenPorts)
|
||||
"listen": "0.0.0.0",
|
||||
"port": 8042,
|
||||
"domain": "example.org", // domain to use for kioubit verification service
|
||||
"base-dir": "/", //optional:directury for which it is reachable (if behind some sort of reverse proxy) default "/"
|
||||
"peerings": "/path/to/peering-config.json", // optional; default "$PWD/peerings", directory to save existing peerings to
|
||||
"production": true, //optional, default true;
|
||||
"debug-mode": false, // optional; whethet to enable debugging; default false
|
||||
"flask-secret-key": "<secret-please-replace>", // secret key for session cookies
|
||||
"flask-template-dir": "../frontend/" // optional; default "../frontend"
|
||||
}
|
||||
|
|
|
@ -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 = ""
|
||||
|
@ -19,13 +24,13 @@ class AuthVerifyer ():
|
|||
pkey = load_publickey(FILETYPE_PEM, pk_content)
|
||||
self.x509 = X509()
|
||||
self.x509.set_pubkey(pkey)
|
||||
|
||||
|
||||
logging.debug(self.x509)
|
||||
|
||||
|
||||
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}")
|
||||
|
@ -33,10 +38,10 @@ class AuthVerifyer ():
|
|||
verify(self.x509, sig, params, 'sha512')
|
||||
except OpenSSL.crypto.Error:
|
||||
return False, "Signature Failed"
|
||||
|
||||
|
||||
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=",
|
||||
))
|
||||
#params = "eyJhc24iOiI0MjQyNDIzMDM1IiwidGltZSI6MTY2ODI1NjI5NSwiYWxsb3dlZDQiOiIxNzIuMjIuMTI1LjEyOFwvMjYsMTcyLjIwLjAuODFcLzMyIiwiYWxsb3dlZDYiOiJmZDYzOjVkNDA6NDdlNTo6XC80OCxmZDQyOmQ0MjpkNDI6ODE6OlwvNjQiLCJtbnQiOiJMQVJFLU1OVCIsImF1dGh0eXBlIjoibG9naW5jb2RlIiwiZG9tYWluIjoic3ZjLmJ1cmJsZS5kbjQyIn0=",
|
||||
#signature = 'MIGHAkFy1m+9ahjIc5cJk/p+RiXJbhbWT5rPSJNg9Q3c8UTAM4F7lz2OqdWHw6GZN5NQgvqm6OB3Y751djYwCd54y2Kn4wJCAcBaOrtSclxkGIleVx183PhTnSr97r2F089PsDzNXIBvH5pYUwvJX7hG0op0f5tPm7fl12HOOrr8Q6kWW+XTrgGX'
|
||||
|
|
|
@ -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,29 +36,31 @@ 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]
|
||||
|
||||
|
||||
def _load_config(self):
|
||||
with open(self.configfile) as cf:
|
||||
try:
|
||||
self._config = json.load(cf)
|
||||
except json.decoder.JSONDecodeError:
|
||||
raise SyntaxError(f"no valid JSON found in '{cf.name}'")
|
||||
|
||||
|
||||
if not "flask-template-dir" in self._config:
|
||||
self._config["flask-template-dir"] = "../frontend"
|
||||
|
||||
self._config["flask-template-dir"] = "../frontend"
|
||||
|
||||
if not "debug-mode" in self._config:
|
||||
self._config["debug-mode"] = False
|
||||
self._config["debug-mode"] = False
|
||||
if not "base-dir" in self._config:
|
||||
self._config["base-dir"] = "/"
|
||||
|
||||
|
||||
if not "peerings-data" in self._config:
|
||||
self._config["peering-data"] = "./peerings"
|
||||
logging.info(self._config)
|
||||
|
||||
|
||||
class PeeringManager:
|
||||
|
||||
def __init__(self, peerings_file):
|
||||
|
@ -59,15 +70,15 @@ 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)
|
||||
try:
|
||||
with open(self._peering_file,"r") as p:
|
||||
with open(self._peering_file, "x") as p:
|
||||
json.dump({"mnter": {}, "asn": {}}, p)
|
||||
try:
|
||||
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:
|
||||
with open(self._peering_file, "w") 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]:
|
||||
|
@ -115,16 +150,19 @@ class PeeringManager:
|
|||
self.peerings["asn"][asn] = []
|
||||
except KeyError:
|
||||
self.peerings["asn"][asn] = []
|
||||
|
||||
# deny more than one peering per ASN to one node
|
||||
|
||||
# deny more than one peering per ASN to one node
|
||||
for peering in self.peerings["asn"][asn]:
|
||||
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})
|
||||
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._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]:
|
||||
|
@ -138,26 +176,42 @@ class PeeringManager:
|
|||
return False
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
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"]
|
||||
|
@ -167,7 +221,7 @@ def check_peering_data(form):
|
|||
raise ValueError("peer-endpoint")
|
||||
else:
|
||||
new_peering["peer-endpoint"] = None
|
||||
|
||||
|
||||
if "peer-v6ll-enabled" in form and form["peer-v6ll-enabled"] == "on":
|
||||
new_peering["peer-v6ll"] = form["peer-v6ll"]
|
||||
if new_peering["peer-v6ll"] == "":
|
||||
|
@ -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
|
||||
|
@ -205,32 +259,35 @@ def check_peering_data(form):
|
|||
base64.b64decode(new_peering["peer-wgkey"])
|
||||
except:
|
||||
wg_key_invalid = True
|
||||
if wg_key_invalid:
|
||||
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)
|
||||
|
@ -283,17 +346,17 @@ def auth_required():
|
|||
|
||||
@app.route("/api/auth/kverify", methods=["GET", "POST"])
|
||||
def kioubit_auth():
|
||||
try:
|
||||
try:
|
||||
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,68 +367,89 @@ 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":
|
||||
session["return_url"] = request.args["return"] if "return" in request.args else ""
|
||||
|
||||
|
||||
return render_template("login.html", session=session, config=config, return_addr=session["return_url"])
|
||||
elif request.method == "POST" and config["debug-mode"]:
|
||||
try:
|
||||
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():
|
||||
|
||||
return f"{request.method} /peerings/delete?{str(request.args)}{str(request.form)}"
|
||||
|
||||
@app.route("/peerings/edit", methods=["GET","POST"])
|
||||
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"])
|
||||
@auth_required()
|
||||
def peerings_edit():
|
||||
print(session)
|
||||
|
@ -380,57 +464,67 @@ def peerings_edit():
|
|||
print(p)
|
||||
break
|
||||
return render_template("peerings-edit.html", session=session, config=config, mnt_peerings=mnt_peerings, selected_peering=selected_peering)
|
||||
else:
|
||||
else:
|
||||
return render_template("peerings-edit.html", session=session, config=config, mnt_peerings=mnt_peerings, selected_peering=None)
|
||||
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-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)
|
||||
selected_peering = None
|
||||
mnt_peerings = peerings.get_peerings_by_mnt(session["login"])
|
||||
for p in mnt_peerings:
|
||||
if p["node"] == request.args["node"] and p["ASN"] == request.args["asn"]:
|
||||
selected_peering = p
|
||||
print(p)
|
||||
break
|
||||
if not peering_valid:
|
||||
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=peering_or_msg, selected_peering=selected_peering), 400
|
||||
if not peerings.update_peering(session["user-data"]["asn"], request.args["node"], session["login"], 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)", selected_peering=selected_peering), 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)
|
||||
if request.method == "GET":
|
||||
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)
|
||||
else:
|
||||
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
|
||||
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=peering_or_msg), 400
|
||||
if not peerings.add_peering(session["user-data"]["asn"], request.args["node"], session["login"], 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 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)
|
||||
if request.method == "GET":
|
||||
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)
|
||||
else:
|
||||
return render_template("peerings.html", session=session, config=config, peerings=peerings)
|
||||
elif request.method == "POST":
|
||||
return peerings_new()
|
||||
elif request.method == "DELETE":
|
||||
|
@ -438,6 +532,7 @@ def peerings_view():
|
|||
else:
|
||||
abort(405)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
print(session)
|
||||
|
@ -446,19 +541,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()
|
||||
main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue