1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#!/usr/bin/env python -tt
# encoding: utf-8
from django.forms import *
import settings
import httplib, urllib
# Code was taken from http://smileychris.tactful.co.nz/static/uploads/recaptcha.py
# Thanks for implementing!
class RecaptchaWidget(Widget):
def __init__(self, theme=None, tabindex=None):
'''
From http://recaptcha.net/apidocs/captcha/#look-n-feel:
theme: 'red' | 'white' | 'blackglass'
Defines which theme to use for reCAPTCHA.
tabindex: any integer
Sets a tabindex for the reCAPTCHA text box. If other elements in
the form use a tabindex, this should be set so that navigation is
easier for the user.
'''
options = {}
if theme:
options['theme'] = theme
if tabindex:
options['tabindex'] = tabindex
self.options = options
super(RecaptchaWidget, self).__init__()
def render(self, name, value, attrs=None):
args = dict(public_key=settings.RECAPTCHA_PUBLIC_KEY)
if self.options:
args['options'] = '''<script type="text/javascript">
var RecaptchaOptions = %r;
</script>
''' % self.options
return '''%(options)s<script type="text/javascript"
src="https://www.google.com/recaptcha/api/challenge?k=%(public_key)s">
</script>
<noscript>
<iframe src="https://www.google.com/recaptcha/api/noscript?k=%(public_key)s"
style="height: 300px; width: 500px; border: none;"></iframe><br />
<textarea name="recaptcha_challenge_field" rows="3" cols="40">
</textarea>
<input type="hidden" name="recaptcha_response_field"
value="manual_challenge">
</noscript>''' % args
def value_from_datadict(self, data, files, name):
challenge = data.get('recaptcha_challenge_field')
response = data.get('recaptcha_response_field')
return (challenge, response)
def id_for_label(self, id_):
return None
class RecaptchaField(Field):
widget = RecaptchaWidget
def __init__(self, remote_ip, *args, **kwargs):
self.remote_ip = remote_ip
super(RecaptchaField, self).__init__(*args, **kwargs)
def clean(self, value):
value = super(RecaptchaField, self).clean(value)
challenge, response = value
if not challenge:
raise ValidationError(u'An error occured with the CAPTCHA service. Please try again.')
if not response:
raise ValidationError(u'Please enter the CAPTCHA solution.')
value = validate_recaptcha(self.remote_ip, challenge, response)
if not value.get('result'):
raise ValidationError(u'An incorrect CAPTCHA solution was entered.')
return value
class RecaptchaFieldPlaceholder(Field):
'''
Placeholder field for use with RecaptchaBaseForm which gets replaced with
RecaptchaField (which is passed the remote_ip) when RecaptchaBaseForm is
initialised.
'''
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
class RecaptchaBaseForm(BaseForm):
def __init__(self, remote_ip, *args, **kwargs):
for key, field in self.base_fields.items():
if isinstance(field, RecaptchaFieldPlaceholder):
self.base_fields[key] = RecaptchaField(remote_ip, *field.args, **field.kwargs)
super(RecaptchaBaseForm, self).__init__(*args, **kwargs)
class RecaptchaForm(RecaptchaBaseForm, Form):
pass
def validate_recaptcha(remote_ip, challenge, response):
# Request validation from recaptcha.net
if challenge:
params = urllib.urlencode(dict(privatekey=settings.RECAPTCHA_PRIVATE_KEY,
remoteip=remote_ip,
challenge=challenge,
response=response))
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
conn = httplib.HTTPConnection("api-verify.recaptcha.net")
conn.request("POST", "/verify", params, headers)
response = conn.getresponse()
if response.status == 200:
data = response.read()
else:
data = ''
conn.close()
# Validate based on response data
result = data.startswith('true')
error_code = ''
if not result:
bits = data.split('\n', 2)
if len(bits) > 1:
error_code = bits[1]
# Return dictionary
return dict(result=result,
error_code=error_code)
|