Compare commits

...

4 Commits

Author SHA1 Message Date
06cf8161e9 last_used only updates the key that was used 2019-09-26 19:23:04 -04:00
448b5048d8 style and added table columns 2019-09-26 19:15:46 -04:00
b174c1d2e8 added /delete_session 2019-09-26 18:44:00 -04:00
b24061fb05 added /delete_key 2019-09-26 18:29:39 -04:00
4 changed files with 100 additions and 45 deletions

View File

@ -53,8 +53,8 @@ def auth_required(func):
await conn.execute( await conn.execute(
"UPDATE user_session SET last_used = NOW(), " "UPDATE user_session SET last_used = NOW(), "
"expires = NOW() + INTERVAL '30 DAYS' " "expires = NOW() + INTERVAL '30 DAYS' "
"WHERE user_id = $1", "WHERE user_id = $1 AND id = $2",
user_id) user_id, sid)
resp.set_cookie( resp.set_cookie(
'userid', 'userid',
user_id, user_id,

View File

@ -44,7 +44,7 @@ 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 id, ip_address, date_created, last_used FROM user_session "
"WHERE user_id = $1", "WHERE user_id = $1",
request['session']['id']) request['session']['id'])
@ -224,13 +224,11 @@ async def get_session(request):
app = await conn.fetchrow("SELECT * FROM app_info WHERE id = $1", app_id) app = await conn.fetchrow("SELECT * FROM app_info WHERE id = $1", app_id)
if app: if app:
if argon2.verify(app_key, app['key_hash']): if argon2.verify(app_key, app['key_hash']):
sessions = await conn.fetch( session = await conn.fetchrow(
"SELECT * FROM user_session " "SELECT * FROM user_session "
"WHERE user_id = $1 AND expires > NOW()", "WHERE user_id = $1 AND id = $2 AND expires > NOW()",
user_id) user_id, user_sid)
session = [s for s in sessions if s.get('id') == user_sid]
if session: if session:
session = session[0]
data = await conn.fetchrow( data = await conn.fetchrow(
"SELECT user_info.username, app_user.session_data " "SELECT user_info.username, app_user.session_data "
"FROM user_info LEFT JOIN app_user " "FROM user_info LEFT JOIN app_user "
@ -244,8 +242,8 @@ async def get_session(request):
await conn.execute( await conn.execute(
"UPDATE user_session SET last_used = NOW(), " "UPDATE user_session SET last_used = NOW(), "
"expires = NOW() + INTERVAL '30 DAYS' " "expires = NOW() + INTERVAL '30 DAYS' "
"WHERE user_id = $1", "WHERE user_id = $1 AND id = $2",
user_id) user_id, user_sid)
await conn.close() await conn.close()
data_meta = dict(data) data_meta = dict(data)
@ -312,6 +310,50 @@ async def set_session(request):
return web.json_response(error) return web.json_response(error)
@routes.post(config.url_prefix + '/delete_key', name='delete_key')
@auth.auth_required
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'])
index_url = request.app.router['index'].url_for()
raise web.HTTPFound(location=index_url)
@routes.post(config.url_prefix + '/delete_session', name='delete_session')
@auth.auth_required
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'])
index_url = request.app.router['index'].url_for()
raise web.HTTPFound(location=index_url)
async def init_app(): async def init_app():
"""Initializes the application.""" """Initializes the application."""
app = web.Application() app = web.Application()

View File

@ -41,15 +41,16 @@ h2 {
list-style-type: none; list-style-type: none;
} }
#users { table {
border: 1px solid lightgray; border: 1px solid lightgray;
border-collapse: collapse; border-collapse: collapse;
width: 100%;
} }
#users tr { tr {
border: 1px solid lightgray; border: 1px solid lightgray;
} }
#users td { td {
text-align: center; text-align: center;
} }

View File

@ -78,6 +78,7 @@
<article style="display: none;"> <article style="display: none;">
<hr> <hr>
{% if fido2_keys %} {% if fido2_keys %}
<form action="{{ request.app.router['delete_key'].url_for() }}" method="POST" enctype="application/x-www-form-urlencoded">
<table id="security_keys"> <table id="security_keys">
<thead> <thead>
<tr> <tr>
@ -94,6 +95,8 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<input type="submit" value="Delete">
</form>
{% else %} {% else %}
<span>No registered keys.</span> <span>No registered keys.</span>
{% endif %} {% endif %}
@ -104,22 +107,31 @@
<h2>Active Sessions</h2> <h2>Active Sessions</h2>
<article style="display: none;"> <article style="display: none;">
<hr> <hr>
<form action="{{ request.app.router['delete_session'].url_for() }}" method="POST" enctype="application/x-www-form-urlencoded">
<table id="active_sessions"> <table id="active_sessions">
<thead> <thead>
<tr> <tr>
<th>Session ID</th>
<th>IP Address</th> <th>IP Address</th>
<th>Created</th>
<th>Last Used</th>
<th>Delete</th> <th>Delete</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for session in active_sessions %} {% for session in active_sessions %}
<tr> <tr>
<td><code>{{ session['id'][:5] }}...{{ session['id'][-5:] }}</code></td>
<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>{{ session['date_created'].strftime('%Y-%m-%d %H:%M') }}</td>
<td>{{ session['last_used'].strftime('%Y-%m-%d %H:%M') }}</td>
<td><input aria-label="Delete {{ session['id'][:5] }}...{{ session['id'][-5:] }}" id="session-{{ session['id'] }}" name="session-{{ session['id'] }}" type="checkbox"></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<input type="submit" value="Delete">
</form>
</article> </article>
</section> </section>
</main> </main>