Add honeypot on forum

This commit is contained in:
Antoine Bartuccio 2024-07-22 11:40:11 +02:00
parent c7f8cdd098
commit 2c8f18d7fc
4 changed files with 33 additions and 2 deletions

View File

@ -29,6 +29,7 @@
{% endif %} {% endif %}
<form action="" method="post" enctype="multipart/form-data"> <form action="" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{% render_honeypot_field settings.HONEYPOT_FIELD_NAME_FORUM %}
{{ form.as_p() }} {{ form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form> </form>

View File

@ -14,6 +14,7 @@
# #
import pytest import pytest
from django.conf import settings
from django.test import Client from django.test import Client
from django.urls import reverse from django.urls import reverse
from pytest_django.asserts import assertRedirects from pytest_django.asserts import assertRedirects
@ -24,13 +25,14 @@ from forum.models import Forum, ForumMessage, ForumTopic
@pytest.mark.django_db @pytest.mark.django_db
class TestTopicCreation: class TestTopicCreation:
def test_topic_creation_success(self, client: Client): def test_topic_creation_ok(self, client: Client):
user: User = User.objects.get(username="root") user: User = User.objects.get(username="root")
forum = Forum.objects.get(name="AE") forum = Forum.objects.get(name="AE")
client.force_login(user) client.force_login(user)
payload = { payload = {
"title": "Hello IT.", "title": "Hello IT.",
"message": "Have you tried turning it off and on again ?", "message": "Have you tried turning it off and on again ?",
settings.HONEYPOT_FIELD_NAME_FORUM: settings.HONEYPOT_VALUE,
} }
assert not ForumTopic.objects.filter(_title=payload["title"]).exists() assert not ForumTopic.objects.filter(_title=payload["title"]).exists()
response = client.post(reverse("forum:new_topic", args=str(forum.id)), payload) response = client.post(reverse("forum:new_topic", args=str(forum.id)), payload)
@ -46,13 +48,28 @@ class TestTopicCreation:
assert topic assert topic
assert topic.last_message.message == payload["message"] assert topic.last_message.message == payload["message"]
def test_topic_creation_failure(self, client: Client): def test_topic_creation_honeypot_fail(self, client: Client):
user: User = User.objects.get(username="root")
forum = Forum.objects.get(name="AE")
client.force_login(user)
payload = {
"title": "You shall",
"message": "Not pass !",
settings.HONEYPOT_FIELD_NAME_FORUM: settings.HONEYPOT_VALUE + "random",
}
assert not ForumTopic.objects.filter(_title=payload["title"]).exists()
response = client.post(reverse("forum:new_topic", args=str(forum.id)), payload)
assert response.status_code == 200
assert not ForumTopic.objects.filter(_title=payload["title"]).exists()
def test_topic_creation_fail(self, client: Client):
user: User = User.objects.get(username="krophil") user: User = User.objects.get(username="krophil")
forum = Forum.objects.get(name="AE") forum = Forum.objects.get(name="AE")
client.force_login(user) client.force_login(user)
payload = { payload = {
"title": "You shall", "title": "You shall",
"message": "Not pass !", "message": "Not pass !",
settings.HONEYPOT_FIELD_NAME_FORUM: settings.HONEYPOT_VALUE,
} }
assert not ForumTopic.objects.filter(_title=payload["title"]).exists() assert not ForumTopic.objects.filter(_title=payload["title"]).exists()
response = client.post(reverse("forum:new_topic", args=str(forum.id)), payload) response = client.post(reverse("forum:new_topic", args=str(forum.id)), payload)

View File

@ -22,6 +22,7 @@
# #
# #
import math import math
from functools import partial
from ajax_select import make_ajax_field from ajax_select import make_ajax_field
from django import forms from django import forms
@ -32,11 +33,13 @@ from django.db import IntegrityError
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils import html, timezone from django.utils import html, timezone
from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView, RedirectView from django.views.generic import DetailView, ListView, RedirectView
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.views.generic.edit import CreateView, DeleteView, UpdateView
from haystack.query import RelatedSearchQuerySet from haystack.query import RelatedSearchQuerySet
from honeypot.decorators import check_honeypot
from core.views import ( from core.views import (
CanCreateMixin, CanCreateMixin,
@ -242,6 +245,9 @@ class TopicForm(forms.ModelForm):
title = forms.CharField(required=True, label=_("Title")) title = forms.CharField(required=True, label=_("Title"))
@method_decorator(
partial(check_honeypot, field_name=settings.HONEYPOT_FIELD_NAME_FORUM), name="post"
)
class ForumTopicCreateView(CanCreateMixin, CreateView): class ForumTopicCreateView(CanCreateMixin, CreateView):
model = ForumMessage model = ForumMessage
form_class = TopicForm form_class = TopicForm
@ -331,6 +337,9 @@ class ForumMessageView(SingleObjectMixin, RedirectView):
return self.object.get_url() return self.object.get_url()
@method_decorator(
partial(check_honeypot, field_name=settings.HONEYPOT_FIELD_NAME_FORUM), name="post"
)
class ForumMessageEditView(CanEditMixin, UpdateView): class ForumMessageEditView(CanEditMixin, UpdateView):
model = ForumMessage model = ForumMessage
form_class = forms.modelform_factory( form_class = forms.modelform_factory(
@ -381,6 +390,9 @@ class ForumMessageUndeleteView(SingleObjectMixin, RedirectView):
return self.object.get_absolute_url() return self.object.get_absolute_url()
@method_decorator(
partial(check_honeypot, field_name=settings.HONEYPOT_FIELD_NAME_FORUM), name="post"
)
class ForumMessageCreateView(CanCreateMixin, CreateView): class ForumMessageCreateView(CanCreateMixin, CreateView):
model = ForumMessage model = ForumMessage
form_class = forms.modelform_factory( form_class = forms.modelform_factory(

View File

@ -287,6 +287,7 @@ REST_FRAMEWORK["UNAUTHENTICATED_USER"] = "core.models.AnonymousUser"
HONEYPOT_FIELD_NAME = "body2" HONEYPOT_FIELD_NAME = "body2"
HONEYPOT_VALUE = "content" HONEYPOT_VALUE = "content"
HONEYPOT_RESPONDER = custom_honeypot_error # Make honeypot errors less suspicious HONEYPOT_RESPONDER = custom_honeypot_error # Make honeypot errors less suspicious
HONEYPOT_FIELD_NAME_FORUM = "message2" # Only used on forum
# Email # Email