Changed the new account creation to require a proper name at the same time as the account password is set, before actually creating the account. Also tweaked the password strength and confirmation code.

- Legacy-Id: 12892
This commit is contained in:
Henrik Levkowetz 2017-02-20 16:50:39 +00:00
parent 8a8cf5b811
commit 858d855eff
8 changed files with 51 additions and 36 deletions

View file

@ -15,7 +15,7 @@ import debug # pyflakes:ignore
from ietf.person.models import Person, Email
from ietf.mailinglists.models import Whitelisted
from ietf.utils.text import isascii
class RegistrationForm(forms.Form):
email = forms.EmailField(label="Your email (lowercase)")
@ -32,9 +32,12 @@ class RegistrationForm(forms.Form):
class PasswordForm(forms.Form):
password = forms.CharField(widget=PasswordStrengthInput)
password_confirmation = forms.CharField(widget=PasswordConfirmationInput,
help_text="Enter the same password as above, for verification.")
password = forms.CharField(widget=PasswordStrengthInput(attrs={'class':'password_strength'}))
password_confirmation = forms.CharField(widget=PasswordConfirmationInput(
confirm_with='password',
attrs={'class':'password_confirmation'}),
help_text="Enter the same password as above, for verification.",)
def clean_password_confirmation(self):
password = self.cleaned_data.get("password", "")
@ -43,12 +46,6 @@ class PasswordForm(forms.Form):
raise forms.ValidationError("The two password fields didn't match.")
return password_confirmation
class PersonPasswordForm(forms.ModelForm, PasswordForm):
class Meta:
model = Person
fields = ['name', 'ascii']
def ascii_cleaner(supposedly_ascii):
outside_printable_ascii_pattern = r'[^\x20-\x7F]'
if re.search(outside_printable_ascii_pattern, supposedly_ascii):
@ -64,6 +61,26 @@ def prevent_system_name(name):
if "(system)" in name_without_spaces.lower():
raise forms.ValidationError("Please pick another name - this name is reserved.")
class PersonPasswordForm(forms.ModelForm, PasswordForm):
class Meta:
model = Person
fields = ['name', 'ascii']
def clean_name(self):
name = self.cleaned_data.get('name', '')
prevent_at_symbol(name)
prevent_system_name(name)
return name
def clean_ascii(self):
ascii = self.cleaned_data.get('ascii', '')
if not isascii(ascii):
raise forms.ValidationError("Ascii name contains non-ASCII characters.")
return ascii
def get_person_form(*args, **kwargs):
exclude_list = ['time', 'user', 'photo_thumb', 'photo', ]
@ -179,7 +196,9 @@ class ChangePasswordForm(forms.Form):
current_password = forms.CharField(widget=forms.PasswordInput)
new_password = forms.CharField(widget=PasswordStrengthInput(attrs={'class':'password_strength'}))
new_password_confirmation = forms.CharField(widget=PasswordConfirmationInput)
new_password_confirmation = forms.CharField(widget=PasswordConfirmationInput(
confirm_with='new_password',
attrs={'class':'password_confirmation'}))
def __init__(self, user, data=None):
self.user = user

View file

@ -127,7 +127,7 @@ class IetfAuthTests(TestCase):
empty_outbox()
r = self.client.post(url, { 'email': email })
self.assertEqual(r.status_code, 200)
self.assertIn("Account created", unicontent(r))
self.assertIn("Account request received", unicontent(r))
self.assertEqual(len(outbox), 1)
# go to confirm page
@ -141,7 +141,7 @@ class IetfAuthTests(TestCase):
self.assertEqual(User.objects.filter(username=email).count(), 0)
# confirm
r = self.client.post(confirm_url, { 'password': 'secret', 'password_confirmation': 'secret' })
r = self.client.post(confirm_url, { 'name': 'User Name', 'ascii': 'User Name', 'password': 'secret', 'password_confirmation': 'secret' })
self.assertEqual(r.status_code, 200)
self.assertEqual(User.objects.filter(username=email).count(), 1)
self.assertEqual(Person.objects.filter(user__username=email).count(), 1)

View file

