From 442f9206812df95023c48a0e18c2d840a35a2f8d Mon Sep 17 00:00:00 2001 From: AlxCzl Date: Mon, 29 Nov 2021 01:18:29 +0100 Subject: [PATCH] feat(reset): added a better validator to the form --- app/reset.py | 33 ++++++++++++++++----- app/ui/static/css/main.css | 34 ++++++++++++++------- app/ui/static/js/validate.js | 57 ++++++++++++++++++++++++++---------- app/ui/templates/reset.html | 22 +++++++++----- 4 files changed, 106 insertions(+), 40 deletions(-) diff --git a/app/reset.py b/app/reset.py index 204c2e1..482ab04 100644 --- a/app/reset.py +++ b/app/reset.py @@ -7,29 +7,48 @@ from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, BooleanField, \ SubmitField from wtforms.validators import ValidationError, DataRequired, \ - Email, EqualTo, Length + Email, EqualTo, Length, Regexp from werkzeug.security import check_password_hash, generate_password_hash - +import re bp = Blueprint('reset', __name__, url_prefix='/reset') class ResetPasswordForm(FlaskForm): - username = StringField(label=('Username'), + # Minimal password length + minlength = 9 + + # Form + username = StringField(label=('Login'), validators=[DataRequired(), Length(max=64)]) currentpassword = PasswordField(label=('Current password'), validators=[DataRequired()]) newpassword = PasswordField(label=('New password'), validators=[DataRequired(), - Length(min=8, message='Password should be at least %(min)d characters long')], - render_kw={"onkeyup": "validate_form()"}) + Length(min=minlength, message='Password should be at least %(min)d characters long'), + Regexp("^(?=.*[a-z])", message="Password must have a lowercase character"), + Regexp("^(?=.*[A-Z])", message="Password must have an uppercase character"), + Regexp("^(?=.*\\d)", message="Password must contain a number"), + #Regexp( + # "(?=.*[@$!%*#?&])", message="Password must contain a special character" + #),], + ], + render_kw={"onkeyup": f"validate_form({minlength})"}) confirm_password = PasswordField( label=('Confirm Password'), validators=[DataRequired(message='* Required'), EqualTo('newpassword', message='Both password fields must be equal!')], - render_kw={"onkeyup": "validate_confirm()"}) + render_kw={"onkeyup": f"validate_confirm({minlength})"}) - submit = SubmitField(label=('Change my password'), render_kw={"onclick": "validate_form()"}) + submit = SubmitField(label=('Change my password'), render_kw={"onclick": f"validate_form({minlength})"}) + + # Validators + def validate_username(self, username): + excluded_chars = " *?!'^+%&/()=}][{$#;\\\"" + for char in self.username.data: + if char in excluded_chars: + raise ValidationError( + f"Character {char} is not allowed in a login.") @bp.route('/', methods=('GET', 'POST')) def reset(): diff --git a/app/ui/static/css/main.css b/app/ui/static/css/main.css index 0e5b919..fb91c40 100644 --- a/app/ui/static/css/main.css +++ b/app/ui/static/css/main.css @@ -51,17 +51,36 @@ a:hover>span { font-size: 32px; } +#confirm-msg, +#password-msg { + color: #d4d4d4; + font-size: small; + transition: color 225ms cubic-bezier(0.25, 0.46, 0.45, 0.94); +} + +#password-msg li { + list-style: none; + content: "" +} + +#password-msg li::before { + content: "☑ "; +} + .errorinput { border-color: #f44246 !important; } -#confirm-msg, -#password-msg { - color: #f44246; - opacity: 0; - transition: opacity 225ms cubic-bezier(0.25, 0.46, 0.45, 0.94); +.errormsg { + color: #f44246 !important; + } +li.errormsg::before { + content: "☒ " !important; +} + + .errorinput:focus { box-shadow: 0 0 0 .10rem rgba(244, 66, 70, 0.50) !important; -webkit-box-shadow: 0 0 0 .10rem rgba(244, 66, 70, 0.50) !important; @@ -77,8 +96,3 @@ a:hover>span { background: #4e4e4e; border-radius: .50rem; } - -.fade { - opacity: 1 !important; - transition: opacity 300ms cubic-bezier(0.55, 0.085, 0.68, 0.53); -} \ No newline at end of file diff --git a/app/ui/static/js/validate.js b/app/ui/static/js/validate.js index 3f90df1..5ab48b5 100644 --- a/app/ui/static/js/validate.js +++ b/app/ui/static/js/validate.js @@ -1,5 +1,5 @@ -function validate_form() { - var pass = validate_password(); +function validate_form(minlength) { + var pass = validate_password(minlength); return validate_confirm() && pass; } @@ -10,28 +10,55 @@ function validate_confirm() { if (password.value != confirm.value) { confirm.classList.add("errorinput"); - document.getElementById("confirm-msg").classList.add("fade"); + document.getElementById("confirm-msg").classList.add("errormsg"); return false; } confirm.classList.remove("errorinput"); - document.getElementById("confirm-msg").classList.remove("fade"); + document.getElementById("confirm-msg").classList.remove("errormsg"); return true; } -function validate_password() { +function validate_password(minlength) { + // Did the checks pass ? + var status = true; + // Target element var password = document.getElementById("newpassword"); - var reg = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}/; - - if (reg.test(password.value) != true) { - password.classList.add("errorinput"); - document.getElementById("password-msg").classList.add("fade"); - return false; + // Check the length + if (password.value.length < minlength) + { + status = false; + document.getElementById("minlen").classList.add("errormsg"); } + else + document.getElementById("minlen").classList.remove("errormsg"); + // Look for a digit + if (/.*\d/.test(password.value) != true) { + status = false; + document.getElementById("digit").classList.add("errormsg"); + } + else + document.getElementById("digit").classList.remove("errormsg"); + // Look for a lowercase char + if (/.*[a-z]/.test(password.value) != true) { + status = false; + document.getElementById("lower").classList.add("errormsg"); + } + else + document.getElementById("lower").classList.remove("errormsg"); + // Look for an uppercase char + if (/.*[A-Z]/.test(password.value) != true) { + status = false; + document.getElementById("upper").classList.add("errormsg"); + } + else + document.getElementById("upper").classList.remove("errormsg"); + // Change the color of the inputbox + if (status == false) + password.classList.add("errorinput"); + else + password.classList.remove("errorinput"); - password.classList.remove("errorinput"); - document.getElementById("password-msg").classList.remove("fade"); - - return true; + return status; } \ No newline at end of file diff --git a/app/ui/templates/reset.html b/app/ui/templates/reset.html index dcd0031..a57e89a 100644 --- a/app/ui/templates/reset.html +++ b/app/ui/templates/reset.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block main_block %} -
+
{% for field, errors in form.errors.items() %} {{ ', '.join(errors) }} {% endfor %} @@ -17,20 +17,26 @@
{{ form.newpassword.label }} - - The new password should contain at least : 8 characters, one numeric digit, one lowercase and one uppercase characters. - +
+ The new password should contain at least : +
    +
  • {{ form.minlength }} characters
  • +
  • 1 numeric digit [0-9]
  • +
  • 1 lowercase character [a-z]
  • +
  • 1 uppercase character [A-Z]
  • +
+
{{ form.newpassword(class="form-control") }}
{{ form.confirm_password.label }} - - Passwords should match - +
+ Passwords must match +
{{ form.confirm_password(class="form-control") }}

-
+
{{ form.submit(class="btn btn-primary")}}