Compare commits
No commits in common. "4309d65c854c7d974efbbf14aed1ff5f3b528bd8" and "9d1a720ab73fb87aecd6a9f79323782cf479b679" have entirely different histories.
4309d65c85
...
9d1a720ab7
18
buckler.py
18
buckler.py
|
@ -16,8 +16,9 @@ import asyncpg
|
||||||
import uvloop
|
import uvloop
|
||||||
|
|
||||||
import auth
|
import auth
|
||||||
import tools
|
import mail
|
||||||
import config
|
import config
|
||||||
|
import validation
|
||||||
|
|
||||||
uvloop.install()
|
uvloop.install()
|
||||||
routes = web.RouteTableDef()
|
routes = web.RouteTableDef()
|
||||||
|
@ -35,7 +36,7 @@ async def index(request):
|
||||||
request['session']['id'])
|
request['session']['id'])
|
||||||
if request['session']['admin']:
|
if request['session']['admin']:
|
||||||
apps = await conn.fetch(
|
apps = await conn.fetch(
|
||||||
"SELECT id, name FROM app_info")
|
"SELECT name FROM app_info")
|
||||||
user_perms = await conn.fetch(
|
user_perms = await conn.fetch(
|
||||||
"SELECT user_info.id, user_info.username, app_user.app_id "
|
"SELECT user_info.id, user_info.username, app_user.app_id "
|
||||||
"FROM user_info LEFT JOIN app_user "
|
"FROM user_info LEFT JOIN app_user "
|
||||||
|
@ -44,16 +45,15 @@ async def index(request):
|
||||||
"SELECT * FROM user_credential WHERE user_id = $1",
|
"SELECT * FROM user_credential WHERE user_id = $1",
|
||||||
request['session']['id'])
|
request['session']['id'])
|
||||||
active_sessions = await conn.fetch(
|
active_sessions = await conn.fetch(
|
||||||
"SELECT id, ip_address FROM user_session "
|
"SELECT ip_address FROM user_session "
|
||||||
"WHERE user_id = $1",
|
"WHERE user_id = $1",
|
||||||
request['session']['id'])
|
request['session']['id'])
|
||||||
|
|
||||||
if request['session']['admin']:
|
if request['session']['admin']:
|
||||||
users = defaultdict(lambda: {app['name']: False for app in apps})
|
apps = [app['name'] for app in apps]
|
||||||
|
users = defaultdict(lambda: [False]*len(apps))
|
||||||
for user_perm in user_perms:
|
for user_perm in user_perms:
|
||||||
index = tools.find_dict(apps, 'id', user_perm['app_id'])
|
users[user_perm['username']][user_perm['app_id']-1] = True
|
||||||
if index != -1:
|
|
||||||
users[user_perm['username']][apps[index]['name']] = True
|
|
||||||
users_json = json.dumps(users)
|
users_json = json.dumps(users)
|
||||||
return render_template("index.html", request, locals())
|
return render_template("index.html", request, locals())
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ async def register(request):
|
||||||
return render_template("register.html", request, locals())
|
return render_template("register.html", request, locals())
|
||||||
|
|
||||||
form = await request.post()
|
form = await request.post()
|
||||||
errors = await tools.validate_register(request, form)
|
errors = await validation.validate_register(request, form)
|
||||||
if any(errors.values()):
|
if any(errors.values()):
|
||||||
return render_template("register.html", request, locals())
|
return render_template("register.html", request, locals())
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ async def register(request):
|
||||||
await conn.execute(
|
await conn.execute(
|
||||||
"DELETE FROM invite WHERE token = $1",
|
"DELETE FROM invite WHERE token = $1",
|
||||||
invite_token)
|
invite_token)
|
||||||
await tools.send_confirmation(request, user['id'], email)
|
await mail.send_confirmation(request, user['id'], email)
|
||||||
message = "An email has been sent." # TODO: more better
|
message = "An email has been sent." # TODO: more better
|
||||||
else:
|
else:
|
||||||
message = "Invalid invitation token."
|
message = "Invalid invitation token."
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Various different tools for Buckler.
|
Tools for sending emails.
|
||||||
"""
|
"""
|
||||||
import email.mime.text
|
import email.mime.text
|
||||||
import smtplib
|
import smtplib
|
||||||
|
@ -8,7 +8,6 @@ import secrets
|
||||||
|
|
||||||
import config
|
import config
|
||||||
|
|
||||||
|
|
||||||
def send_mail(to_addr, subject, body):
|
def send_mail(to_addr, subject, body):
|
||||||
"""
|
"""
|
||||||
Sends an email.
|
Sends an email.
|
||||||
|
@ -54,44 +53,4 @@ async def send_confirmation(request, user_id, to_addr):
|
||||||
confirm_url = request.app.router['register'].url_for().with_query(d)
|
confirm_url = request.app.router['register'].url_for().with_query(d)
|
||||||
confirm_url = config.server_domain + str(confirm_url)
|
confirm_url = config.server_domain + str(confirm_url)
|
||||||
body = "Buckle up.\n" + confirm_url
|
body = "Buckle up.\n" + confirm_url
|
||||||
|
send_mail(to_addr, "Buckler Invite", body)
|
||||||
|
|
||||||
async def validate_register(request, form):
|
|
||||||
"""Validate data from the registration form."""
|
|
||||||
username = form.get('username')
|
|
||||||
email = form.get('email')
|
|
||||||
password = form.get('password')
|
|
||||||
password_verify = form.get('password_verify')
|
|
||||||
|
|
||||||
async with request.app['pool'].acquire() as conn:
|
|
||||||
users = await conn.fetch(
|
|
||||||
"SELECT username, email FROM user_info "
|
|
||||||
"WHERE username = $1 OR email = $2",
|
|
||||||
username, email)
|
|
||||||
|
|
||||||
errors = {'password': [], 'username': [], 'email': []}
|
|
||||||
if password != password_verify:
|
|
||||||
errors['password'].append("Passwords do not match.")
|
|
||||||
if len(password) < 8 or len(password) > 10240:
|
|
||||||
errors['password'].append(
|
|
||||||
"Password must be between 8 and 10240 characters long.")
|
|
||||||
if len(username) < 3 or len(username) > 20:
|
|
||||||
errors['username'].append(
|
|
||||||
"Username must be between 3 and 20 characters long.")
|
|
||||||
if username in [user['username'] for user in users]:
|
|
||||||
errors['username'].append("Username already in use.")
|
|
||||||
if email in [user['email'] for user in users]:
|
|
||||||
errors['email'].append("Email already in use.")
|
|
||||||
|
|
||||||
return errors
|
|
||||||
|
|
||||||
|
|
||||||
def find_dict(lst, key, value):
|
|
||||||
"""
|
|
||||||
Returns the index of the dictionary in the given `lst` which
|
|
||||||
has d[`key`] == `value`.
|
|
||||||
"""
|
|
||||||
for i, d in enumerate(lst):
|
|
||||||
if d[key] == value:
|
|
||||||
return i
|
|
||||||
return -1
|
|
|
@ -14,19 +14,19 @@ function load() {
|
||||||
|
|
||||||
function perm_change(row) {
|
function perm_change(row) {
|
||||||
let user_perms = users_perms[row.children[0].textContent];
|
let user_perms = users_perms[row.children[0].textContent];
|
||||||
let row_perms = {};
|
let row_perms = [];
|
||||||
for (let child of row.children) {
|
for (let child of row.children) {
|
||||||
if (child.firstChild.type == "checkbox") {
|
if (child.firstChild.type == "checkbox") {
|
||||||
if (child.firstChild.checked) {
|
if (child.firstChild.checked) {
|
||||||
row_perms[child.firstChild.dataset.appName] = true;
|
row_perms.push(true);
|
||||||
} else {
|
} else {
|
||||||
row_perms[child.firstChild.dataset.appName] = false;
|
row_perms.push(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let perms_changed = false;
|
let perms_changed = false;
|
||||||
for (let app_name of Object.keys(user_perms)) {
|
for (let i = 0; i < user_perms.length; i++) {
|
||||||
if (user_perms[app_name] != row_perms[app_name]) {
|
if (user_perms[i] != row_perms[i]) {
|
||||||
perms_changed = true;
|
perms_changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>User</th>
|
<th>User</th>
|
||||||
{% for app in apps %}
|
{% for app in apps %}
|
||||||
<th>{{ app['name'] }}</th>
|
<th>{{ app }}</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -47,8 +47,8 @@
|
||||||
{% for username, values in users.items() %}
|
{% for username, values in users.items() %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ username }}</td>
|
<td>{{ username }}</td>
|
||||||
{% for name, value in values.items() %}
|
{% for value in values %}
|
||||||
<td><input aria-label="{{ username }}-{{ name }}" data-app-name={{ name }} type="checkbox" onchange="perm_change(this.parentElement.parentElement)"{% if value %} checked{% endif %}></td>
|
<td><input type="checkbox" onchange="perm_change(this.parentElement.parentElement)"{% if value %} checked{% endif %}></td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<td><input type="submit"></td>
|
<td><input type="submit"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
{% for key in fido2_keys %}
|
{% for key in fido2_keys %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ key['nick'] }}</td>
|
<td>{{ key['nick'] }}</td>
|
||||||
<td><input aria-label="Delete {{ key['nick'] }}" id="fido-{{ key['id'] }}" name="fido-{{ key['id'] }}" type="checkbox"></td>
|
<td><input type="checkbox"></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -115,7 +115,7 @@
|
||||||
{% for session in active_sessions %}
|
{% for session in active_sessions %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ session['ip_address'] }}</td>
|
<td>{{ session['ip_address'] }}</td>
|
||||||
<td><input aria-label="Delete {{ session['id'][:5] }}" id="session-{{ session['id'][:5] }}" name="session-{{ session['id'][:5] }}" type="checkbox"></td>
|
<td><input type="checkbox"></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
33
validation.py
Normal file
33
validation.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Functions for validating forms.
|
||||||
|
"""
|
||||||
|
|
||||||
|
async def validate_register(request, form):
|
||||||
|
"""Validate data from the registration form."""
|
||||||
|
username = form.get('username')
|
||||||
|
email = form.get('email')
|
||||||
|
password = form.get('password')
|
||||||
|
password_verify = form.get('password_verify')
|
||||||
|
|
||||||
|
async with request.app['pool'].acquire() as conn:
|
||||||
|
users = await conn.fetch(
|
||||||
|
"SELECT username, email FROM user_info "
|
||||||
|
"WHERE username = $1 OR email = $2",
|
||||||
|
username, email)
|
||||||
|
|
||||||
|
errors = {'password': [], 'username': [], 'email': []}
|
||||||
|
if password != password_verify:
|
||||||
|
errors['password'].append("Passwords do not match.")
|
||||||
|
if len(password) < 8 or len(password) > 10240:
|
||||||
|
errors['password'].append(
|
||||||
|
"Password must be between 8 and 10240 characters long.")
|
||||||
|
if len(username) < 3 or len(username) > 20:
|
||||||
|
errors['username'].append(
|
||||||
|
"Username must be between 3 and 20 characters long.")
|
||||||
|
if username in [user['username'] for user in users]:
|
||||||
|
errors['username'].append("Username already in use.")
|
||||||
|
if email in [user['email'] for user in users]:
|
||||||
|
errors['email'].append("Email already in use.")
|
||||||
|
|
||||||
|
return errors
|
Loading…
Reference in New Issue
Block a user