@ -54,7 +54,7 @@ import debug # pyflakes:ignore
from ietf.group.models import Role, Group
from ietf.ietfauth.forms import ( RegistrationForm, PasswordForm, ResetPasswordForm, TestEmailForm,
WhitelistForm, ChangePasswordForm, get_person_form, RoleEmailForm,
NewEmailForm, ChangeUsernameForm )
NewEmailForm, ChangeUsernameForm, PersonPasswordForm)
from ietf.ietfauth.htpasswd import update_htpasswd_file
from ietf.ietfauth.utils import role_required
from ietf.mailinglists.models import Subscribed, Whitelisted
@ -138,7 +138,7 @@ def confirm_account(request, auth):
success = False
if request.method == 'POST':
form = PasswordForm(request.POST)
form = PersonPasswordForm(request.POST)
if form.is_valid():
password = form.cleaned_data["password"]
@ -157,9 +157,11 @@ def confirm_account(request, auth):
person = email_obj.person
if not person:
name = form.cleaned_data["name"]
ascii = form.cleaned_data["ascii"]
person = Person.objects.create(user=user,
name=email,
ascii=email)
name=name,
ascii=ascii)
if not email_obj:
email_obj = Email.objects.create(address=email, person=person)
else:
@ -172,7 +174,7 @@ def confirm_account(request, auth):
success = True
else:
form = PasswordForm()
form = PersonPasswordForm()
return render(request, 'registration/confirm_account.html', {
'form': form,

View file

@ -11,7 +11,7 @@ import debug # pyflakes:ignore
from ietf.person.factories import EmailFactory,PersonFactory
from ietf.person.models import Person
from ietf.utils.test_data import make_test_data
from ietf.utils.test_utils import TestCase
from ietf.utils.test_utils import TestCase, unicontent
from ietf.utils.mail import outbox, empty_outbox
@ -42,7 +42,7 @@ class PersonTests(TestCase):
url = urlreverse("ietf.person.views.profile", kwargs={ "email_or_name": person.plain_name()})
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertIn(person.photo_name(), r.content.decode(r.charset))
self.assertIn(person.photo_name(), unicontent(r))
q = PyQuery(r.content)
self.assertIn("Photo of %s"%person, q("div.bio-text img.bio-photo").attr("alt"))

View file

@ -24,8 +24,8 @@
$('.' + self.config.passwordClass).on('keyup', function() {
var password_strength_bar = $(this).parent().find('.password_strength_bar');
var password_strength_info = $(this).parent().find('.password_strength_info');
var password_strength_offline_info = $(this).parent().parent().parent().find('.password_strength_offline_info');
var password_strength_info = $(this).parent().find('.password_strength_info');
var password_strength_offline_info = $(this).parent().parent().parent().find('.password_strength_offline_info');
if( $(this).val() ) {
var result = zxcvbn( $(this).val() );
@ -39,12 +39,12 @@
}
password_strength_bar.width( ((result.score+1)/5)*100 + '%' ).attr('aria-valuenow', result.score + 1);
// henrik@levkowetz.com -- this is the only changed line:
password_strength_info.find('.password_strength_time').html(result.crack_times_display.online_no_throttling_10_per_second);
password_strength_info.removeClass('hidden');
// henrik@levkowetz.com -- this is the only changed line:
password_strength_info.find('.password_strength_time').html(result.crack_times_display.online_no_throttling_10_per_second);
password_strength_info.removeClass('hidden');
password_strength_offline_info.find('.password_strength_time').html(result.crack_times_display.offline_slow_hashing_1e4_per_second);
password_strength_offline_info.removeClass('hidden');
password_strength_offline_info.find('.password_strength_time').html(result.crack_times_display.offline_slow_hashing_1e4_per_second);
password_strength_offline_info.removeClass('hidden');
} else {
password_strength_bar.removeClass('progress-bar-success').addClass('progress-bar-warning');
password_strength_bar.width( '0%' ).attr('aria-valuenow', 0);

View file

@ -31,7 +31,7 @@
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Set password</button>
<button type="submit" class="btn btn-primary">Set name and password</button>
{% endbuttons %}
</form>
{% endif %}

View file

@ -10,7 +10,7 @@
{% origin %}
{% if to_email %}
<h1>Account created successfully</h1>
<h1>Account request received.</h1>
<p>Your account creation request has been successfully received.</p>

View file

@ -265,13 +265,7 @@ def login_testing_unauthorized(test_case, username, url, password=None):
def unicontent(r):
"Return a HttpResponse object's content as unicode"
content_type = r._headers.get("content-type", "text/html; charset=utf-8")
if 'charset=' in content_type:
mediatype, charset = content_type.split(';')
encoding = charset.split('=')[1].strip()
else:
encoding = 'utf-8'
return r.content.decode(encoding)
return r.content.decode(r.charset)
def reload_db_objects(*objects):
"""Rerequest the given arguments from the database so they're refreshed, to be used like