Package: python-moinmoin
Version: 1.9.3-1
Severity: wishlist
Tags: patch

Hi,

I've added simple support for using recaptcha, similar in design to
the existing textcha. So far I've only added this for the "newaccount"
action, but this could be extended to other actions if desired.

I've sent a patch upstream to the Moin folks (see
http://sourceforge.net/mailarchive/message.php?msg_id=27933760); the
one attached here is functionally the same, just slightly cleaned
up. This would also necessitate a Depends: on python-recaptcha.

Please consider this quickly - I've developed this recaptcha support
because we would like to use it for wiki.d.o. A backport of a version
in testing including this support would be ideal for us! :-)

-- System Information:
Debian Release: 6.0.2
  APT prefers stable
  APT policy: (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.32-5-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages python-moinmoin depends on:
ii  python                  2.6.6-3+squeeze6 interactive high-level object-orie
ii  python-parsedatetime    0.8.7-2          Python module to parse human-reada
ii  python-pygments         1.3.1+dfsg-1     syntax highlighting package writte
ii  python-support          1.0.10           automated rebuilding support for P
ii  python-werkzeug         0.6.2-1          collection of utilities for WSGI a

Versions of packages python-moinmoin recommends:
ii  apache2-mpm-worker [ht 2.2.16-6+squeeze1 Apache HTTP Server - high speed th
ii  exim4-daemon-light [ma 4.72-6+squeeze2   lightweight Exim MTA (v4) daemon
ii  fckeditor              1:2.6.6-1         rich text format javascript web ed
ii  python-xapian          1.2.3-3           Xapian search engine interface for
ii  python-xappy           0.5-4             easy-to-use interface to the Xapia

Versions of packages python-moinmoin suggests:
ii  antiword                  0.37-6         Converts MS Word files to text, PS
pn  catdoc                    <none>         (no description available)
pn  docbook-dsssl             <none>         (no description available)
ii  miscfiles [wordlist]      1.4.2.dfsg.1-9 Dictionaries and other interesting
ii  poppler-utils [xpdf-utils 0.12.4-1.2     PDF utilitites (based on libpopple
pn  python-4suite-xml         <none>         (no description available)
pn  python-docutils           <none>         (no description available)
pn  python-flup               <none>         (no description available)
pn  python-gdchart            <none>         (no description available)
pn  python-ldap               <none>         (no description available)
pn  python-mysqldb            <none>         (no description available)
pn  python-openid             <none>         (no description available)
pn  python-pyxmpp             <none>         (no description available)
ii  python-tz                 2010b-1        Python version of the Olson timezo
pn  python-xml                <none>         (no description available)
pn  smbfs                     <none>         (no description available)
ii  wamerican [wordlist]      6-3            American English dictionary words 
ii  wbritish [wordlist]       6-3            British English dictionary words f

-- Configuration Files:
/etc/moin/mywiki.py changed [not included]

-- no debconf information
diff -uNrBb --exclude support --exclude _tests --exclude i18n ./action/newaccount.py /usr/share/pyshared/MoinMoin/action/newaccount.py
--- ./action/newaccount.py	2010-06-26 22:46:40.000000000 +0100
+++ /usr/share/pyshared/MoinMoin/action/newaccount.py	2011-08-11 15:34:58.053890100 +0100
@@ -10,6 +10,7 @@
 from MoinMoin.Page import Page
 from MoinMoin.widget import html
 from MoinMoin.security.textcha import TextCha
+from MoinMoin.security.sec_recaptcha import ReCaptcha
 from MoinMoin.auth import MoinAuth
 
 
@@ -26,6 +27,9 @@
     if not TextCha(request).check_answer_from_form():
         return _('TextCha: Wrong answer! Go back and try again...')
 
+    if not ReCaptcha(request).check_answer_from_form():
+        return _('ReCaptcha: Wrong answer! Go back and try again...')
+
     # Create user profile
     theuser = user.User(request, auth_method="new-user")
 
@@ -143,6 +147,17 @@
             td.append(textcha.render())
         row.append(td)
 
+    recaptcha = ReCaptcha(request)
+    if recaptcha.is_enabled():
+        row = html.TR()
+        tbl.append(row)
+        row.append(html.TD().append(html.STRONG().append(
+                                      html.Text(_('ReCaptcha (required)')))))
+        td = html.TD()
+        if recaptcha:
+            td.append(recaptcha.render())
+        row.append(td)        
+
     row = html.TR()
     tbl.append(row)
     row.append(html.TD())
--- ./security/sec_recaptcha.py	1970-01-01 01:00:00.000000000 +0100
+++ /usr/share/pyshared/MoinMoin/security/sec_recaptcha.py	2011-08-15 14:11:40.944626628 +0100
@@ -0,0 +1,73 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - recaptcha support
+
+    Based heavily on the textcha support in textcha.py
+
+    @copyright: 2011 by Steve McIntyre
+    @license: GNU GPL, see COPYING for details.
+"""
+
+from MoinMoin import log
+from recaptcha.client import captcha
+import sys
+
+logging = log.getLogger(__name__)
+
+from MoinMoin import wikiutil
+
+class ReCaptcha(object):
+    """ Recaptcha support """
+
+    def __init__(self, request):
+        """ Initialize the Recaptcha setup.
+
+            @param request: the request object
+        """
+        self.request = request
+        self.user_info = request.user.valid and request.user.name or request.remote_addr
+        cfg = request.cfg
+
+        try:
+            if cfg.recaptcha_public_key:
+                self.public_key = cfg.recaptcha_public_key
+            if cfg.recaptcha_private_key:
+                self.private_key = cfg.recaptcha_private_key
+        except:
+            self.public_key = None
+            self.private_key = None
+
+    def is_enabled(self):
+        """ check if we're configured, i.e. we have a key
+        """
+        if (self.public_key and self.private_key):
+            return True
+        return False
+
+    def check_answer_from_form(self, form=None):
+        if self.is_enabled():
+            if form is None:
+                form = self.request.form
+            challenge = form.get('recaptcha_challenge_field')
+            response = form.get('recaptcha_response_field')
+            captcha_result = captcha.submit(challenge, response, self.private_key, self.request.remote_addr)
+            if captcha_result.is_valid:
+                logging.info(u"ReCaptcha: OK.")
+                return True
+            else:
+                logging.info(u"ReCaptcha: failed, error code %s." % captcha_result.error_code)
+                return False
+        else:
+            return True
+
+    def render(self, form=None):
+        """ Checks if ReCaptchas are enabled and returns HTML for one,
+            or an empty string if they are not enabled.
+
+            @return: unicode result html
+        """
+        if self.is_enabled():
+            result = captcha.displayhtml(self.public_key, use_ssl = True)
+        else:
+            result = u''
+        return result

Reply via email to