Mercurial > repos > other > IBBCaptcha
changeset 0:51a744916b4f default tip
Basic dictionary CAPTCHA
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sat, 10 Aug 2013 11:00:42 +0000 |
parents | |
children | |
files | ibbcaptcha/__init__.py ibbcaptcha/register.py ibbcaptcha/templates/captcha.html ibbcaptcha/utils.py setup.py |
diffstat | 5 files changed, 218 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ibbcaptcha/__init__.py Sat Aug 10 11:00:42 2013 +0000 @@ -0,0 +1,2 @@ +# +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ibbcaptcha/register.py Sat Aug 10 11:00:42 2013 +0000 @@ -0,0 +1,124 @@ +""" +A quick and dirty captcha for use with AccountManagerPlugin registration +""" +# Plugin for trac 0.11 + +from acct_mgr.web_ui import RegistrationModule + +from componentdependencies import IRequireComponents + +from genshi.builder import Markup +from genshi.builder import tag +from genshi.filters.transform import Transformer + +from trac.config import Option +from trac.core import * +from trac.web import IRequestFilter +from trac.web import ITemplateStreamFilter +from trac.web.api import IRequestHandler +from trac.web.chrome import add_warning + +from utils import random_word + +class RegistrationCaptcha(Component): + + ### class data + implements(IRequestFilter, ITemplateStreamFilter, IRequireComponents) + dict_file = Option('ibbcaptcha', 'dictionary_file', + default="http://java.sun.com/docs/books/tutorial/collections/interfaces/examples/dictionary.txt") + + + ### IRequestFilter methods + + def pre_process_request(self, req, handler): + """Called after initial handler selection, and can be used to change + the selected handler or redirect request. + + Always returns the request handler, even if unchanged. + """ + + if req.path_info.strip('/') == "register": + + if req.method == "POST": + correct_answer = req.session.pop('captcha', None) + req.session.save() + if req.args['captcha'].lower() != correct_answer: + req.session['ibbcaptcha_message'] = "You typed the wrong word. Please try again." + req.session.save() + req.redirect(req.href('register')) + if req.method == "GET": + message = req.session.pop('ibbcaptcha_message', None) + if message: + add_warning(req, message) + + return handler + + # for ClearSilver templates + def post_process_request(self, req, template, content_type): + """Do any post-processing the request might need; typically adding + values to req.hdf, or changing template or mime type. + + Always returns a tuple of (template, content_type), even if + unchanged. + + Note that `template`, `content_type` will be `None` if: + - called when processing an error page + - the default request handler did not return any result + + (for 0.10 compatibility; only used together with ClearSilver templates) + """ + return (template, content_type) + + # for Genshi templates + def post_process_request(self, req, template, data, content_type): + """Do any post-processing the request might need; typically adding + values to the template `data` dictionary, or changing template or + mime type. + + `data` may be update in place. + + Always returns a tuple of (template, data, content_type), even if + unchanged. + + Note that `template`, `data`, `content_type` will be `None` if: + - called when processing an error page + - the default request handler did not return any result + + (Since 0.11) + """ + return (template, data, content_type) + + + ### ITemplateStreamFilter method + + def filter_stream(self, req, method, filename, stream, data): + """Return a filtered Genshi event stream, or the original unfiltered + stream if no match. + + `req` is the current request object, `method` is the Genshi render + method (xml, xhtml or text), `filename` is the filename of the template + to be rendered, `stream` is the event stream and `data` is the data for + the current template. + + See the Genshi documentation for more information. + """ + # move these someplace sensible? + form_id = "acctmgr_registerform" # id of the registration form + msg = "Please enter the text below to prove you're not a machine." + + if filename == "register.html": + word = random_word(self.dict_file) + req.session['captcha'] = word + req.session.save() + captcha = word + content = "<p>%s</p><p>%s</p>" % (msg, captcha) + content += '<label>Confirm: <input type="text" name="captcha" class="textwidget" size="20"/></label>' + stream |= Transformer('//form[@id="%s"]/fieldset[1]' % form_id).append(tag.div(Markup(content))) + + return stream + + ### method for IRequireComponents + + def requires(self): + """list of component classes that this component depends on""" + return [RegistrationModule]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ibbcaptcha/templates/captcha.html Sat Aug 10 11:00:42 2013 +0000 @@ -0,0 +1,29 @@ +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/" + py:strip="True"> + <fieldset> + + <div> + <label>Name: + <input type="text" name="name" class="textwidget" size="20" value="${name}"/> + </label> + </div> + + <div> + <label>Email: + <input type="text" name="email" class="textwidget" size="20" value="${email}"/> + </label> + </div> + + <div> + <p> + Please enter the text below to prove you're not a machine. + </p> + <p> + ${captcha} + </p> + <label>Confirm: <input type="text" name="ibbcaptcha" class="textwidget" size="20"/></label> + </div> + <input type="hidden" name="captchaid" value="${captchaid}"/> + </fieldset> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ibbcaptcha/utils.py Sat Aug 10 11:00:42 2013 +0000 @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +import random +import urllib + +class WordChooser(object): + """chose a random word given a dict file""" + wordlist = [] + def __init__(self, dictfile, min_len=5): + if not getattr(WordChooser, 'dictfile', '') == dictfile: + if dictfile.startswith("http://"): + f = urllib.urlopen(dictfile) + else: + f = open(dictfile, 'r') + _dict = f.read() + f.close() + _dict = _dict.lower().split() + _dict = [word for word in _dict if word.isalpha() and len(word) > min_len] + WordChooser.wordlist = _dict + WordChooser.dictfile = dictfile + + def __call__(self): + return random.Random().choice(self.wordlist) + +def random_word(dictfile): + chooser = WordChooser(dictfile) + return chooser() + + +if __name__ == '__main__': + foo = WordChooser('http://java.sun.com/docs/books/tutorial/collections/interfaces/examples/dictionary.txt') + print foo() +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup.py Sat Aug 10 11:00:42 2013 +0000 @@ -0,0 +1,30 @@ +from setuptools import find_packages, setup + +version='0.1' + +setup(name='IBBCaptcha', + version=version, + description="Simple text-based CAPTCHA check for registration", + author='IBBoard', + author_email='dev@ibboard.co.uk', + url='http://ibboard.co.uk', + keywords='trac plugin', + license="GPL", + packages=find_packages(exclude=['ez_setup', 'examples', 'tests*']), + include_package_data=True, + package_data={ 'ibbcaptcha': ['templates/*', ] }, + zip_safe=False, + install_requires=[ + 'Trac', + 'TracAccountManager', + 'ComponentDependencyPlugin', + ], + dependency_links=[ + "http://trac-hacks.org/svn/componentdependencyplugin/0.11#egg=ComponentDependencyPlugin", + ], + entry_points = """ + [trac.plugins] + registration_captcha = ibbcaptcha.register + """, + ) +