A Django Captcha without Freetype or the Python Imaging Library (PIL)

If, like me, you've had trouble installing the Python Imaging Library or FreeType, you may have also had trouble getting a captcha to work. Here's my quick and dirty workaround — be warned, this is very low level security, and shouldn't be used on high-profile sites.

Form Field

from django.forms.fields import CharField, MultiValueField
from django.forms.widgets import TextInput, MultiWidget, HiddenInput
from django import forms
from django.utils.safestring import mark_safe
import hashlib
import random


class CaptchaTextInput(MultiWidget):
    def __init__(self,attrs=None):
        widgets = (
            HiddenInput(attrs),
            TextInput(attrs),
        )
        super(CaptchaTextInput,self).__init__(widgets,attrs)

    def decompress(self,value):
        if value:
            return value.split(',')
        return [None,None]


    def render(self, name, value, attrs=None):
        ints = (random.randint(0,9),random.randint(0,9),)
        answer = hashlib.sha1(str(sum(ints))).hexdigest()

        extra = "What is %d + %d?" % (ints[0], ints[1])
        value = [answer, u'',]

        return mark_safe(extra + super(CaptchaTextInput, self).render(name, value, attrs=attrs))


class CaptchaField(MultiValueField):
    widget=CaptchaTextInput

    def __init__(self, *args,**kwargs):
        fields = (
            CharField(show_hidden_initial=True), 
            CharField(),
        )
        super(CaptchaField,self).__init__(fields=fields, *args, **kwargs)

    def compress(self,data_list):
        if data_list:
            return ','.join(data_list)
        return None


    def clean(self, value):
        super(CaptchaField, self).clean(value)
        response, value[1] = value[1].strip().lower(), ''

        if not hashlib.sha1(str(response)).hexdigest() == value[0]:
            raise forms.ValidationError("Sorry, you got the security question wrong - to prove you're not a spammer, please try again.")
        return value

Usage

from django import forms
from models import Post
from ABOVE-FILE import CaptchaField

class CaptchaTestForm(forms.Form):
    myfield = AnyOtherField()
    ...
    security_check = CaptchaField()

Credit to the author of django-simple-captcha, from whom I borrowed most of this code.


Loading