Buckler/forms.py

134 lines
3.5 KiB
Python
Raw Normal View History

2019-09-29 13:25:07 -04:00
#!/usr/bin/env python3
"""
Co-routines for handling various forms in Buckler.
"""
2020-11-20 19:32:32 -05:00
import json
2019-10-17 13:47:25 -04:00
from passlib.hash import argon2
2019-09-29 13:25:07 -04:00
import tools
async def invite_user(request):
"""Allows an admin to invite a new user."""
if not request['session']['admin']:
return {'main': "You do not have permission to do that."}
data = await request.post()
email = data.get('email')
if not email:
return {'invite_user': "This field is required."}
# TODO: validate email address
await tools.send_invite(request, email)
return {}
2019-10-17 20:58:20 -04:00
async def change_user_perms(request):
"""Allows an admin to change user permissions."""
data = await request.post()
2020-11-20 19:32:32 -05:00
data = json.loads(data['perms'])
2019-10-17 20:58:20 -04:00
pluses = []
2020-11-20 19:32:32 -05:00
minuses = []
for user_id, perms in data.items():
for app_id, value in perms.items():
if value: # TODO: check for TypeError
pluses.append((int(user_id), int(app_id)))
else:
minuses.append((int(user_id), int(app_id)))
2019-10-17 20:58:20 -04:00
async with request.app['pool'].acquire() as conn:
await conn.executemany(
2020-11-20 19:32:32 -05:00
"INSERT INTO app_user (user_id, app_id) VALUES ($1, $2) "
2019-10-17 20:58:20 -04:00
"ON CONFLICT ON CONSTRAINT app_user_pkey DO NOTHING",
pluses)
await conn.executemany(
2020-11-20 19:32:32 -05:00
"DELETE FROM app_user WHERE user_id = $1 AND app_id = $2",
2019-10-17 20:58:20 -04:00
minuses)
return {}
async def new_app(request):
"""Allows an admin to add a new app to be managed by Buckler."""
data = await request.post()
app_name = data.get('app_name')
app_url = data.get('app_url')
app_key = data.get('app_key')
key_hash = argon2.hash(app_key)
async with request.app['pool'].acquire() as conn:
await conn.execute(
"INSERT INTO app_info (name, url, key_hash) "
"VALUES ($1, $2, $3)",
app_name, app_url, key_hash)
return {}
2019-09-29 13:25:07 -04:00
async def change_password(request):
"""Allows a user to change their password."""
errors = {}
data = await request.post()
current_pw = data.get('current_password')
new_pw = data.get('new_password')
verify_pw = data.get('verify_password')
if not all((current_pw, new_pw, verify_pw)):
errors['change_password'] = "All fields are required."
return errors
if not new_pw == verify_pw:
errors['change_password'] = "Passwords do not match."
return errors
async with request.app['pool'].acquire() as conn:
2020-04-09 07:58:38 -04:00
pw_hash = await conn.fetchrow(
2019-09-29 13:25:07 -04:00
"SELECT password_hash FROM user_info WHERE id = $1",
request['session']['id'])
if not argon2.verify(current_pw, pw_hash['password_hash']):
errors['change_password'] = "Invalid password."
return errors
h = argon2.hash(new_pw)
2020-04-09 07:58:38 -04:00
await conn.execute(
2019-09-29 13:25:07 -04:00
"UPDATE user_info SET password_hash = $1 WHERE id = $2",
h, request['session']['id'])
return errors
async def delete_key(request):
"""Allows a user to delete a security key."""
data = await request.post()
async with request.app['pool'].acquire() as conn:
for key, value in data.items():
key_id = key.replace('fido-', '')
if not key_id:
continue
try:
key_id = int(key_id)
except ValueError:
continue
if value != 'on':
continue
await conn.execute(
"DELETE FROM user_credential "
"WHERE id = $1 AND user_id = $2",
key_id, request['session']['id'])
return {}
async def delete_session(request):
"""Allows a user to delete a session ."""
data = await request.post()
async with request.app['pool'].acquire() as conn:
for key, value in data.items():
session_id = key.replace('session-', '', 1)
if not session_id:
continue
if value != 'on':
continue
await conn.execute(
"DELETE FROM user_session "
"WHERE id = $1 AND user_id = $2",
session_id, request['session']['id'])
return {}