From 2a1a8d9e94574e1bb1e585c493e3042de27db00b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20Teijelo=20P=C3=A9rez?= Date: Wed, 4 Nov 2015 12:46:20 -0500 Subject: [PATCH] Show users tree --- main.py | 132 ++++++++++++++++++++++-------------------- static/css/isabel.css | 11 +++- static/img/icon.png | Bin 26012 -> 7576 bytes templates/admin.html | 5 +- templates/base.html | 10 +--- templates/users.html | 28 +++++++++ 6 files changed, 111 insertions(+), 75 deletions(-) create mode 100644 templates/users.html diff --git a/main.py b/main.py index f37c872..8478ef0 100755 --- a/main.py +++ b/main.py @@ -3,14 +3,11 @@ from flask import Flask, request, abort, make_response, \ render_template, redirect, url_for, \ json, jsonify, session, flash -from werkzeug import secure_filename -from multiprocessing import Process -from urllib.parse import unquote - import hashlib import random import shutil import time +import sys import re import os @@ -38,10 +35,12 @@ def delete_user(deluser): f.close() reload_freeradius() -def create_user(username, password): - nthash = hashlib.new('md4',password.encode('utf-16le')).hexdigest().upper() +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 := "{}"\n'.format(username, nthash)) + f.write('{} NT-Password := "{}" # created by {} \n'.format(username, nthash(password), creator)) f.close() reload_freeradius() @@ -58,6 +57,22 @@ def index(): 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(): @@ -68,18 +83,20 @@ def login(): 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") - try: - check_call(["radtest",username,password,"localhost","0","testing123"]) - except: + 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']) @@ -97,6 +114,7 @@ def admin(): 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") @@ -104,67 +122,53 @@ def admin(): pass2 is None or \ pass1 != pass2: return render_template("admin.html", create_error=True, errormsg="Password do not match") - create_user(username,pass1) + 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) + @app.route("/logout") def logout(): session.pop("logged_in",None) return redirect(url_for("index")) -#@app.route("/upload",methods=['GET','POST']) -#def upload(): -# if request.method == 'POST': -# f = request.files['circuit'] -# if len(f.filename) == 0: -# return render_template("emptyupload.html") -# if f and len(f.filename) > 0: -# sid = new_id() -# session_dir = os.path.join('sessions',sid) -# shutil.copytree('skel',session_dir) -# old_dir = os.getcwd() -# os.chdir(session_dir) -# try: -# skipcookie = unquote(request.cookies.get('skip_tests','')) -# skip = set(int(n) for n in skipcookie.split(',')) -# except: -# skip = set() -# options = {'skip_tests': skip} -# try: -# filename = secure_filename(f.filename) -# f.save(filename) -# p = Process(target=Verifier, args=(filename, ), kwargs={'options': options}) -# p.start() -# except: -# os.chdir(old_dir) -# raise -# os.chdir(old_dir) -# return redirect(url_for('tests',sid=sid)) -# return "Ocurrió algún error haciendo upload" - - -#@app.route("/details") -#def details(): -# sid = request.args.get('sid','') -# filename = request.args.get('file','') -# if len(sid) == 0: -# return '' -# if len(filename) == 0: -# return '' -# filename = secure_filename(filename) -# session_dir = os.path.join('sessions',sid) -# try: -# f = open(os.path.join(session_dir,filename), encoding="utf8") -# s = f.read() -# f.close() -# except FileNotFoundError: -# s = "" -# resp = make_response(s) -# resp.mimetype = 'text/plain' -# return resp if __name__ == '__main__': - app.debug = True + if "debug" in sys.argv: + users_file = "users.dpto2" + app.debug = True app.run(host="0.0.0.0") diff --git a/static/css/isabel.css b/static/css/isabel.css index 6383587..12cb83c 100644 --- a/static/css/isabel.css +++ b/static/css/isabel.css @@ -16,4 +16,13 @@ #selected-tests span { margin-left: 0.5em; -} \ No newline at end of file +} + +div.users-tree { + line-height: initial; +} + +.edges { + font-family: monospace; + line-height: initial; +} diff --git a/static/img/icon.png b/static/img/icon.png index 7472f8553bc5b80ef9f563fcf1f7004c61a119f8..10436b52db50ed586a0f74a0a32ff3760c3b2447 100644 GIT binary patch literal 7576 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 rFI#jaIW_;+-s1n?e~j@Uxunq<7tR0xAOJ~3 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 b@IUYe6j`{yWh=4300000NkvXXu0mjf{>ql_ diff --git a/templates/admin.html b/templates/admin.html index ae09838..2109779 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -6,7 +6,7 @@ {% endblock %} {% block content %} -

Usuarios de dpto2

+

Usuarios de dpto2

{% with messages = get_flashed_messages() %} {% if messages %} @@ -18,7 +18,6 @@ {% endif %} {% endwith %} -

Crear usuario nuevo:

@@ -76,7 +75,7 @@
+ - {% endblock %} diff --git a/templates/base.html b/templates/base.html index edec241..fa69b6d 100644 --- a/templates/base.html +++ b/templates/base.html @@ -10,7 +10,7 @@ - + @@ -27,14 +27,10 @@ {% endblock %} - -
-
-
+ +
{% block content %} {% endblock %} -
-
{% block body_scripts %} diff --git a/templates/users.html b/templates/users.html new file mode 100644 index 0000000..16046b7 --- /dev/null +++ b/templates/users.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{% block title %}Usuarios{% endblock %} + +{% block head %} + {{ super() }} +{% endblock %} + +{% block content %} +

Usuarios de dpto2:

+ +
+
+ {% for edges, username in users %} + + {% if username == "" %} +   Ilúvatar + {% else %} + {{ edges|replace(" "," ")|safe }} + {{ username }} + {% endif %} +
+ {% endfor %} +
+
+ + + +{% endblock %}