fifth commit

This commit is contained in:
iou1name 2019-09-20 19:24:12 -04:00
parent 6acc767923
commit 325d2af09c
6 changed files with 163 additions and 22 deletions

View File

@ -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
View 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
View 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
View 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

View File

@ -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>

View File

@ -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>