login_as: add function to login as arbitrary account

This commit is contained in:
Darks 2021-03-05 23:44:02 +01:00
parent d783feb7d0
commit 87ef91b9e3
Signed by untrusted user: Darks
GPG Key ID: 7515644268BE1433
9 changed files with 155 additions and 3 deletions

View File

@ -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;"

15
app/forms/login_as.py Normal file
View File

@ -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',
)

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -15,6 +15,7 @@
<li><a href="{{ url_for('adm_polls') }}">Sondages</a></li>
<li><a href="{{ url_for('adm_attachments') }}">Pièces-jointes</a></li>
<li><a href="{{ url_for('adm_config') }}">Configuration du site</a></li>
<li><a href="{{ url_for('adm_login_as') }}">Vandalisme</a></li>
</ul>
</section>
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends "base/base.html" %}
{% block title %}
<h1>Vandaliser un compte</h1>
{% endblock %}
{% block content %}
<section class="form" style="width:40%;">
<form action="" method="post">
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }}<br>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>{{ form.submit(class_="bg-ok") }}</p>
</form>
</section>
{% endblock %}

View File

@ -41,11 +41,19 @@
<path fill="#ffffff" d="M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z"></path>
</svg>Paramètres
</a>
{% if is_vandal() %}
<a href="{{ url_for('adm_logout_as', csrf_token=csrf_token()) }}">
<svg viewBox="0 0 24 24">
<path fill="#ffffff" d="M17,17.25V14H10V10H17V6.75L22.25,12L17,17.25M13,2A2,2 0 0,1 15,4V8H13V4H4V20H13V16H15V20A2,2 0 0,1 13,22H4A2,2 0 0,1 2,20V4A2,2 0 0,1 4,2H13Z"></path>
</svg>Fuir ce compte
</a>
{% else %}
<a href="{{ url_for('logout', csrf_token=csrf_token()) }}">
<svg viewBox="0 0 24 24">
<path fill="#ffffff" d="M17,17.25V14H10V10H17V6.75L22.25,12L17,17.25M13,2A2,2 0 0,1 15,4V8H13V4H4V20H13V16H15V20A2,2 0 0,1 13,22H4A2,2 0 0,1 2,20V4A2,2 0 0,1 4,2H13Z"></path>
</svg>Déconnexion
</a>
{% endif %}
</div>
{% else %}
<div>

20
app/utils/login_as.py Normal file
View File

@ -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