Commit 8cff9ab1 authored by Michal Čihař's avatar Michal Čihař

Captcha protection for registration.

parent 4d2682c5
......@@ -23,6 +23,7 @@ from django.utils.translation import ugettext_lazy as _, get_language
from django.contrib.auth.forms import AuthenticationForm
from accounts.models import Profile, VerifiedEmail
from accounts.captcha import MathCaptcha
from lang.models import Language
from trans.models import Project
from django.contrib.auth.models import User
......@@ -321,6 +322,46 @@ class RegistrationForm(EmailForm):
return ''
class CaptchaRegistrationForm(RegistrationForm):
'''
Registration form with captcha protection.
'''
captcha = forms.IntegerField(required=True)
captcha_id = forms.CharField(widget=forms.HiddenInput)
def __init__(self, data=None, *args, **kwargs):
super(CaptchaRegistrationForm, self).__init__(
data,
*args,
**kwargs
)
# Load data
self.tampering = False
if data is None or 'captcha_id' not in data:
self.captcha = MathCaptcha()
else:
try:
self.captcha = MathCaptcha.from_hash(data['captcha_id'])
except ValueError:
self.captcha = MathCaptcha()
self.tampering = True
# Set correct label
self.fields['captcha'].label = _('What is %s') % self.captcha.question
self.fields['captcha_id'].initial = self.captcha.hashed
def clean_captcha(self):
'''
Validation for captcha.
'''
if (self.tampering
or not self.captcha.validate(self.cleaned_data['captcha'])):
raise forms.ValidationError(
_('Please check your math and try again.')
)
class PasswordForm(forms.Form):
'''
Form for setting password.
......
......@@ -52,6 +52,8 @@ REGISTRATION_DATA = {
'email': 'noreply@weblate.org',
'first_name': 'First',
'last_name': 'Last',
'captcha_id': '00',
'captcha': '9999'
}
......@@ -77,7 +79,20 @@ class RegistrationTest(TestCase):
reverse('password')
)
def test_register_captcha(self):
response = self.client.post(
reverse('register'),
REGISTRATION_DATA
)
self.assertContains(
response,
'Please check your math and try again.'
)
def test_register(self):
# Disable captcha
appsettings.REGISTRATION_CAPTCHA = False
response = self.client.post(
reverse('register'),
REGISTRATION_DATA
......@@ -109,6 +124,9 @@ class RegistrationTest(TestCase):
self.assertEqual(user.first_name, 'First')
self.assertEqual(user.last_name, 'Last')
# Restore settings
appsettings.REGISTRATION_CAPTCHA = True
def test_reset(self):
'''
Test for password reset.
......
......@@ -33,7 +33,7 @@ from urllib import urlencode
from accounts.forms import (
RegistrationForm, PasswordForm, PasswordChangeForm, EmailForm, ResetForm,
LoginForm, HostingForm
LoginForm, HostingForm, CaptchaRegistrationForm
)
from social.backends.utils import load_backends
from social.apps.django_app.utils import BACKENDS
......@@ -338,12 +338,17 @@ def register(request):
'''
Registration form.
'''
if appsettings.REGISTRATION_CAPTCHA:
form_class = CaptchaRegistrationForm
else:
form_class = RegistrationForm
if request.method == 'POST':
form = RegistrationForm(request.POST)
form = form_class(request.POST)
if form.is_valid() and appsettings.REGISTRATION_OPEN:
return complete(request, 'email')
else:
form = RegistrationForm()
form = form_class()
return render_to_response(
'accounts/register.html',
......
......@@ -320,6 +320,15 @@ For example you can allow script which does some cleanup:
.. seealso:: :ref:`processing`
.. setting:: REGISTRATION_CAPTCHA
REGISTRATION_CAPTCHA
--------------------
A boolean (either ``True`` or ``False``) indicating whether registration of new
accounts is protected by captcha. This setting is optional, and a default of
True will be assumed if it is not supplied.
.. setting:: REGISTRATION_OPEN
REGISTRATION_OPEN
......
......@@ -16,6 +16,7 @@ Released on ? 2013.
* Improved source strings review.
* Searching across all units.
* Better tracking of source strings.
* Captcha protection for registration.
weblate 1.7
-----------
......
......@@ -149,3 +149,6 @@ ANONYMOUS_USER_NAME = get('ANONYMOUS_USER_NAME', 'anonymous')
# Enable registrations
REGISTRATION_OPEN = get('REGISTRATION_OPEN', True)
# Captcha for registrations
REGISTRATION_CAPTCHA = get('REGISTRATION_CAPTCHA', True)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment