I've made some more changes/fixes to this, in case anyone's
interested. Here's what's changed from the original:
- updated for compatibility w/ django-1.1
- using sha1 instead of md5 to store captcha image (theoretically more
secure)
- added expire_time config variable
- added imagetype variable (defaults to jpg)
- fixed bug where .svn dirs (or any other files in the fonts dir)
messed up the font loading
And here's the patch:
--- cut here ---
diff -x .svn -Nur captcha/__init__.py captcha.new/__init__.py
--- captcha/__init__.py 2007-06-14 12:53:55.000000000 -0500
+++ captcha.new/__init__.py 2009-03-16 10:15:43.000000000 -0500
@@ -6,18 +6,21 @@
"""
from os import listdir, sep, access, mkdir, W_OK, R_OK, remove,
chmod, path, rmdir, stat
+from glob import glob
from urllib import basejoin
-import md5
+import sha
from random import choice, randrange
from sys import modules
import tempfile
import datetime
from PIL import Image, ImageColor, ImageFont, ImageDraw
-from django.newforms import *
-from django.newforms.fields import CharField
+from django.forms import Widget, Field, ValidationError
+from django.forms.fields import CharField
from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import gettext
from django.utils.datastructures import MultiValueDict
+from django.utils.safestring import mark_safe
def clean_old_entries(captchas_dir, max_age=1200):
"""maintainance function for deleting all expired captchas
@@ -40,7 +43,7 @@
pass
def mycrypt(value, salt):
- return md5.new(value.lower() + salt +
settings.SECRET_KEY).hexdigest()
+ return sha.new(value.lower() + salt +
settings.SECRET_KEY).hexdigest()
class CaptchaWidget(Widget):
"""generate a captcha image and display the image along with
@@ -53,6 +56,7 @@
'upload_url': None, # default: None (uses MEDIA_URL/
captchas)
'captchaconf_dir': None, # default: None (uses the
directory of the captcha module)
'auto_cleanup': True, # default: True (delete all captchas
older than 20 minutes)
+ 'expire_time' : 1200, # default: 1200 (time in seconds after
which old captchas are deleted)
'minmaxvpos': (8, 15), # default: (8, 15) (vertical position
of characters)
'minmaxrotations': (-30,31), # default: (-30,31) (rotate
characters)
'minmaxheight': (30,45), # default: (30,45) (font size)
@@ -63,6 +67,7 @@
'imagesize': (200,60), # default: (200,60)
'iterations': 1, # default 1 (change to a high value (200 is
a good choice)
# for trying out new settings)
+ 'imagetype' : 'jpg',
}
# change colors to tuples if possible
try:
@@ -83,17 +88,21 @@
if not self.csettings['captchaconf_dir']:
myfile = modules[self.__module__].__file__
self.csettings['captchaconf_dir'] = myfile[:myfile.rfind
(sep)]
+
super(CaptchaWidget, self).__init__(*args, **kwargs)
def render(self, name, value, attrs=None):
img = Image.new('RGB',self.csettings['imagesize'],
self.csettings['bgcolor'])
for dummy in range(self.csettings['iterations']):
img = self.generate_image(img)
- return u'''<input type="hidden" name="%(name)s"
value="captcha.%(hiddentext)s"
-/><img src="%(imageurl)s" alt="" /><br
-/><input type="text" name="%(name)s" id="id_%(name)s" />''' %
{'name':name,
- 'hiddentext': self.hiddentext,
- 'imageurl': self.imageurl }
+ html = u'''<input type="hidden" name="%(name)s"
value="captcha.%(hiddentext)s"/>
+ <img src="%(imageurl)s" alt="" class="captcha" />
+ <input type="text" name="%(name)s" id="id_%(name)
s" class="text" />
+ ''' % {'name':name,
+ 'hiddentext': self.hiddentext,
+ 'imageurl': self.imageurl }
+
+ return mark_safe(html)
def generate_image(self, bgimage):
""" create a image file.
@@ -102,13 +111,13 @@
HASH is the hashed solution.
"""
if self.csettings['auto_cleanup']:
- clean_old_entries(self.csettings['captchas_dir'])
+ clean_old_entries(self.csettings['captchas_dir'],
self.csettings['expire_time'])
cs = self.csettings
imagesize = cs['imagesize']
posnew = 7
fontdir = path.join(cs['captchaconf_dir'], 'fonts')
- fontnames = [path.join(fontdir, x) for x in listdir
(fontdir) ]
+ fontnames = [path.join(fontdir, x) for x in glob('%s/*.ttf' %
fontdir) ]
# generate characters
@@ -161,17 +170,21 @@
self.imageurl = '%s/%s/%s' % (cs['upload_url'],
self.hiddentext, plainfilename)
imagepath = path.join(dirpath, plainfilename)
- try:
- bgimage.convert('P', palette=Image.ADAPTIVE,
colors=4).save(imagepath + '.gif')
- ext = '.gif'
- except:
- bgimage.save(imagepath + '.jpg')
- ext = '.jpg'
- self.imageurl += ext
- chmod(imagepath + ext, 0644)
+
+ imagetype = cs.get('imagetype')
+
+ if imagetype == 'gif':
+ bgimage.convert('P', palette=Image.ADAPTIVE,
colors=4).save(imagepath + imagetype)
+ elif imagetype in ('jpg', 'png'):
+ bgimage.save('%s.%s' % (imagepath, imagetype))
+ else:
+ raise ImproperlyConfigured('Invalid captcha image
imagetype: %s' % imagetype)
+
+ self.imageurl = '%s.%s' % (self.imageurl, imagetype)
+ chmod('%s.%s' % (imagepath, imagetype), 0644)
return bgimage
- def value_from_datadict(self, data, name):
+ def value_from_datadict(self, data, files, name):
if isinstance(data, MultiValueDict):
return data.getlist(name)
return data.get(name, None)
@@ -200,6 +213,7 @@
settingcaptchas_dir = None
self.captchas_dir = options.get('captchas_dir') or
settingcaptchas_dir or \
path.join(settings.MEDIA_ROOT, 'captchas')
+
super(CaptchaField, self).__init__(required=required,
widget=CaptchaWidget(options=options),
label=label, help_text=help_text, *args, **kwargs
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---