diff options
| author | 0livd <0livd@users.noreply.github.com> | 2017-05-18 10:48:09 +0100 |
|---|---|---|
| committer | Alexis Metaireau <alexis@notmyidea.org> | 2017-05-18 11:48:09 +0200 |
| commit | ea8eda35a7bd831964c38b38cc9a5b19bcb44d6a (patch) | |
| tree | 5a5efbe2523a1f8f84aec65c298a9b4fd6a9421e /budget/web.py | |
| parent | 091553be566d97816ed898207b56d2694eb2efdd (diff) | |
| download | ihatemoney-mirror-ea8eda35a7bd831964c38b38cc9a5b19bcb44d6a.zip ihatemoney-mirror-ea8eda35a7bd831964c38b38cc9a5b19bcb44d6a.tar.gz ihatemoney-mirror-ea8eda35a7bd831964c38b38cc9a5b19bcb44d6a.tar.bz2 | |
Public project creation and admin permissions (#210)
* Add a @requires_admin decorator
It can be used to protect specific endpoints with ADMIN_PASSWORD
(a password that is stored unencrypted in the settings)
The decorator has no effect if ADMIN_PASSWORD is an empty string (default value)
* Require admin permissions to access create project endpoint
When ADMIN_PASSWORD is not empty, project creation form on the
home page will be replaced by a link to the create project endpoint
so one is able to enter the admin password before filling the form
Diffstat (limited to 'budget/web.py')
| -rw-r--r-- | budget/web.py | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/budget/web.py b/budget/web.py index efb427c..3bfa73a 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""" @@ -121,14 +152,18 @@ def authenticate(project_id=None): def home(): project_form = ProjectForm() auth_form = AuthenticationForm() + # If ADMIN_PASSWORD is empty we consider that admin mode is disabled + is_admin_mode_enabled = bool(current_app.config['ADMIN_PASSWORD']) is_demo_project_activated = current_app.config['ACTIVATE_DEMO_PROJECT'] return render_template("home.html", project_form=project_form, is_demo_project_activated=is_demo_project_activated, + is_admin_mode_enabled=is_admin_mode_enabled, auth_form=auth_form, session=session) @main.route("/create", methods=["GET", "POST"]) +@requires_admin def create_project(): form = ProjectForm() if request.method == "GET" and 'project_id' in request.values: |
