view captchamiddleware/middleware.py @ 0:21ec6325ae0e

initial import of CAPTCHA middleware; unfinished
author k0s <k0scist@gmail.com>
date Sun, 24 Jan 2010 23:15:57 -0500
parents
children 478d13061336
line wrap: on
line source

"""
CAPTCHA middleware
"""

import os
import random
import sys
from lxml import etree
from lxmlmiddleware import LXMLMiddleware
from skimpyGimpy import skimpyAPI
from urllib2 import urlopen
from webob import Request, exc


class CAPTCHAmiddleware(LXMLMiddleware):
    """
    put CAPTCHAs on forms for unauthorized users
    """

    ### class level variables
    defaults = { 
                 'dictionary': '/usr/share/dict/words',
                 'error': '<span class="error">Please type the CAPTCHA</span>',
                 'minimum_length': 5, 
                 'path': "/input[@type='submit']",
                 }

    def __init__(self, app, **kw):
        self.app = app

        # set instance parameters from kw and defaults
        for key in self.defaults:
            setattr(self, key, kw.get(key, self.defaults[key]))
        self.minimum_length = int(self.minimum_length)
        assert os.path.exists(self.dictionary)
        
        # get dictionary
        if self.dictionary.startswith('http://') or self.dictionary.startswith('https://'):
            f = urlopen(self.dictionary)
        else:
            f = file(self.dictionary)
        self.words = [ i.strip() for i in f.readlines()
                       if len(i.strip()) > self.minimum_length ]
        random.shuffle(self.words)


    def __call__(self, environ, start_response):
        request = Request(environ)
        if request.method == 'post' and not request.remote_user:
            pass # TODO: check CAPTCHA

        return LXMLMiddleware.__call__(self, environ, start_response)

    def manipulate(self, environ, tree):
        """manipulate the DOM; should return an etree._Element"""

        request = Request(environ)

        # don't use CAPTCHAs for authorized users
        if request.remote_user:
            return tree 

        for element in tree.findall(".//form[@method='post']"):
            key = random.Random().randint(0, len(self.words))
            word = self.words[key]
            captcha = skimpyAPI.Pre(word).data()
            string = '<div class="captcha">%s<input type="hidden" value="%s"/></div>' % (captcha, key)
            addition = etree.fromstring(string)
            insertion_point = element.find('.' + self.path)
            insertion_point.addprevious(addition)

        return tree