Mercurial > hg > CAPTCHAmiddleware
annotate captchamiddleware/middleware.py @ 8:59245309f054 default tip
conform to modern version of lxmlmiddleware
author | k0s <k0scist@gmail.com> |
---|---|
date | Fri, 26 Feb 2010 15:40:56 -0500 |
parents | ce757057961c |
children |
rev | line source |
---|---|
0
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
1 """ |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
2 CAPTCHA middleware |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
3 """ |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
4 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
5 import os |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
6 import random |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
7 import sys |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
8 from lxml import etree |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
9 from lxmlmiddleware import LXMLMiddleware |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
10 from skimpyGimpy import skimpyAPI |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
11 from urllib2 import urlopen |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
12 from webob import Request, exc |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
13 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
14 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
15 class CAPTCHAmiddleware(LXMLMiddleware): |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
16 """ |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
17 put CAPTCHAs on forms for unauthorized users |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
18 """ |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
19 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
20 ### class level variables |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
21 defaults = { |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
22 'dictionary': '/usr/share/dict/words', |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
23 'error': '<span class="error">Please type the CAPTCHA</span>', |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
24 'minimum_length': 5, |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
25 'path': "/input[@type='submit']", |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
26 } |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
27 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
28 def __init__(self, app, **kw): |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
29 self.app = app |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
30 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
31 # set instance parameters from kw and defaults |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
32 for key in self.defaults: |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
33 setattr(self, key, kw.get(key, self.defaults[key])) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
34 self.minimum_length = int(self.minimum_length) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
35 assert os.path.exists(self.dictionary) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
36 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
37 # get dictionary |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
38 if self.dictionary.startswith('http://') or self.dictionary.startswith('https://'): |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
39 f = urlopen(self.dictionary) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
40 else: |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
41 f = file(self.dictionary) |
2
c861518b2a44
fix bug whereby forbidden characters cause issues
k0s <k0scist@gmail.com>
parents:
1
diff
changeset
|
42 |
c861518b2a44
fix bug whereby forbidden characters cause issues
k0s <k0scist@gmail.com>
parents:
1
diff
changeset
|
43 # characters skimpygimpy doesnt know about |
c861518b2a44
fix bug whereby forbidden characters cause issues
k0s <k0scist@gmail.com>
parents:
1
diff
changeset
|
44 forbidden_characters = set(["'"]) |
c861518b2a44
fix bug whereby forbidden characters cause issues
k0s <k0scist@gmail.com>
parents:
1
diff
changeset
|
45 |
3 | 46 self.words = [ i.strip().lower() for i in f.readlines() |
2
c861518b2a44
fix bug whereby forbidden characters cause issues
k0s <k0scist@gmail.com>
parents:
1
diff
changeset
|
47 if (len(i.strip()) > self.minimum_length) |
c861518b2a44
fix bug whereby forbidden characters cause issues
k0s <k0scist@gmail.com>
parents:
1
diff
changeset
|
48 and not forbidden_characters.intersection(i) ] |
0
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
49 random.shuffle(self.words) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
50 |
3 | 51 def check_captcha(self, request): |
52 captcha = request.POST.get('captcha', '').lower() | |
53 key = request.POST.get('key') | |
54 if not key: return False | |
55 try: | |
56 key = int(key) | |
57 except ValueError: | |
58 return False | |
59 try: | |
60 value = self.words[key] | |
61 except IndexError: | |
62 raise # TODO: better error handling | |
63 return value == captcha | |
0
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
64 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
65 def __call__(self, environ, start_response): |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
66 request = Request(environ) |
2
c861518b2a44
fix bug whereby forbidden characters cause issues
k0s <k0scist@gmail.com>
parents:
1
diff
changeset
|
67 if request.method == 'POST' and not request.remote_user: |
4
ce757057961c
flow contol now works; bumping version
k0s <k0scist@gmail.com>
parents:
3
diff
changeset
|
68 if not self.check_captcha(request): |
ce757057961c
flow contol now works; bumping version
k0s <k0scist@gmail.com>
parents:
3
diff
changeset
|
69 location = request.referrer |
ce757057961c
flow contol now works; bumping version
k0s <k0scist@gmail.com>
parents:
3
diff
changeset
|
70 return exc.HTTPSeeOther(location=location)(environ, start_response) |
ce757057961c
flow contol now works; bumping version
k0s <k0scist@gmail.com>
parents:
3
diff
changeset
|
71 # TODO: set a cookie to record an error |
ce757057961c
flow contol now works; bumping version
k0s <k0scist@gmail.com>
parents:
3
diff
changeset
|
72 # stage 2: record form values from request.POST, |
ce757057961c
flow contol now works; bumping version
k0s <k0scist@gmail.com>
parents:
3
diff
changeset
|
73 # and reinsert them into the form so that users |
ce757057961c
flow contol now works; bumping version
k0s <k0scist@gmail.com>
parents:
3
diff
changeset
|
74 # don't hate me ;) |
0
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
75 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
76 return LXMLMiddleware.__call__(self, environ, start_response) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
77 |
8
59245309f054
conform to modern version of lxmlmiddleware
k0s <k0scist@gmail.com>
parents:
4
diff
changeset
|
78 def manipulate(self, request, response, tree): |
0
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
79 """manipulate the DOM; should return an etree._Element""" |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
80 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
81 # don't use CAPTCHAs for authorized users |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
82 if request.remote_user: |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
83 return tree |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
84 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
85 for element in tree.findall(".//form[@method='post']"): |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
86 key = random.Random().randint(0, len(self.words)) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
87 word = self.words[key] |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
88 captcha = skimpyAPI.Pre(word).data() |
3 | 89 string = '<div class="captcha">%s<input type="hidden" name="key" value="%s"/><input type="text" name="captcha"/></div>' % (captcha, key) |
0
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
90 addition = etree.fromstring(string) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
91 insertion_point = element.find('.' + self.path) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
92 insertion_point.addprevious(addition) |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
93 |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
94 return tree |
21ec6325ae0e
initial import of CAPTCHA middleware; unfinished
k0s <k0scist@gmail.com>
parents:
diff
changeset
|
95 |