#!/usr/bin/env python3 from flask import Flask, request, abort, make_response, \ render_template, redirect, url_for, \ json, jsonify, session, flash from collections import namedtuple import hashlib import random import shutil import time import sys import re import os from subprocess import check_call, call #app = Flask("ISABEL-2 Verifier") # That app name breaks Ubuntu 14.04 :-o app = Flask("main") app.secret_key = "6ab77f3c45447429c2ae163c260a626029519a66450e474c" debug = True users_file = "/etc/freeradius/users.dpto2" dhcp_hosts_file = "/etc/dnsmasq.d/dpto2/dhcp_hosts" def reload_freeradius(): call("./reload_freeradius") def delete_user(deluser): f = open(users_file) lines = f.readlines() f.close() f = open(users_file,"w") for line in lines: if line.startswith(deluser): continue f.write(line) f.close() reload_freeradius() def nthash(password): return hashlib.new('md4',password.encode('utf-16le')).hexdigest().upper() def create_user(username, password, creator): f = open(users_file,"a") f.write('{} NT-Password := "{}" # created by {} \n'.format(username, nthash(password), creator)) f.close() reload_freeradius() @app.route("/") def index(): f = open(users_file) guestpass = "?" for line in f: if line.startswith("guest"): m = re.search(':=\s+"(.+?)"\s*$',line) if m: guestpass = m.group(1) break return render_template("index.html", guestpass=guestpass) def load_users(): users = [] with open(users_file) as f: for l in f: if l.strip().startswith("#"): continue m = re.match("(^\S+).*-Password\s+:=\s+\"(\S+)\"(?:\s+#.*created.by\s+(\S+))?", l) if m: users.append(m.groups()) return users def check_login(username, password): for u,p,c in load_users(): if u == username and p == nthash(password): return True raise ValueError("Invalid username or password") @app.route("/login",methods=['GET','POST']) def login(): if session.get('logged_in',False): return redirect(url_for('admin')) if request.method == 'GET': return render_template("login.html") if request.method == 'POST': username = request.form.get("username",None) password = request.form.get("password",None) if username is None or password is None: return render_template("login.html",error=True,errormsg="invalid username or password") if username == 'guest': return render_template("login.html",error=True,errormsg="guest user has no admin privileges") try: check_login(username, password) except Exception as e: return render_template("login.html",error=True,errormsg=str(e)) session['logged_in'] = True session['username'] = username return redirect(url_for('admin')) @app.route("/admin",methods=['GET','POST']) def admin(): if not session.get('logged_in', False): return redirect(url_for('login')) if request.method == 'POST': deluser = request.form.get('deluser',None) if deluser is not None: if deluser == 'guest': return render_template("admin.html", delete_error=True, errormsg="Cannot delete guest user") delete_user(deluser) flash("User deleted succesfully") username = request.form.get('username',None) pass1 = request.form.get('password1',None) pass2 = request.form.get('password2',None) creator = session['username'] if username is not None: if username == 'guest': return render_template("admin.html", create_error=True, errormsg="Cannot create guest user") if pass1 is None or \ pass2 is None or \ pass1 != pass2: return render_template("admin.html", create_error=True, errormsg="Password do not match") create_user(username,pass1,creator) flash("User created successfully") return render_template("admin.html") def render_users_tree(tree): lines = [] def _render(user, edges, is_last): lines.append((edges + (" └─" if is_last else " ├─"), user)) n = len(tree[user]) for i,u in enumerate(tree[user]): _render(u, edges + (" " if is_last else " │ "), i == n - 1) return lines # root = tree(""); n = len(root) # for i,u in enumerate(root): _render("", "", True) return lines @app.route("/users") def list_users(): if not session.get('logged_in', False): return redirect(url_for('login')) users = load_users() users_set = set(x[0] for x in users) tree = { "": [] } for user,passwd,creator in users: if user == "guest": continue tree[user] = [] if creator is None: tree[""].append(user) else: if creator not in users_set: creator += " (invalid username)" tree[""].append(creator) tree[creator] = tree.get(creator,[]) + [user] lines = render_users_tree(tree) return render_template("users.html", users=lines) mac_re = re.compile("(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}") ip_re = re.compile("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") DhcpHostLine = namedtuple("DhcpHostLine","macs ip") def parse_dchp_host(line): macs = [] ip = "" parts = line.split(",") for p in parts: p = p.strip() m = mac_re.match(p) if m: macs.append(m.group(0)) m = ip_re.match(p) if m: ip = m.group(0) return DhcpHostLine(macs, ip) Ip = namedtuple("Ip","reserved_by dhcp") @app.route("/ips") def ips(): ipmap = {} for i in range(1,255): ipmap[i] = Ip("",True) ipmap[0] = ipmap[255] = Ip("", False) with open(dhcp_hosts_file) as f: meta = {} for line in f: line = line.strip() if line.startswith("#"): try: meta = json.loads(line[1:]) except: meta = {} continue if not isinstance(meta,dict): meta = {} continue if re.match("^[0-9a-fA-F]{2}:",line): r = parse_dchp_host(line) ip = int(r.ip.split(".")[-1]) ipmap[ip] = Ip(meta.get("reserved-by",""), False) return render_template("ips.html", ipmap=ipmap) @app.route("/ip/") def ip(addr): return render_template("ip.html", ip=addr) @app.route("/logout") def logout(): session.pop("logged_in",None) return redirect(url_for("index")) if __name__ == '__main__': if "debug" in sys.argv: users_file = "users.dpto2" dhcp_hosts_file = "dhcp-hosts.dpto2" dhcp_opts_file = "dhcp-opts.dpto2" app.debug = True app.run(host="0.0.0.0")