fifth commit
This commit is contained in:
parent
6acc767923
commit
325d2af09c
45
buckler.py
45
buckler.py
|
@ -6,6 +6,7 @@ import json
|
|||
import secrets
|
||||
import functools
|
||||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
from aiohttp import web
|
||||
import jinja2
|
||||
|
@ -37,14 +38,17 @@ def auth_required(func):
|
|||
if not sid or not user_id:
|
||||
raise web.HTTPFound(location=login_url)
|
||||
async with request.app['pool'].acquire() as conn:
|
||||
sessions = await conn.fetch(
|
||||
"SELECT * FROM user_session "
|
||||
"WHERE user_id = $1 AND expires > NOW()",
|
||||
user_id)
|
||||
session = [s for s in sessions if s.get('id') == sid]
|
||||
session = await conn.fetchrow(
|
||||
"SELECT user_info.id, user_info.username, user_info.admin, "
|
||||
"user_session.last_used "
|
||||
"FROM user_info LEFT JOIN user_session "
|
||||
"ON (user_info.id = user_session.user_id) "
|
||||
"WHERE user_info.id = $1 AND user_session.id = $2 "
|
||||
"AND user_session.expires > NOW()",
|
||||
user_id, sid)
|
||||
if session:
|
||||
request['session'] = dict(session)
|
||||
resp = await func(request, *args, **kwargs)
|
||||
session = session[0]
|
||||
tz = session['last_used'].tzinfo
|
||||
delta = datetime.now(tz) - session['last_used']
|
||||
if delta.seconds > 600:
|
||||
|
@ -76,6 +80,27 @@ def auth_required(func):
|
|||
@auth_required
|
||||
async def index(request):
|
||||
"""The index page."""
|
||||
async with request.app['pool'].acquire() as conn:
|
||||
avail_sites = await conn.fetch(
|
||||
"SELECT app_info.name, app_info.url "
|
||||
"FROM app_info LEFT JOIN app_user "
|
||||
"ON (app_info.id = app_user.app_id) "
|
||||
"WHERE app_user.user_id = $1",
|
||||
request['session']['id'])
|
||||
if request['session']['admin']:
|
||||
apps = await conn.fetch(
|
||||
"SELECT name FROM app_info")
|
||||
user_perms = await conn.fetch(
|
||||
"SELECT user_info.id, user_info.username, app_user.app_id "
|
||||
"FROM user_info LEFT JOIN app_user "
|
||||
"ON (user_info.id = app_user.user_id)")
|
||||
|
||||
if request['session']['admin']:
|
||||
apps = [app['name'] for app in apps]
|
||||
users = defaultdict(lambda: [False]*len(apps))
|
||||
for user_perm in user_perms:
|
||||
users[user_perm['username']][user_perm['app_id']-1] = True
|
||||
users_json = json.dumps(users)
|
||||
return render_template("index.html", request, locals())
|
||||
|
||||
|
||||
|
@ -101,8 +126,11 @@ async def login(request):
|
|||
return render_template("login.html", request, locals())
|
||||
|
||||
if argon2.verify(password, user_info['password_hash']):
|
||||
index_url = request.app.router['index'].url_for()
|
||||
resp = web.HTTPFound(location=index_url)
|
||||
url = request.cookies.get('redirect')
|
||||
if not url:
|
||||
url = request.app.router['index'].url_for()
|
||||
resp = web.HTTPFound(location=url)
|
||||
resp.set_cookie('redirect', '', max_age=0)
|
||||
resp.set_cookie(
|
||||
'userid',
|
||||
user_info['id'],
|
||||
|
@ -240,7 +268,6 @@ async def get_session(request):
|
|||
'meta': data_meta,
|
||||
'session_data': json.loads(data_meta.pop('session_data'))}
|
||||
|
||||
print(data)
|
||||
return web.json_response(data)
|
||||
else:
|
||||
error = {'error': "User ID or Session ID invalid."}
|
||||
|
|
46
static/buckler.css
Normal file
46
static/buckler.css
Normal file
|
@ -0,0 +1,46 @@
|
|||
body {
|
||||
margin-left: 10%;
|
||||
margin-right: 10%;
|
||||
background-color: lightgray;
|
||||
font-family: Helvetica,sans-serif;
|
||||
}
|
||||
|
||||
header {
|
||||
margin-bottom: 3em;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#logo {
|
||||
height: 5em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
main {
|
||||
display: grid;
|
||||
gap: 2em;
|
||||
background-color: whitesmoke;
|
||||
padding: 5%;
|
||||
border-radius: 0.5em;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
||||
0 3px 1px -2px rgba(0, 0, 0, 0.2),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
#avail_sites {
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#users {
|
||||
border: 1px solid lightgray;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#users tr {
|
||||
border: 1px solid lightgray;
|
||||
}
|
||||
|
||||
#users td {
|
||||
text-align: center;
|
||||
}
|
20
static/buckler.js
Normal file
20
static/buckler.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
function perm_change(row) {
|
||||
let user_perms = users_perms[row.children[0].textContent];
|
||||
let row_perms = [];
|
||||
for (let child of row.children) {
|
||||
if (child.firstChild.type == "checkbox") {
|
||||
if (child.firstChild.checked) {
|
||||
row_perms.push(true);
|
||||
} else {
|
||||
row_perms.push(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
let perms_changed = false;
|
||||
for (let i = 0; i < user_perms.length; i++) {
|
||||
if (user_perms[i] != row_perms[i]) {
|
||||
perms_changed = true;
|
||||
}
|
||||
}
|
||||
console.log("perms_changed = " + perms_changed);
|
||||
}
|
4
static/buckler_icon.svg
Normal file
4
static/buckler_icon.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="50" cy="50" r="48" stroke="black" fill="none"/>
|
||||
<circle cx="50" cy="50" r="18" stroke="black" fill="none"/>
|
||||
</svg>
|
After Width: | Height: | Size: 192 B |
|
@ -2,9 +2,49 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<title>Buckler</title>
|
||||
<script>
|
||||
var users_perms = {{ users_json|safe }};
|
||||
</script>
|
||||
<script type="text/javascript" src="/static/buckler.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/buckler.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Buckler</h1>
|
||||
Secret page.
|
||||
<header>
|
||||
<object id="logo" data="/static/buckler_icon.svg"></object>
|
||||
<h1>Buckler</h1>
|
||||
</header>
|
||||
<main>
|
||||
<div>
|
||||
Available sites
|
||||
<ul id="avail_sites">
|
||||
{% for site in avail_sites %}
|
||||
<li><a href="{{ site['url'] }}">{{ site['name'] }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% if request['session']['admin'] %}
|
||||
<table id="users">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
{% for app in apps %}
|
||||
<th>{{ app }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for username, values in users.items() %}
|
||||
<tr>
|
||||
<td>{{ username }}</td>
|
||||
{% for value in values %}
|
||||
<td><input type="checkbox" onchange="perm_change(this.parentElement.parentElement)"{% if value %} checked{% endif %}></td>
|
||||
{% endfor %}
|
||||
<td><input type="submit"></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -4,16 +4,20 @@
|
|||
<title>Buckler - Login</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Buckler Login</h1>
|
||||
<form action="{{ request.app.router['login'].url_for() }}" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<label for="username">Username</label>
|
||||
<input id="username" name="username" type="text"><br>
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" type="password"><br>
|
||||
{% if login_failed %}
|
||||
<ul><li>Username and/or password incorrect</li></ul>
|
||||
{% endif %}
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
||||
<header>
|
||||
<h1>Buckler Login</h1>
|
||||
</header>
|
||||
<main>
|
||||
<form action="{{ request.app.router['login'].url_for() }}" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<label for="username">Username</label>
|
||||
<input id="username" name="username" type="text"><br>
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" type="password"><br>
|
||||
{% if login_failed %}
|
||||
<ul><li>Username and/or password incorrect</li></ul>
|
||||
{% endif %}
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue
Block a user