Skip to content

Commit

Permalink
feat(account): Signup honeypot field
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit 3e9da7df6fc518eb1615e1b3055ede292a550d9c
Author: Raymond Penners <raymond.penners@intenct.nl>
Date:   Thu May 9 22:57:12 2024 +0200

    fix: label=False

commit cf1846bb5cd0351b36728b936d70fae80b18a139
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon May 6 18:46:21 2024 -0500

    fix: fix for 3.7

commit 7ff2f81d800768bb36f424aac51e617a5aa2ac37
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Sun May 5 16:00:50 2024 -0500

    Update ChangeLog.rst

    Co-authored-by: Raymond Penners <raymond.penners@intenct.nl>

commit 0f7214d5e2ac750a4455b9da0b476a4bf9e325a7
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Sun May 5 15:31:24 2024 -0500

    fix: formatting on forms.py

commit 2451e14c7f66893de64847e24d7fa00b44efac43
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Sun May 5 15:28:05 2024 -0500

    fix: black formatting

commit 0a8479abe462fd0021971bea87d7c86f28b3a8b8
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Sun May 5 15:25:46 2024 -0500

    fix: move honeypot code into UI specific form

commit 035dbbf2a6082d66eed7caf1d870bca9a0155298
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon Apr 29 20:30:47 2024 -0500

    test: added more specific assertions to tests for honeypot

commit 6e39ba90f7be0edabd02b75587e661fbb71821e4
Author: Raymond Penners <raymond.penners@intenct.nl>
Date:   Wed May 8 23:31:58 2024 +0200

    doc: update changelog

commit 5a559fcf3b3a4434b84dde286792d763e6a8cdc3
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon Apr 29 20:05:40 2024 -0500

    doc: updated method doc with honeypot behavior

commit d34040a8c6d1ce349e0fe4e6ba4d1f272f917a8f
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon Apr 29 20:02:01 2024 -0500

    feat: make honeypot field not required

commit 4b4be40eb080851d5b7e30cf47d10d91179c0ed8
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon Apr 29 20:00:40 2024 -0500

    feat: turn off autocomplete for honeypot from browser tools

commit 7709f4e90915390161c92e900890311dd425e779
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon Apr 29 19:57:29 2024 -0500

    feat: remove honeypot from tab index

commit ea8804a9187550808631c9cddda3b3f37f3ab87c
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon Apr 29 19:53:58 2024 -0500

    feat: hide label for honeypot

commit c7662c4d7853708cce2f76558ce9035db5174514
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon Apr 29 19:50:20 2024 -0500

    feat: hide input field for honeypot

commit 699731e5da43be367aaf49ef46b613953403dfa2
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon Apr 29 19:30:12 2024 -0500

    feat: initial basic functionality for honeypot

commit 73f1999ac2a89d5a9f4258aa25dc7f6868eae68e
Author: Riley Mathews <rileymathews80@gmail.com>
Date:   Mon Apr 29 18:43:18 2024 -0500

    feat: added config value for honeypot
  • Loading branch information
pennersr committed May 9, 2024
1 parent 8837079 commit 8281bd7
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 1 deletion.
4 changes: 4 additions & 0 deletions ChangeLog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
- An official API for single-page and mobile application support is now
available, via the new ``allauth.headless`` app.

- Added support for a honeypot field on the signup form. Real users do not see
the field and therefore leave it empty. When bots do fill out the field
account creation is silently skipped.


0.62.1 (2024-04-24)
*******************
Expand Down
7 changes: 7 additions & 0 deletions allauth/account/app_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,13 @@ def SIGNUP_FORM_CLASS(self):
"""
return self._setting("SIGNUP_FORM_CLASS", None)

@property
def SIGNUP_FORM_HONEYPOT_FIELD(self):
"""
Honeypot field name. Empty string or ``None`` will disable honeypot behavior.
"""
return self._setting("SIGNUP_FORM_HONEYPOT_FIELD", None)

@property
def USERNAME_REQUIRED(self):
"""
Expand Down
35 changes: 34 additions & 1 deletion allauth/account/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,41 @@ def __init__(self, *args, **kwargs):
if hasattr(self, "field_order"):
set_form_field_order(self, self.field_order)

honeypot_field_name = app_settings.SIGNUP_FORM_HONEYPOT_FIELD
if honeypot_field_name:
self.fields[honeypot_field_name] = forms.CharField(
required=False,
label="",
widget=forms.TextInput(
attrs={
"style": "position: absolute; right: -99999px;",
"tabindex": "-1",
"autocomplete": "nope",
}
),
)

def try_save(self, request):
"""
override of parent class method that adds additional catching
of a potential bot filling out the honeypot field and returns a
'fake' email verification response if honeypot was filled out
"""
honeypot_field_name = app_settings.SIGNUP_FORM_HONEYPOT_FIELD
if honeypot_field_name:
if self.cleaned_data[honeypot_field_name]:
user = None
adapter = get_adapter()
# honeypot fields work best when you do not report to the bot
# that anything went wrong. So we return a fake email verification
# sent response but without creating a user
resp = adapter.respond_email_verification_sent(request, None)
return user, resp

return super().try_save(request)

def clean(self):
super(SignupForm, self).clean()
super().clean()

# `password` cannot be of type `SetPasswordField`, as we don't
# have a `User` yet. So, let's populate a dummy user to be used
Expand Down
33 changes: 33 additions & 0 deletions allauth/account/tests/test_signup.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,36 @@ def test_email_lower_case(db, settings):
)
assert resp.status_code == 302
assert EmailAddress.objects.filter(email="john@doe.org").count() == 1


def test_does_not_create_user_when_honeypot_filled_out(client, db, settings):
settings.ACCOUNT_SIGNUP_FORM_HONEYPOT_FIELD = "phone_number"
resp = client.post(
reverse("account_signup"),
{
"username": "johndoe",
"email": "john@example.com",
"password1": "Password1@",
"password2": "Password1@",
"phone_number": "5551231234",
},
)

assert not get_user_model().objects.all().exists()
assert resp.status_code == 302


def test_create_user_when_honeypot_not_filled_out(client, db, settings):
settings.ACCOUNT_SIGNUP_FORM_HONEYPOT_FIELD = "phone_number"
resp = client.post(
reverse("account_signup"),
{
"username": "johndoe",
"email": "john@example.com",
"password1": "Password1@",
"password2": "Password1@",
"phone_number": "",
},
)
assert get_user_model().objects.filter(username="johndoe").count() == 1
assert resp.status_code == 302
12 changes: 12 additions & 0 deletions docs/account/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,18 @@ Available settings:
date). This class should implement a ``def signup(self, request, user)``
method, where user represents the newly signed up user.

``ACCOUNT_SIGNUP_FORM_HONEYPOT_FIELD`` (default: ``None``)
A string value that will be used as the HTML 'name' property
on a honeypot input field on the sign up form. Honeypot fields are hidden
to normal users but might be filled out by niave spam bots. When the field
is filled out the app will not create a new user and attempt to fool
the bot with a fake successful response. We recommend setting this
to some believable value that your app does not actually collect
on signup e.g. 'phone_number' or 'address'. Honeypots are not
always successful for sophisticated bots so this should be
used as one layer in a suite of spam detection tools if your
site is having trouble with spam.

``ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE`` (default: ``True``)
When signing up, let the user type in their password twice to avoid typos.

Expand Down

0 comments on commit 8281bd7

Please sign in to comment.