87
|
1 #!/usr/bin/env python
|
|
2 #
|
|
3 # An example that presents CAPTCHA tests in a web environment
|
|
4 # and gives the user a chance to solve them. Run it, optionally
|
|
5 # specifying a port number on the command line, then point your web
|
|
6 # browser at the given URL.
|
|
7 #
|
|
8
|
|
9 from Captcha.Visual import Tests
|
|
10 from Captcha import Factory
|
|
11 import BaseHTTPServer, urlparse, sys
|
|
12
|
|
13
|
|
14 class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|
15 def do_GET(self):
|
|
16 scheme, host, path, parameters, query, fragment = urlparse.urlparse(self.path)
|
|
17
|
|
18 # Split the path into segments
|
|
19 pathSegments = path.split('/')[1:]
|
|
20
|
|
21 # Split the query into key-value pairs
|
|
22 args = {}
|
|
23 for pair in query.split("&"):
|
|
24 if pair.find("=") >= 0:
|
|
25 key, value = pair.split("=", 1)
|
|
26 args.setdefault(key, []).append(value)
|
|
27 else:
|
|
28 args[pair] = []
|
|
29
|
|
30 # A hack so it works with a proxy configured for VHostMonster :)
|
|
31 if pathSegments[0] == "vhost":
|
|
32 pathSegments = pathSegments[3:]
|
|
33
|
|
34 if pathSegments[0] == "":
|
|
35 self.handleRootPage(args.get('test', Tests.__all__)[0])
|
|
36
|
|
37 elif pathSegments[0] == "images":
|
|
38 self.handleImagePage(pathSegments[1])
|
|
39
|
|
40 elif pathSegments[0] == "solutions":
|
|
41 self.handleSolutionPage(pathSegments[1], args['word'][0])
|
|
42
|
|
43 else:
|
|
44 self.handle404()
|
|
45
|
|
46 def handle404(self):
|
|
47 self.send_response(404)
|
|
48 self.send_header("Content-Type", "text/html")
|
|
49 self.end_headers()
|
|
50 self.wfile.write("<html><body><h1>No such resource</h1></body></html>")
|
|
51
|
|
52 def handleRootPage(self, testName):
|
|
53 self.send_response(200)
|
|
54 self.send_header("Content-Type", "text/html")
|
|
55 self.end_headers()
|
|
56
|
|
57 test = self.captchaFactory.new(getattr(Tests, testName))
|
|
58
|
|
59 # Make a list of tests other than the one we're using
|
|
60 others = []
|
|
61 for t in Tests.__all__:
|
|
62 if t != testName:
|
|
63 others.append('<li><a href="/?test=%s">%s</a></li>' % (t,t))
|
|
64 others = "\n".join(others)
|
|
65
|
|
66 self.wfile.write("""<html>
|
|
67 <head>
|
|
68 <title>PyCAPTCHA Example</title>
|
|
69 </head>
|
|
70 <body>
|
|
71 <h1>PyCAPTCHA Example</h1>
|
|
72 <p>
|
|
73 <b>%s</b>:
|
|
74 %s
|
|
75 </p>
|
|
76
|
|
77 <p><img src="/images/%s"/></p>
|
|
78 <p>
|
|
79 <form action="/solutions/%s" method="get">
|
|
80 Enter the word shown:
|
|
81 <input type="text" name="word"/>
|
|
82 </form>
|
|
83 </p>
|
|
84
|
|
85 <p>
|
|
86 Or try...
|
|
87 <ul>
|
|
88 %s
|
|
89 </ul>
|
|
90 </p>
|
|
91
|
|
92 </body>
|
|
93 </html>
|
|
94 """ % (test.__class__.__name__, test.__doc__, test.id, test.id, others))
|
|
95
|
|
96 def handleImagePage(self, id):
|
|
97 test = self.captchaFactory.get(id)
|
|
98 if not test:
|
|
99 return self.handle404()
|
|
100
|
|
101 self.send_response(200)
|
|
102 self.send_header("Content-Type", "image/jpeg")
|
|
103 self.end_headers()
|
|
104 test.render().save(self.wfile, "JPEG")
|
|
105
|
|
106 def handleSolutionPage(self, id, word):
|
|
107 test = self.captchaFactory.get(id)
|
|
108 if not test:
|
|
109 return self.handle404()
|
|
110
|
|
111 if not test.valid:
|
|
112 # Invalid tests will always return False, to prevent
|
|
113 # random trial-and-error attacks. This could be confusing to a user...
|
|
114 result = "Test invalidated, try another test"
|
|
115 elif test.testSolutions([word]):
|
|
116 result = "Correct"
|
|
117 else:
|
|
118 result = "Incorrect"
|
|
119
|
|
120 self.send_response(200)
|
|
121 self.send_header("Content-Type", "text/html")
|
|
122 self.end_headers()
|
|
123 self.wfile.write("""<html>
|
|
124 <head>
|
|
125 <title>PyCAPTCHA Example</title>
|
|
126 </head>
|
|
127 <body>
|
|
128 <h1>PyCAPTCHA Example</h1>
|
|
129 <h2>%s</h2>
|
|
130 <p><img src="/images/%s"/></p>
|
|
131 <p><b>%s</b></p>
|
|
132 <p>You guessed: %s</p>
|
|
133 <p>Possible solutions: %s</p>
|
|
134 <p><a href="/">Try again</a></p>
|
|
135 </body>
|
|
136 </html>
|
|
137 """ % (test.__class__.__name__, test.id, result, word, ", ".join(test.solutions)))
|
|
138
|
|
139
|
|
140 def main(port):
|
|
141 print "Starting server at http://localhost:%d/" % port
|
|
142 handler = RequestHandler
|
|
143 handler.captchaFactory = Factory()
|
|
144 BaseHTTPServer.HTTPServer(('', port), RequestHandler).serve_forever()
|
|
145
|
|
146 if __name__ == "__main__":
|
|
147 # The port number can be specified on the command line, default is 8080
|
|
148 if len(sys.argv) >= 2:
|
|
149 port = int(sys.argv[1])
|
|
150 else:
|
|
151 port = 8080
|
|
152 main(port)
|
|
153
|
|
154 ### The End ###
|