Show users tree
This commit is contained in:
parent
ba036d26b7
commit
2a1a8d9e94
6 changed files with 111 additions and 75 deletions
130
main.py
130
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__':
|
||||
if "debug" in sys.argv:
|
||||
users_file = "users.dpto2"
|
||||
app.debug = True
|
||||
app.run(host="0.0.0.0")
|
||||
|
|
|
@ -17,3 +17,12 @@
|
|||
#selected-tests span {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
div.users-tree {
|
||||
line-height: initial;
|
||||
}
|
||||
|
||||
.edges {
|
||||
font-family: monospace;
|
||||
line-height: initial;
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 7.4 KiB |
|
@ -6,7 +6,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<center><h1>Usuarios de <code>dpto2</code></h1></center>
|
||||
<center><h2>Usuarios de <code>dpto2</code></h2></center>
|
||||
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
|
@ -18,7 +18,6 @@
|
|||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<div class="container" style="width: 601px;">
|
||||
<div class="row"><h3>Crear usuario nuevo:</h3></div>
|
||||
|
||||
<div class="row">
|
||||
|
@ -76,7 +75,7 @@
|
|||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row"><a href="{{ url_for('list_users') }}">Lista de usuarios</a></div>
|
||||
<div class="row"><a href="{{ url_for('logout') }}">Cerrar sesión</a></div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<link href="{{ static('css/bootstrap.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ static('css/font-awesome.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ static('css/isabel.css') }}" rel="stylesheet">
|
||||
<!-- <link href="{{ static('img/icon.png') }}" rel="icon"/> -->
|
||||
<link href="{{ static('img/icon.png') }}" rel="icon"/>
|
||||
|
||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
||||
<script src="{{ static('js/cookies.js')}}"></script>
|
||||
|
@ -28,14 +28,10 @@
|
|||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="container" style="width: 600px;">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block body_scripts %}
|
||||
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
||||
|
|
28
templates/users.html
Normal file
28
templates/users.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}Usuarios{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row"><h3>Usuarios de <code>dpto2</code>:</h3></div>
|
||||
|
||||
<div class="well well-lg">
|
||||
<div class="users-tree">
|
||||
{% for edges, username in users %}
|
||||
<span>
|
||||
{% if username == "" %}
|
||||
<i>Ilúvatar</i>
|
||||
{% else %}
|
||||
<span class="edges">{{ edges|replace(" "," ")|safe }}</span>
|
||||
{{ username }}
|
||||
{% endif %}
|
||||
</span><br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row"><a href="{{ url_for('admin') }}">Administrar usuarios</a></div>
|
||||
<div class="row"><a href="{{ url_for('logout') }}">Cerrar sesión</a></div>
|
||||
{% endblock %}
|
Loading…
Reference in a new issue