diff --git a/budget/default_settings.py b/budget/default_settings.py index 210b3f20..15fe9cdd 100644 --- a/budget/default_settings.py +++ b/budget/default_settings.py @@ -10,3 +10,5 @@ SECRET_KEY = "tralala" MAIL_DEFAULT_SENDER = ("Budget manager", "budget@notmyidea.org") ACTIVATE_DEMO_PROJECT = True + +ADMIN_PASSWORD = "" diff --git a/budget/forms.py b/budget/forms.py index f4464751..06df7430 100644 --- a/budget/forms.py +++ b/budget/forms.py @@ -83,6 +83,11 @@ class AuthenticationForm(FlaskForm): submit = SubmitField(_("Get in")) +class AdminAuthenticationForm(FlaskForm): + admin_password = PasswordField(_("Admin password"), validators=[Required()]) + submit = SubmitField(_("Get in")) + + class PasswordReminder(FlaskForm): id = StringField(_("Project identifier"), validators=[Required()]) submit = SubmitField(_("Send me the code by email")) diff --git a/budget/templates/authenticate.html b/budget/templates/authenticate.html index 98914d09..f241c487 100644 --- a/budget/templates/authenticate.html +++ b/budget/templates/authenticate.html @@ -7,7 +7,13 @@ to") }} {{ _("create it") }}{{ _("?") }}

{% endif %} +{% if admin_auth %} +
+ {{ forms.admin(form) }} +
+{% else %}
{{ forms.authenticate(form) }}
+{% endif %} {% endblock %} diff --git a/budget/templates/forms.html b/budget/templates/forms.html index 01e54867..ffdd165b 100644 --- a/budget/templates/forms.html +++ b/budget/templates/forms.html @@ -45,6 +45,16 @@ {% endmacro %} +{% macro admin(form) %} + + {% include "display_errors.html" %} + + {{ form.hidden_tag() }} + {{ input(form.admin_password) }} + {{ submit(form.submit) }} + +{% endmacro %} + {% macro create_project(form, home=False) %} {% include "display_errors.html" %} diff --git a/budget/translations/fr/LC_MESSAGES/messages.mo b/budget/translations/fr/LC_MESSAGES/messages.mo index 1794c62c..c824b18a 100644 Binary files a/budget/translations/fr/LC_MESSAGES/messages.mo and b/budget/translations/fr/LC_MESSAGES/messages.mo differ diff --git a/budget/translations/fr/LC_MESSAGES/messages.po b/budget/translations/fr/LC_MESSAGES/messages.po index 8bf347ab..609846ff 100644 --- a/budget/translations/fr/LC_MESSAGES/messages.po +++ b/budget/translations/fr/LC_MESSAGES/messages.po @@ -41,6 +41,10 @@ msgstr "Email" msgid "Project identifier" msgstr "Identifiant du projet" +#: forms.py:87 +msgid "Admin password" +msgstr "Mot de passe administrateur" + #: forms.py:87 templates/send_invites.html:5 msgid "Create the project" msgstr "Créer le projet" @@ -158,6 +162,10 @@ msgstr "remboursements" msgid "Export file format" msgstr "Format du fichier d'export" +#: web.py:95 +msgid "This admin password is not the right one" +msgstr "Le mot de passe administrateur que vous avez entré n'est pas correct" + #: web.py:95 msgid "This private code is not the right one" msgstr "Le code que vous avez entré n'est pas correct" diff --git a/budget/web.py b/budget/web.py index efb427cb..c38bc26d 100644 --- a/budget/web.py +++ b/budget/web.py @@ -16,11 +16,12 @@ from flask_babel import get_locale, gettext as _ from smtplib import SMTPRecipientsRefused import werkzeug from sqlalchemy import orm +from functools import wraps # local modules from models import db, Project, Person, Bill -from forms import AuthenticationForm, EditProjectForm, InviteForm, \ - MemberForm, PasswordReminder, ProjectForm, get_billform_for, \ +from forms import AdminAuthenticationForm, AuthenticationForm, EditProjectForm, \ + InviteForm, MemberForm, PasswordReminder, ProjectForm, get_billform_for, \ ExportForm from utils import Redirect303, list_of_dicts2json, list_of_dicts2csv @@ -28,6 +29,19 @@ main = Blueprint("main", __name__) mail = Mail() +def requires_admin(f): + """Require admin permissions for @requires_admin decorated endpoints. + Has no effect if ADMIN_PASSWORD is empty (default value) + """ + @wraps(f) + def admin_auth(*args, **kws): + admin_password = session.get('admin_password', '') + if not admin_password == current_app.config['ADMIN_PASSWORD']: + raise Redirect303(url_for('.admin', goto=request.path)) + return f(*args, **kws) + return admin_auth + + @main.url_defaults def add_project_id(endpoint, values): """Add the project id to the url calls if it is expected. @@ -66,6 +80,23 @@ def pull_project(endpoint, values): url_for(".authenticate", project_id=project_id)) +@main.route("/admin", methods=["GET", "POST"]) +def admin(): + """Admin authentication""" + form = AdminAuthenticationForm() + goto = request.args.get('goto', url_for('.home')) + if request.method == "POST": + if form.validate(): + if form.admin_password.data == current_app.config['ADMIN_PASSWORD']: + session['admin_password'] = form.admin_password.data + session.update() + return redirect(goto) + else: + msg = _("This admin password is not the right one") + form.errors['admin_password'] = [msg] + return render_template("authenticate.html", form=form, admin_auth=True) + + @main.route("/authenticate", methods=["GET", "POST"]) def authenticate(project_id=None): """Authentication form"""