author | Sylvain Thénault <sylvain.thenault@logilab.fr> |
Fri, 19 Mar 2010 14:47:09 +0100 | |
changeset 4961 | 03e083faefbf |
parent 4722 | 9c13d5db03d9 |
child 5037 | 7778a2bbdf9d |
permissions | -rw-r--r-- |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
1 |
"""Simple captcha library, based on PIL. Monkey patch functions in this module |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
2 |
if you want something better... |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
3 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
4 |
:organization: Logilab |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
5 |
:copyright: 2009-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
6 |
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
7 |
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
8 |
""" |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
9 |
__docformat__ = "restructuredtext en" |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
10 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
11 |
from random import randint, choice |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
12 |
from cStringIO import StringIO |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
13 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
14 |
import Image, ImageFont, ImageDraw, ImageFilter |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
15 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
16 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
17 |
from time import time |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
18 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
19 |
from cubicweb import tags |
4621
fe1c5a46a1cb
move captcha view to a place where it will be loaded by the registry...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4595
diff
changeset
|
20 |
from cubicweb.web import formwidgets as fw |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
21 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
22 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
23 |
def pil_captcha(text, fontfile, fontsize): |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
24 |
"""Generate a captcha image. Return a PIL image object. |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
25 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
26 |
adapted from http://code.activestate.com/recipes/440588/ |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
27 |
""" |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
28 |
# randomly select the foreground color |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
29 |
fgcolor = randint(0, 0xffff00) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
30 |
# make the background color the opposite of fgcolor |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
31 |
bgcolor = fgcolor ^ 0xffffff |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
32 |
# create a font object |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
33 |
font = ImageFont.truetype(fontfile, fontsize) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
34 |
# determine dimensions of the text |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
35 |
dim = font.getsize(text) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
36 |
# create a new image slightly larger that the text |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
37 |
img = Image.new('RGB', (dim[0]+5, dim[1]+5), bgcolor) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
38 |
draw = ImageDraw.Draw(img) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
39 |
# draw 100 random colored boxes on the background |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
40 |
x, y = img.size |
4722
9c13d5db03d9
pylint suggested refactorings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4621
diff
changeset
|
41 |
for num in xrange(100): |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
42 |
draw.rectangle((randint(0, x), randint(0, y), |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
43 |
randint(0, x), randint(0, y)), |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
44 |
fill=randint(0, 0xffffff)) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
45 |
# add the text to the image |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
46 |
draw.text((3, 3), text, font=font, fill=fgcolor) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
47 |
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
48 |
return img |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
49 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
50 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
51 |
def captcha(fontfile, fontsize, size=5, format='JPEG'): |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
52 |
"""Generate an arbitrary text, return it together with a buffer containing |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
53 |
the captcha image for the text |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
54 |
""" |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
55 |
text = u''.join(choice('QWERTYUOPASDFGHJKLZXCVBNM') for i in range(size)) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
56 |
img = pil_captcha(text, fontfile, fontsize) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
57 |
out = StringIO() |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
58 |
img.save(out, format) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
59 |
out.seek(0) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
60 |
return text, out |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
61 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
62 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
63 |
class CaptchaWidget(fw.TextInput): |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
64 |
def render(self, form, field, renderer=None): |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
65 |
# t=int(time()*100) to make sure img is not cached |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
66 |
src = form._cw.build_url('view', vid='captcha', t=int(time()*100)) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
67 |
img = tags.img(src=src, alt=u'captcha') |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
68 |
img = u'<div class="captcha">%s</div>' % img |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
69 |
return img + super(CaptchaWidget, self).render(form, field, renderer) |