From d783feb7d0da20189f2eb4124f29534b426aa6db Mon Sep 17 00:00:00 2001 From: Darks Date: Fri, 5 Mar 2021 21:52:07 +0100 Subject: [PATCH 1/3] PEP8: removed trailing spaces --- app/forms/login.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/forms/login.py b/app/forms/login.py index 498a319..c43fd56 100644 --- a/app/forms/login.py +++ b/app/forms/login.py @@ -5,13 +5,13 @@ from wtforms.validators import InputRequired class LoginForm(FlaskForm): username = StringField( - 'Identifiant', + 'Identifiant', validators=[ InputRequired(), ], ) password = PasswordField( - 'Mot de passe', + 'Mot de passe', validators=[ InputRequired(), ], From 87ef91b9e3042f0816e03798d604a5bf62eda5b6 Mon Sep 17 00:00:00 2001 From: Darks Date: Fri, 5 Mar 2021 23:44:02 +0100 Subject: [PATCH 2/3] login_as: add function to login as arbitrary account --- app/data/groups.yaml | 5 +- app/forms/login_as.py | 15 +++++ app/processors/utilities.py | 2 + app/routes/__init__.py | 2 +- app/routes/admin/login_as.py | 84 ++++++++++++++++++++++++++ app/templates/admin/index.html | 1 + app/templates/admin/login_as.html | 21 +++++++ app/templates/base/navbar/account.html | 8 +++ app/utils/login_as.py | 20 ++++++ 9 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 app/forms/login_as.py create mode 100644 app/routes/admin/login_as.py create mode 100644 app/templates/admin/login_as.html create mode 100644 app/utils/login_as.py diff --git a/app/data/groups.yaml b/app/data/groups.yaml index 03ffd21..24ead16 100644 --- a/app/data/groups.yaml +++ b/app/data/groups.yaml @@ -33,6 +33,7 @@ # Miscellaneous: # misc.unlimited-pms # misc.dev-infos +# misc.arbitrary-login # misc.community-login # misc.admin-panel # misc.no-upload-limits @@ -60,8 +61,8 @@ delete.posts delete.tests delete.accounts delete.shared-files move.posts shoutbox.kick shoutbox.ban - misc.unlimited-pms misc.dev-infos misc.community-login misc.admin-panel - misc.no-upload-limits + misc.unlimited-pms misc.dev-infos misc.admin-panel + misc.no-upload-limits misc.arbitrary-login misc.community-login - name: Modérateur css: "color: green;" diff --git a/app/forms/login_as.py b/app/forms/login_as.py new file mode 100644 index 0000000..d3235f0 --- /dev/null +++ b/app/forms/login_as.py @@ -0,0 +1,15 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, SubmitField +from wtforms.validators import InputRequired + + +class LoginAsForm(FlaskForm): + username = StringField( + 'Identifiant', + validators=[ + InputRequired(), + ], + ) + submit = SubmitField( + 'Vandaliser', + ) diff --git a/app/processors/utilities.py b/app/processors/utilities.py index 7200fb8..0b8edf2 100644 --- a/app/processors/utilities.py +++ b/app/processors/utilities.py @@ -2,6 +2,7 @@ from app import app from flask import url_for from config import V5Config from slugify import slugify +from app.utils.login_as import is_vandal @app.context_processor def utilities_processor(): @@ -12,4 +13,5 @@ def utilities_processor(): _url_for=lambda route, args, **other: url_for(route, **args, **other), V5Config=V5Config, slugify=slugify, + is_vandal=is_vandal ) diff --git a/app/routes/__init__.py b/app/routes/__init__.py index 28cdc9c..b39260d 100644 --- a/app/routes/__init__.py +++ b/app/routes/__init__.py @@ -3,7 +3,7 @@ from app.routes import index, search, users, tools, development from app.routes.account import login, account, notification, polls from app.routes.admin import index, groups, account, trophies, forums, \ - attachments, config, members, polls + attachments, config, members, polls, login_as from app.routes.forum import index, topic from app.routes.polls import vote, delete from app.routes.posts import edit diff --git a/app/routes/admin/login_as.py b/app/routes/admin/login_as.py new file mode 100644 index 0000000..f1d7029 --- /dev/null +++ b/app/routes/admin/login_as.py @@ -0,0 +1,84 @@ +from flask import request, flash, make_response, redirect, url_for, abort +from flask_login import current_user, login_user, logout_user, login_required +from itsdangerous import Serializer +from itsdangerous.exc import BadSignature +from app import app +from app.utils.render import render +from app.utils.login_as import is_vandal +from app.models.user import Member +from app.forms.login_as import LoginAsForm + + +@app.route("/admin/vandalisme", methods=['GET', 'POST']) +@login_required +def adm_login_as(): + """ Show a basic form and login as arbitrary user when asked """ + + # Basic permission + if (not current_user.priv("misc.arbitrary-login") and + not current_user.priv("misc.community-login")): + abort(403) + if is_vandal(): + flash("Vous êtes déjà authentifié", "error") + return redirect(url_for('index')) + + # Handle form + form = LoginAsForm() + if form.validate_on_submit(): + user = Member.query.filter_by(name=form.username.data).first() + if user is None: + flash("Utilisateur invalide", "error") + return render('admin/login_as.html', form=form) + + # Apply for community login + is_community = True # TODO: check if user is community + if not is_community and not user.priv("misc.arbitrary-login"): + abort(403) + + # Create a safe token to flee when needed + s = Serializer(app.config["SECRET_KEY"]) + vandal_token = s.dumps(current_user.id) + + # Login and display some messages + login_user(user) + if user.name == "GLaDOS": + flash("Vous espérez quoi exactement ? Survivre ? " + "Dans ce cas, évitez de me faire du mal.") + else: + flash(f"Connecté en tant que {user.name}") + + # Return the response + resp = make_response(redirect(url_for('index'))) + resp.set_cookie('vandale', vandal_token) + return resp + + # Else return form + return render('admin/login_as.html', form=form) + +@app.route("/admin/vandalisme/fuir") +@login_required +def adm_logout_as(): + """ Log out as a vandalized user, login back as admin """ + s = Serializer(app.config["SECRET_KEY"]) + + vandal_token = request.cookies.get('vandale') + if vandal_token is None: + abort(403) + + try: + id = s.loads(vandal_token) + except BadSignature: + flash("Vous avez vraiment agit de manière stupide.", "error") + abort(403) + + user = Member.query.get(id) + logout_user() + login_user(user) + + if request.referrer: + resp = make_response(redirect(request.referrer)) + else: + resp = make_response(redirect(url_for('index'))) + + resp.set_cookie('vandale', '', expires=0) + return resp diff --git a/app/templates/admin/index.html b/app/templates/admin/index.html index d39d7bd..6cc7a28 100644 --- a/app/templates/admin/index.html +++ b/app/templates/admin/index.html @@ -15,6 +15,7 @@
  • Sondages
  • Pièces-jointes
  • Configuration du site
  • +
  • Vandalisme
  • {% endblock %} diff --git a/app/templates/admin/login_as.html b/app/templates/admin/login_as.html new file mode 100644 index 0000000..44881c9 --- /dev/null +++ b/app/templates/admin/login_as.html @@ -0,0 +1,21 @@ +{% extends "base/base.html" %} + +{% block title %} +

    Vandaliser un compte

    +{% endblock %} + +{% block content %} +
    +
    + {{ form.hidden_tag() }} +

    + {{ form.username.label }}
    + {{ form.username(size=32) }}
    + {% for error in form.username.errors %} + [{{ error }}] + {% endfor %} +

    +

    {{ form.submit(class_="bg-ok") }}

    +
    +
    +{% endblock %} diff --git a/app/templates/base/navbar/account.html b/app/templates/base/navbar/account.html index 6d5937b..f34ac61 100644 --- a/app/templates/base/navbar/account.html +++ b/app/templates/base/navbar/account.html @@ -41,11 +41,19 @@ Paramètres + {% if is_vandal() %} + + + + Fuir ce compte + + {% else %} Déconnexion + {% endif %} {% else %}
    diff --git a/app/utils/login_as.py b/app/utils/login_as.py new file mode 100644 index 0000000..5311fcd --- /dev/null +++ b/app/utils/login_as.py @@ -0,0 +1,20 @@ +from flask import request +from itsdangerous import Serializer +from itsdangerous.exc import BadSignature +from app import app + + +def is_vandal(): + """ Return True is the current user looks like a vandal """ + s = Serializer(app.config["SECRET_KEY"]) + + vandal_token = request.cookies.get('vandale') + if vandal_token is None: + return False + + try: + s.loads(vandal_token) + except BadSignature: + return False + + return True From 8bdf3909ea53ca61237516508798a36712aa2803 Mon Sep 17 00:00:00 2001 From: Darks Date: Sat, 6 Mar 2021 11:36:35 +0100 Subject: [PATCH 3/3] login_as: fixed some issues See https://gitea.planet-casio.com/devs/PCv5/issues/90#issuecomment-1131 --- app/data/groups.yaml | 7 +++---- app/routes/admin/login_as.py | 12 ++++++++---- app/templates/admin/login_as.html | 2 +- app/utils/login_as.py | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/data/groups.yaml b/app/data/groups.yaml index 24ead16..6f5d93d 100644 --- a/app/data/groups.yaml +++ b/app/data/groups.yaml @@ -48,7 +48,6 @@ # move.posts # shoutbox.* # misc.unlimited-pms -# misc.community-login - name: Administrateur @@ -62,7 +61,7 @@ move.posts shoutbox.kick shoutbox.ban misc.unlimited-pms misc.dev-infos misc.admin-panel - misc.no-upload-limits misc.arbitrary-login misc.community-login + misc.no-upload-limits misc.arbitrary-login - name: Modérateur css: "color: green;" @@ -89,7 +88,7 @@ privs: forum.access.admin forum.post-news publish.schedule-posts publish.pin-posts publish.shared-files delete.shared-files - misc.no-upload-limits + misc.no-upload-limits misc.community-login - name: Responsable communauté css: "color: DarkOrange;" @@ -97,7 +96,7 @@ l'évolution du monde autour de nous !" privs: forum.access.admin forum.post-news publish.schedule-posts publish.pin-posts publish.shared-files - delete.shared-files + delete.shared-files misc.community-login - name: Partenaire css: "color: purple;" diff --git a/app/routes/admin/login_as.py b/app/routes/admin/login_as.py index f1d7029..208775a 100644 --- a/app/routes/admin/login_as.py +++ b/app/routes/admin/login_as.py @@ -5,7 +5,9 @@ from itsdangerous.exc import BadSignature from app import app from app.utils.render import render from app.utils.login_as import is_vandal +from app.utils.unicode_names import normalize from app.models.user import Member +from app.models.priv import Group from app.forms.login_as import LoginAsForm @@ -25,14 +27,16 @@ def adm_login_as(): # Handle form form = LoginAsForm() if form.validate_on_submit(): - user = Member.query.filter_by(name=form.username.data).first() + norm = normalize(form.username.data) + user = Member.query.filter_by(norm=norm).one() if user is None: flash("Utilisateur invalide", "error") return render('admin/login_as.html', form=form) # Apply for community login - is_community = True # TODO: check if user is community - if not is_community and not user.priv("misc.arbitrary-login"): + g = Group.query.filter_by(name="Compte communautaire").one() + is_community = g in user.groups + if not is_community and not current_user.priv("misc.arbitrary-login"): abort(403) # Create a safe token to flee when needed @@ -68,7 +72,7 @@ def adm_logout_as(): try: id = s.loads(vandal_token) except BadSignature: - flash("Vous avez vraiment agit de manière stupide.", "error") + flash("Vous avez vraiment agi de manière stupide.", "error") abort(403) user = Member.query.get(id) diff --git a/app/templates/admin/login_as.html b/app/templates/admin/login_as.html index 44881c9..0576763 100644 --- a/app/templates/admin/login_as.html +++ b/app/templates/admin/login_as.html @@ -5,7 +5,7 @@ {% endblock %} {% block content %} -
    +
    {{ form.hidden_tag() }}

    diff --git a/app/utils/login_as.py b/app/utils/login_as.py index 5311fcd..10336ec 100644 --- a/app/utils/login_as.py +++ b/app/utils/login_as.py @@ -5,7 +5,7 @@ from app import app def is_vandal(): - """ Return True is the current user looks like a vandal """ + """ Return True if the current user looks like a vandal """ s = Serializer(app.config["SECRET_KEY"]) vandal_token = request.cookies.get('vandale')