author | Denis Laxalde <denis.laxalde@logilab.fr> |
Fri, 24 Jun 2016 13:08:52 +0200 | |
branch | 3.22 |
changeset 11387 | 51e988f9870e |
parent 10609 | e2d8e81bfe68 |
child 11405 | 5ba55f4c813a |
permissions | -rw-r--r-- |
7825 | 1 |
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
5421
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
2 |
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
3 |
# |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
4 |
# This file is part of CubicWeb. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
5 |
# |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
6 |
# CubicWeb is free software: you can redistribute it and/or modify it under the |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
7 |
# terms of the GNU Lesser General Public License as published by the Free |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
8 |
# Software Foundation, either version 2.1 of the License, or (at your option) |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
9 |
# any later version. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
10 |
# |
5424
8ecbcbff9777
replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5421
diff
changeset
|
11 |
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
5421
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
12 |
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
13 |
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
14 |
# details. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
15 |
# |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
16 |
# You should have received a copy of the GNU Lesser General Public License along |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
17 |
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
18 |
"""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
|
19 |
if you want something better... |
7825 | 20 |
""" |
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 |
__docformat__ = "restructuredtext en" |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
23 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
24 |
from random import randint, choice |
10566
4c103a2c5e93
[captcha] Port to io.BytesIO
Rémi Cardona <remi.cardona@free.fr>
parents:
9772
diff
changeset
|
25 |
from io import BytesIO |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
26 |
|
10609
e2d8e81bfe68
[py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10566
diff
changeset
|
27 |
from six.moves import range |
e2d8e81bfe68
[py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10566
diff
changeset
|
28 |
|
9772
7d0d622c9bc9
Import PIL modules from the PIL namespace to be Pillow-compatible
Christophe de Vienne <christophe@unlish.com>
parents:
7825
diff
changeset
|
29 |
from PIL import Image, ImageFont, ImageDraw, ImageFilter |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
30 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
31 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
32 |
from time import time |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
33 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
34 |
from cubicweb import tags |
5037
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
35 |
from cubicweb.web import ProcessFormError, formwidgets as fw |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
36 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
37 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
38 |
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
|
39 |
"""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
|
40 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
41 |
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
|
42 |
""" |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
43 |
# randomly select the foreground color |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
44 |
fgcolor = randint(0, 0xffff00) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
45 |
# 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
|
46 |
bgcolor = fgcolor ^ 0xffffff |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
47 |
# create a font object |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
48 |
font = ImageFont.truetype(fontfile, fontsize) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
49 |
# determine dimensions of the text |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
50 |
dim = font.getsize(text) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
51 |
# 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
|
52 |
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
|
53 |
draw = ImageDraw.Draw(img) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
54 |
# 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
|
55 |
x, y = img.size |
10609
e2d8e81bfe68
[py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10566
diff
changeset
|
56 |
for num in range(100): |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
57 |
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
|
58 |
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
|
59 |
fill=randint(0, 0xffffff)) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
60 |
# 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
|
61 |
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
|
62 |
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
|
63 |
return img |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
64 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
65 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
66 |
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
|
67 |
"""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
|
68 |
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
|
69 |
""" |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
70 |
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
|
71 |
img = pil_captcha(text, fontfile, fontsize) |
10566
4c103a2c5e93
[captcha] Port to io.BytesIO
Rémi Cardona <remi.cardona@free.fr>
parents:
9772
diff
changeset
|
72 |
out = BytesIO() |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
73 |
img.save(out, format) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
74 |
out.seek(0) |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
75 |
return text, out |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
76 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
77 |
|
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
78 |
class CaptchaWidget(fw.TextInput): |
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
79 |
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
|
80 |
# t=int(time()*100) to make sure img is not cached |
5037
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
81 |
src = form._cw.build_url('view', vid='captcha', t=int(time()*100), |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
82 |
captchakey=field.input_name(form)) |
4595
bb08a75832e6
backport crypto/captcha utilities from the registration cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff
changeset
|
83 |
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
|
84 |
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
|
85 |
return img + super(CaptchaWidget, self).render(form, field, renderer) |
5037
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
86 |
|
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
87 |
def process_field_data(self, form, field): |
5223
6abd6e3599f4
#773448: refactor session and 'no connection' handling, by introducing proper web session. We should now be able to see page even when no anon is configured, and be redirected to the login form as soon as one tries to do a query.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5037
diff
changeset
|
88 |
captcha = form._cw.session.data.pop(field.input_name(form), None) |
5037
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
89 |
val = super(CaptchaWidget, self).process_field_data(form, field) |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
90 |
if val is None: |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
91 |
return val # required will be checked by field |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
92 |
if captcha is None: |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
93 |
msg = form._cw._('unable to check captcha, please try again') |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
94 |
raise ProcessFormError(msg) |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
95 |
elif val.lower() != captcha.lower(): |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
96 |
msg = form._cw._('incorrect captcha value') |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
97 |
raise ProcessFormError(msg) |
7778a2bbdf9d
[captcha] handle captcha validation properly in the captcha widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4722
diff
changeset
|
98 |
return val |