From 32d214d31db1dc330d0f249579ffea961e74277b Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 14 Jan 2021 10:30:46 +0100 Subject: [PATCH] add a honeypot middleware (#50108) Forms must be instrumented by adding a 'robotcheck' checkbox input, then a request.is_robot boolean signals if the request is possibly from a spam robot. --- src/authentic2/middleware.py | 11 +++++++++++ src/authentic2/settings.py | 1 + .../login_password_registration_form.html | 1 + .../registration/registration_complete.html | 6 ++++++ src/authentic2/views.py | 2 ++ tests/test_registration.py | 14 ++++++++++++++ 6 files changed, 35 insertions(+) diff --git a/src/authentic2/middleware.py b/src/authentic2/middleware.py index e5aeb4f0..980398a3 100644 --- a/src/authentic2/middleware.py +++ b/src/authentic2/middleware.py @@ -227,3 +227,14 @@ def null_character_middleware(get_response): return get_response(request) return middleware + + +def honeypot_middleware(get_response): + # The following HTML code must be added to forms for the middleware to work : + # + + def middleware(request): + if 'robotcheck' in request.POST: + request.session['is_robot'] = True + return get_response(request) + return middleware diff --git a/src/authentic2/settings.py b/src/authentic2/settings.py index cce65c88..249c85f4 100644 --- a/src/authentic2/settings.py +++ b/src/authentic2/settings.py @@ -102,6 +102,7 @@ MIDDLEWARE = ( 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'authentic2.middleware.journal_middleware', + 'authentic2.middleware.honeypot_middleware', ) DATABASES['default']['ATOMIC_REQUESTS'] = True diff --git a/src/authentic2/templates/authentic2/login_password_registration_form.html b/src/authentic2/templates/authentic2/login_password_registration_form.html index e7384af5..82194921 100644 --- a/src/authentic2/templates/authentic2/login_password_registration_form.html +++ b/src/authentic2/templates/authentic2/login_password_registration_form.html @@ -4,6 +4,7 @@
{% csrf_token %} {{ form|with_template }} +
{% endblock %} diff --git a/src/authentic2/templates/registration/registration_complete.html b/src/authentic2/templates/registration/registration_complete.html index 7699d0a9..1d2b17c6 100644 --- a/src/authentic2/templates/registration/registration_complete.html +++ b/src/authentic2/templates/registration/registration_complete.html @@ -6,6 +6,11 @@ {% endblock %} {% block content %} + {% if request.session.is_robot %} + {% block robot-detected %} +

{% blocktrans %}Your registration request is refused. Indeed your browser checked an hidden anti-robot checkbox on the registration form. A browser extension may produce this behaviour, in this case disable the extension and try agin.{% endblocktrans %}

+ {% endblock %} + {% else %} {% block instructions %}

{% blocktrans with email=request.session.registered_email %} @@ -36,4 +41,5 @@ {% block back %}

{% trans "Back" %}

{% endblock %} + {% endif %} {% endblock %} diff --git a/src/authentic2/views.py b/src/authentic2/views.py index 26133d84..890eead8 100644 --- a/src/authentic2/views.py +++ b/src/authentic2/views.py @@ -829,6 +829,8 @@ class BaseRegistrationView(FormView): return super(BaseRegistrationView, self).dispatch(request, *args, **kwargs) def form_valid(self, form): + if self.request.session.get('is_robot'): + return utils.redirect(self.request, 'registration_complete', params={REDIRECT_FIELD_NAME: self.next_url}) email = form.cleaned_data.pop('email') # if an email has already been sent, warn once before allowing resend diff --git a/tests/test_registration.py b/tests/test_registration.py index 13645ee2..697142d4 100644 --- a/tests/test_registration.py +++ b/tests/test_registration.py @@ -819,3 +819,17 @@ def test_registration_email_not_verified_required_and_unrequired_attributes(app, assert user.attributes.preferred_color == 'bleu' assert user.email == 'john.doe2@example.com' assert user.email_verified is True + + +def test_honeypot(app, db, settings, mailoutbox): + settings.DEFAULT_FROM_EMAIL = 'show only addr ' + + response = app.get(utils.make_url('registration_register')) + response = app.post(utils.make_url('registration_register'), params={ + 'email': 'testbot@entrouvert.com', + 'csrfmiddlewaretoken': response.context['csrf_token'], + 'robotcheck': 'a', + }) + response = response.follow() + assert len(mailoutbox) == 0 + assert 'Your registration request is refused' in response -- 2.29.2