You've already forked snikket-web-portal
Convert login page to proper form
- free CSRF protection - free "empty field" early out - easier passing on of errors to the view
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import base64
|
||||
import binascii
|
||||
import itertools
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
@@ -9,10 +10,13 @@ from quart import (
|
||||
Quart, session, request, render_template, redirect, url_for, Response,
|
||||
current_app,
|
||||
)
|
||||
import quart.exceptions
|
||||
|
||||
from flask_babel import Babel
|
||||
from flask_wtf import FlaskForm
|
||||
import wtforms
|
||||
from flask_babel import Babel, _, lazy_gettext as _l
|
||||
|
||||
from . import colour
|
||||
from . import colour, xmpputil
|
||||
from .prosodyclient import client
|
||||
|
||||
from ._version import version, version_info
|
||||
@@ -27,6 +31,18 @@ client.default_login_redirect = "login"
|
||||
babel = Babel(app)
|
||||
|
||||
|
||||
class LoginForm(FlaskForm):
|
||||
address = wtforms.TextField(
|
||||
_l("Address"),
|
||||
validators=[wtforms.validators.InputRequired()],
|
||||
)
|
||||
|
||||
password = wtforms.PasswordField(
|
||||
_l("Password"),
|
||||
validators=[wtforms.validators.InputRequired()],
|
||||
)
|
||||
|
||||
|
||||
@babel.localeselector
|
||||
def selected_locale():
|
||||
return request.accept_languages.best_match(
|
||||
@@ -39,14 +55,24 @@ async def login():
|
||||
if client.has_session and (await client.test_session()):
|
||||
return redirect(url_for('user.index'))
|
||||
|
||||
if request.method == "POST":
|
||||
form = await request.form
|
||||
jid = form["address"]
|
||||
password = form["password"]
|
||||
await client.login(jid, password)
|
||||
return redirect(url_for('user.index'))
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit():
|
||||
jid = form.address.data
|
||||
localpart, domain, resource = xmpputil.split_jid(jid)
|
||||
if not localpart:
|
||||
localpart, domain = domain, current_app.config["SNIKKET_DOMAIN"]
|
||||
jid = "{}@{}".format(localpart, domain)
|
||||
password = form.password.data
|
||||
try:
|
||||
await client.login(jid, password)
|
||||
except quart.exceptions.Unauthorized:
|
||||
form.errors.setdefault("", []).append(
|
||||
_("Invalid user name or password.")
|
||||
)
|
||||
else:
|
||||
return redirect(url_for('user.index'))
|
||||
|
||||
return await render_template("login.html")
|
||||
return await render_template("login.html", form=form)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
@@ -132,5 +158,12 @@ def proc():
|
||||
app.template_filter("repr")(repr)
|
||||
|
||||
|
||||
@app.template_filter("flatten")
|
||||
def flatten(a, levels=1):
|
||||
for i in range(levels):
|
||||
a = itertools.chain(*a)
|
||||
return a
|
||||
|
||||
|
||||
from .user import user_bp # NOQA
|
||||
app.register_blueprint(user_bp)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
{% from "library.j2" import box %}
|
||||
{% set body_id = "login" %}
|
||||
{% block head_lead %}
|
||||
<title>{{ _("Snikket Login") }}</title>
|
||||
@@ -12,13 +13,19 @@
|
||||
<h1 class="form-title">{{ config["SNIKKET_DOMAIN"] }}</h1>
|
||||
<p class="form-desc">{{ _("Enter your Snikket address and password to manage your account.") }}</p>
|
||||
<form method="POST" action="{{ url_for('login') }}" name="login">
|
||||
{{ form.csrf_token }}
|
||||
{% if form.errors %}
|
||||
{% call box("alert", _("Login failed")) %}
|
||||
<p>{{ form.errors.values() | flatten | join(", ")}}</p>
|
||||
{% endcall %}
|
||||
{% endif %}
|
||||
<div class="f-ebox">
|
||||
<label for="address" class="a11y-only">{{ _("Address") }}:</label>
|
||||
<input type="text" name="address" id="address" required="required" placeholder="{{ _("Address") }}">
|
||||
{{ form.address.label(class="a11y-only") }}
|
||||
{{ form.address(placeholder=form.address.label.text) }}
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
<label for="password" class="a11y-only">{{ _("Password") }}:</label>
|
||||
<input type="password" name="password" id="password" required="required" placeholder="{{ _("Password") }}">
|
||||
{{ form.password.label(class="a11y-only") }}
|
||||
{{ form.password(placeholder=form.password.label.text) }}
|
||||
</div>
|
||||
<div class="f-bbox">
|
||||
<button type="submit" class="primary">{{ _("Log in") }}</button>
|
||||
|
||||
Reference in New Issue
Block a user