A general AntiSpamForm using some tricks to prevent spam based on current django.contrib.comments.forms. It uses a timestamp, a security hash and a honeypot field. See AntiSpamModelForm too.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | import time
from django import forms
from django.forms.util import ErrorDict
from django.conf import settings
from django.utils.hashcompat import sha_constructor
class AntiSpamForm(forms.Form):
timestamp = forms.IntegerField(widget=forms.HiddenInput)
security_hash = forms.CharField(min_length=40, max_length=40, widget=forms.HiddenInput)
honeypot = forms.CharField(required=False,
widget=forms.TextInput(attrs={'style':'display:none;'}),
label='')
def __init__(self, data=None, initial=None):
if initial is None:
initial = {}
initial.update(self.generate_security_data())
super(AntiSpamForm, self).__init__(data=data, initial=initial)
def security_errors(self):
"""Return just those errors associated with security"""
errors = ErrorDict()
for f in ["honeypot", "timestamp", "security_hash"]:
if f in self.errors:
errors[f] = self.errors[f]
return errors
def clean_security_hash(self):
"""Check the security hash."""
security_hash_dict = {
'timestamp' : self.data.get("timestamp", ""),
}
expected_hash = self.generate_security_hash(**security_hash_dict)
actual_hash = self.cleaned_data["security_hash"]
if expected_hash != actual_hash:
raise forms.ValidationError("Security hash check failed.")
return actual_hash
def clean_timestamp(self):
"""Make sure the timestamp isn't too far (> 2 hours) in the past or too close (< 5 seg)."""
ts = self.cleaned_data["timestamp"]
difference = time.time() - ts
if difference > (2 * 60 * 60) or difference < 5:
raise forms.ValidationError("Timestamp check failed")
return ts
def generate_security_data(self):
"""Generate a dict of security data for "initial" data."""
timestamp = int(time.time())
security_dict = {
'timestamp' : str(timestamp),
'security_hash' : self.initial_security_hash(timestamp),
}
return security_dict
def initial_security_hash(self, timestamp):
"""
Generate the initial security hash from a (unix) timestamp.
"""
initial_security_dict = {
'timestamp' : str(timestamp),
}
return self.generate_security_hash(**initial_security_dict)
def generate_security_hash(self, timestamp):
"""Generate a (SHA1) security hash from the provided info."""
info = (timestamp, settings.SECRET_KEY)
return sha_constructor("".join(info)).hexdigest()
def clean_honeypot(self):
"""Check that nothing's been entered into the honeypot."""
value = self.cleaned_data["honeypot"]
if value:
raise forms.ValidationError(self.fields["honeypot"].label)
return value
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Thank you, i got it to work easily. As a reference i leave it here, you instantiate this class in one view and add it to its context
In your view
from forms import AntiSpamForm context['antispamform'] = AntiSpamForm()
In your template inside a list of fields in a form
form method='POST' {% csrf_token %} {% for field in antispamform %} {{ field }} {% endfor %} <input name='yourfield' value=''></input>
And in the view that recieves this form
form = AntiSpamForm(request.POST) if form.is_valid(): do_stuff()
That is all
#
if you get a deprecation warning on sha_constructor replace it with sha1 and import: from hashlib import sha1
#
also, probbaly better would be using kwargs in the init method:
def __init__(self, *args, **kwargs):
#
Please login first before commenting.