3434: Fix #3425 r=mergify[bot] a=nextgens

## What type of PR?

enhancement

## What does this PR do?

Warn if passwords set from the UI contain leading or trailing whitespaces.

Not sure if it's worth backporting it.

### Related issue(s)
-  close #3425

## Prerequisites
Before we can consider review and merge, please make sure the following list is done and checked.
If an entry in not applicable, you can check it or remove it from the list.

- [ ] In case of feature or enhancement: documentation updated accordingly
- [x] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/workflow.html#changelog) entry file.


Co-authored-by: Florent Daigniere <nextgens@freenetproject.org>
This commit is contained in:
bors-mailu[bot]
2024-09-10 16:42:49 +00:00
committed by GitHub
2 changed files with 10 additions and 4 deletions

View File

@@ -1,4 +1,5 @@
from wtforms import validators, fields, widgets from wtforms import validators, fields, widgets
from wtforms.validators import ValidationError
from wtforms_components import fields as fields_ from wtforms_components import fields as fields_
from flask_babel import lazy_gettext as _ from flask_babel import lazy_gettext as _
@@ -9,6 +10,10 @@ import ipaddress
LOCALPART_REGEX = r'^[a-zA-Z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+/=?^_`{|}~-]+)*$' LOCALPART_REGEX = r'^[a-zA-Z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+/=?^_`{|}~-]+)*$'
def checkStrippable(form, field):
if field.data.startswith(' ') or field.data.endswith(' '):
raise ValidationError(_('Passwords should not start or end with whitespaces'))
class DestinationField(fields.SelectMultipleField): class DestinationField(fields.SelectMultipleField):
""" Allow for multiple emails selection from current user choices and """ Allow for multiple emails selection from current user choices and
additional email addresses. additional email addresses.
@@ -68,7 +73,7 @@ class DomainForm(flask_wtf.FlaskForm):
class DomainSignupForm(flask_wtf.FlaskForm): class DomainSignupForm(flask_wtf.FlaskForm):
name = fields.StringField(_('Domain name'), [validators.DataRequired()]) name = fields.StringField(_('Domain name'), [validators.DataRequired()])
localpart = fields.StringField(_('Initial admin'), [validators.DataRequired()]) localpart = fields.StringField(_('Initial admin'), [validators.DataRequired()])
pw = fields.PasswordField(_('Admin password'), [validators.DataRequired()]) pw = fields.PasswordField(_('Admin password'), [validators.DataRequired(), checkStrippable])
pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')]) pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')])
pwned = fields.HiddenField(label='', default=-1) pwned = fields.HiddenField(label='', default=-1)
captcha = flask_wtf.RecaptchaField() captcha = flask_wtf.RecaptchaField()
@@ -90,7 +95,7 @@ class RelayForm(flask_wtf.FlaskForm):
class UserForm(flask_wtf.FlaskForm): class UserForm(flask_wtf.FlaskForm):
localpart = fields.StringField(_('E-mail'), [validators.DataRequired(), validators.Regexp(LOCALPART_REGEX)]) localpart = fields.StringField(_('E-mail'), [validators.DataRequired(), validators.Regexp(LOCALPART_REGEX)])
pw = fields.PasswordField(_('Password')) pw = fields.PasswordField(_('Password'))
pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')]) pw2 = fields.PasswordField(_('Confirm password'), [checkStrippable, validators.EqualTo('pw')])
pwned = fields.HiddenField(label='', default=-1) pwned = fields.HiddenField(label='', default=-1)
quota_bytes = fields_.IntegerSliderField(_('Quota'), default=10**9) quota_bytes = fields_.IntegerSliderField(_('Quota'), default=10**9)
enable_imap = fields.BooleanField(_('Allow IMAP access'), default=True) enable_imap = fields.BooleanField(_('Allow IMAP access'), default=True)
@@ -105,7 +110,7 @@ class UserForm(flask_wtf.FlaskForm):
class UserSignupForm(flask_wtf.FlaskForm): class UserSignupForm(flask_wtf.FlaskForm):
localpart = fields.StringField(_('Email address'), [validators.DataRequired(), validators.Regexp(LOCALPART_REGEX)]) localpart = fields.StringField(_('Email address'), [validators.DataRequired(), validators.Regexp(LOCALPART_REGEX)])
pw = fields.PasswordField(_('Password'), [validators.DataRequired()]) pw = fields.PasswordField(_('Password'), [validators.DataRequired(), checkStrippable])
pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')]) pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')])
pwned = fields.HiddenField(label='', default=-1) pwned = fields.HiddenField(label='', default=-1)
submit = fields.SubmitField(_('Sign up')) submit = fields.SubmitField(_('Sign up'))
@@ -132,7 +137,7 @@ class UserPasswordForm(flask_wtf.FlaskForm):
class UserPasswordChangeForm(flask_wtf.FlaskForm): class UserPasswordChangeForm(flask_wtf.FlaskForm):
current_pw = fields.PasswordField(_('Current password'), [validators.DataRequired()]) current_pw = fields.PasswordField(_('Current password'), [validators.DataRequired()])
pw = fields.PasswordField(_('Password'), [validators.DataRequired()]) pw = fields.PasswordField(_('Password'), [validators.DataRequired(), checkStrippable])
pw2 = fields.PasswordField(_('Password check'), [validators.DataRequired()]) pw2 = fields.PasswordField(_('Password check'), [validators.DataRequired()])
pwned = fields.HiddenField(label='', default=-1) pwned = fields.HiddenField(label='', default=-1)
submit = fields.SubmitField(_('Update password')) submit = fields.SubmitField(_('Update password'))

View File

@@ -0,0 +1 @@
Warn if passwords set from the UI contain leading or trailing whitespaces (see #3425)