From 291fbe7bc47ec4d7574e7247e3e40dda4de6d155 Mon Sep 17 00:00:00 2001 From: kaiyou Date: Sun, 29 Oct 2017 14:49:07 +0100 Subject: [PATCH] Add views and templates for authentication tokens --- admin/mailu/ui/forms.py | 11 +++++ admin/mailu/ui/templates/sidebar.html | 5 +++ admin/mailu/ui/templates/token/create.html | 9 ++++ admin/mailu/ui/templates/token/list.html | 36 +++++++++++++++ admin/mailu/ui/templates/user/list.html | 1 + admin/mailu/ui/views/__init__.py | 5 ++- admin/mailu/ui/views/tokens.py | 51 ++++++++++++++++++++++ 7 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 admin/mailu/ui/templates/token/create.html create mode 100644 admin/mailu/ui/templates/token/list.html create mode 100644 admin/mailu/ui/views/tokens.py diff --git a/admin/mailu/ui/forms.py b/admin/mailu/ui/forms.py index b00f4dac..bd371eec 100644 --- a/admin/mailu/ui/forms.py +++ b/admin/mailu/ui/forms.py @@ -104,6 +104,17 @@ class UserReplyForm(flask_wtf.FlaskForm): submit = fields.SubmitField(_('Update')) +class TokenForm(flask_wtf.FlaskForm): + raw_password = fields.StringField( + _('Your token (write it down, as it will never be displayed again)') + ) + comment = fields.StringField(_('Comment')) + ip = fields.StringField( + _('Authorized IP'), [validators.Optional(), validators.IPAddress()] + ) + submit = fields.SubmitField(_('Create')) + + class AliasForm(flask_wtf.FlaskForm): localpart = fields.StringField(_('Alias'), [validators.DataRequired()]) wildcard = fields.BooleanField( diff --git a/admin/mailu/ui/templates/sidebar.html b/admin/mailu/ui/templates/sidebar.html index 14abe241..920074e2 100644 --- a/admin/mailu/ui/templates/sidebar.html +++ b/admin/mailu/ui/templates/sidebar.html @@ -28,6 +28,11 @@ {% trans %}Fetched accounts{% endtrans %} +
  • + + {% trans %}Authentication tokens{% endtrans %} + +
  • {% trans %}Sign out{% endtrans %} diff --git a/admin/mailu/ui/templates/token/create.html b/admin/mailu/ui/templates/token/create.html new file mode 100644 index 00000000..a64e662c --- /dev/null +++ b/admin/mailu/ui/templates/token/create.html @@ -0,0 +1,9 @@ +{% extends "form.html" %} + +{% block title %} +{% trans %}Create an authentication token{% endtrans %} +{% endblock %} + +{% block subtitle %} +{{ user }} +{% endblock %} diff --git a/admin/mailu/ui/templates/token/list.html b/admin/mailu/ui/templates/token/list.html new file mode 100644 index 00000000..b3996da8 --- /dev/null +++ b/admin/mailu/ui/templates/token/list.html @@ -0,0 +1,36 @@ +{% extends "base.html" %} + +{% block title %} +{% trans %}Authentication tokens{% endtrans %} +{% endblock %} + +{% block subtitle %} +{{ user }} +{% endblock %} + +{% block main_action %} +{% trans %}New token{% endtrans %} +{% endblock %} + +{% block box %} + + + + + + + + + {% for token in user.tokens %} + + + + + + + {% endfor %} + +
    {% trans %}Actions{% endtrans %}{% trans %}Comment{% endtrans %}{% trans %}Authorized IP{% endtrans %}{% trans %}Created{% endtrans %}
    + + {{ token.comment }}{{ token.ip or "any" }}{{ token.created_at }}
    +{% endblock %} diff --git a/admin/mailu/ui/templates/user/list.html b/admin/mailu/ui/templates/user/list.html index a3ee52b1..3c6156e9 100644 --- a/admin/mailu/ui/templates/user/list.html +++ b/admin/mailu/ui/templates/user/list.html @@ -36,6 +36,7 @@       +   {{ user }} diff --git a/admin/mailu/ui/views/__init__.py b/admin/mailu/ui/views/__init__.py index e4f5d7d2..e7ae8b35 100644 --- a/admin/mailu/ui/views/__init__.py +++ b/admin/mailu/ui/views/__init__.py @@ -1 +1,4 @@ -__all__ = ['admins', 'aliases', 'alternatives', 'base', 'domains', 'fetches', 'managers', 'users', 'relays'] +__all__ = [ + 'admins', 'aliases', 'alternatives', 'base', 'domains', 'fetches', + 'managers', 'users', 'relays', 'tokens' +] diff --git a/admin/mailu/ui/views/tokens.py b/admin/mailu/ui/views/tokens.py new file mode 100644 index 00000000..312d8a49 --- /dev/null +++ b/admin/mailu/ui/views/tokens.py @@ -0,0 +1,51 @@ +from mailu import db, models +from mailu.ui import ui, forms, access + +from passlib import pwd + +import flask +import flask_login +import wtforms_components + + +@ui.route('/token/list', methods=['GET', 'POST'], defaults={'user_email': None}) +@ui.route('/token/list/', methods=['GET']) +@access.owner(models.User, 'user_email') +def token_list(user_email): + user_email = user_email or flask_login.current_user.email + user = models.User.query.get(user_email) or flask.abort(404) + return flask.render_template('token/list.html', user=user) + + +@ui.route('/token/create', methods=['GET', 'POST'], defaults={'user_email': None}) +@ui.route('/token/create/', methods=['GET', 'POST']) +@access.owner(models.User, 'user_email') +def token_create(user_email): + user_email = user_email or flask_login.current_user.email + user = models.User.query.get(user_email) or flask.abort(404) + form = forms.TokenForm() + form.raw_password.data = pwd.genword(entropy=128, charset="hex") + wtforms_components.read_only(form.raw_password) + if form.validate_on_submit(): + token = models.Token(user=user) + form.populate_obj(token) + token.set_password(form.raw_password.data) + db.session.add(token) + db.session.commit() + flask.flash('Authentication token created') + return flask.redirect( + flask.url_for('.token_list', user_email=user.email)) + return flask.render_template('token/create.html', form=form) + + +@ui.route('/token/delete/', methods=['GET', 'POST']) +@access.confirmation_required("delete an authentication token") +@access.owner(models.Token, 'token_id') +def token_delete(token_id): + token = models.Token.query.get(token_id) or flask.abort(404) + user = token.user + db.session.delete(token) + db.session.commit() + flask.flash('Authentication token deleted') + return flask.redirect( + flask.url_for('.token_list', user_email=user.email))