From c7437336b47f88329613f1a495b4e1228e4bfdf7 Mon Sep 17 00:00:00 2001 From: Kara Engelhardt Date: Fri, 20 Mar 2026 12:54:44 +0100 Subject: [PATCH] Add length help text to customer password forms Also cleans up dead code, as `validate_password` always returns None or raises a ValidationError. --- src/pretix/base/forms/auth.py | 3 +-- src/pretix/presale/forms/customer.py | 33 +++++++++++++++++++--------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/pretix/base/forms/auth.py b/src/pretix/base/forms/auth.py index 79e5a0e7c..a47c231a7 100644 --- a/src/pretix/base/forms/auth.py +++ b/src/pretix/base/forms/auth.py @@ -196,8 +196,7 @@ class RegistrationForm(forms.Form): def clean_password(self): password1 = self.cleaned_data.get('password', '') user = User(email=self.cleaned_data.get('email')) - if validate_password(password1, user=user) is not None: - raise forms.ValidationError(_(password_validators_help_texts()), code='pw_invalid') + validate_password(password1, user=user) return password1 def clean_email(self): diff --git a/src/pretix/presale/forms/customer.py b/src/pretix/presale/forms/customer.py index b8c14ac7c..ef21ab3c7 100644 --- a/src/pretix/presale/forms/customer.py +++ b/src/pretix/presale/forms/customer.py @@ -28,7 +28,7 @@ from django import forms from django.conf import settings from django.contrib.auth.hashers import check_password from django.contrib.auth.password_validation import ( - get_password_validators, password_validators_help_texts, validate_password, + MinimumLengthValidator, get_password_validators, validate_password, ) from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.core import signing @@ -300,13 +300,12 @@ class SetPasswordForm(forms.Form): ) password = forms.CharField( label=_('Password'), - widget=forms.PasswordInput(attrs={'minlength': '8', 'autocomplete': 'new-password'}), + widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}), max_length=4096, - required=True ) password_repeat = forms.CharField( label=_('Repeat password'), - widget=forms.PasswordInput(attrs={'minlength': '8', 'autocomplete': 'new-password'}), + widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}), max_length=4096, ) @@ -316,6 +315,14 @@ class SetPasswordForm(forms.Form): kwargs['initial']['email'] = self.customer.email super().__init__(*args, **kwargs) + pw_min_len_validators = [v for v in get_customer_password_validators() if isinstance(v, MinimumLengthValidator)] + if pw_min_len_validators: + self.fields['password'].widget.attrs['minlength'] = max(v.min_length for v in pw_min_len_validators) + self.fields['password_repeat'].widget.attrs['minlength'] = max(v.min_length for v in pw_min_len_validators) + + if 'password' not in self.data: + self.fields['password'].help_text = ' '.join(v.get_help_text() for v in pw_min_len_validators) + def clean(self): password1 = self.cleaned_data.get('password', '') password2 = self.cleaned_data.get('password_repeat') @@ -329,8 +336,7 @@ class SetPasswordForm(forms.Form): def clean_password(self): password1 = self.cleaned_data.get('password', '') - if validate_password(password1, user=self.customer, password_validators=get_customer_password_validators()) is not None: - raise forms.ValidationError(_(password_validators_help_texts()), code='pw_invalid') + validate_password(password1, user=self.customer, password_validators=get_customer_password_validators()) return password1 @@ -395,13 +401,13 @@ class ChangePasswordForm(forms.Form): ) password = forms.CharField( label=_('New password'), - widget=forms.PasswordInput(attrs={'minlength': '8', 'autocomplete': 'new-password'}), + widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}), max_length=4096, required=True ) password_repeat = forms.CharField( label=_('Repeat password'), - widget=forms.PasswordInput(attrs={'minlength': '8', 'autocomplete': 'new-password'}), + widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}), max_length=4096, ) @@ -411,6 +417,14 @@ class ChangePasswordForm(forms.Form): kwargs['initial']['email'] = self.customer.email super().__init__(*args, **kwargs) + pw_min_len_validators = [v for v in get_customer_password_validators() if isinstance(v, MinimumLengthValidator)] + if pw_min_len_validators: + self.fields['password'].widget.attrs['minlength'] = max(v.min_length for v in pw_min_len_validators) + self.fields['password_repeat'].widget.attrs['minlength'] = max(v.min_length for v in pw_min_len_validators) + + if 'password' not in self.data: + self.fields['password'].help_text = ' '.join(v.get_help_text() for v in pw_min_len_validators) + def clean(self): password1 = self.cleaned_data.get('password', '') password2 = self.cleaned_data.get('password_repeat') @@ -424,8 +438,7 @@ class ChangePasswordForm(forms.Form): def clean_password(self): password1 = self.cleaned_data.get('password', '') - if validate_password(password1, user=self.customer, password_validators=get_customer_password_validators()) is not None: - raise forms.ValidationError(_(password_validators_help_texts()), code='pw_invalid') + validate_password(password1, user=self.customer, password_validators=get_customer_password_validators()) return password1 def clean_password_current(self):