Last active
January 15, 2016 19:23
-
-
Save tfoote/675b98df53369e199dea to your computer and use it in GitHub Desktop.
This is the diff to add recaptcha to moin moin 1.9.7
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/PageEditor.py b/PageEditor.py | |
index 83a6505..a6dab02 100755 | |
--- a/PageEditor.py | |
+++ b/PageEditor.py | |
@@ -420,6 +420,9 @@ If you don't want that, hit '''%(cancel_button_text)s''' to cancel your changes. | |
from MoinMoin.security.textcha import TextCha | |
request.write(TextCha(request).render()) | |
+ from MoinMoin.security.sec_recaptcha import ReCaptcha | |
+ request.write(ReCaptcha(request).render()) | |
+ | |
# Add textarea with page text | |
self.sendconfirmleaving() | |
diff --git a/PageGraphicalEditor.py b/PageGraphicalEditor.py | |
index 0a39fb8..7e40c17 100755 | |
--- a/PageGraphicalEditor.py | |
+++ b/PageGraphicalEditor.py | |
@@ -305,6 +305,9 @@ If you don't want that, hit '''%(cancel_button_text)s''' to cancel your changes. | |
from MoinMoin.security.textcha import TextCha | |
request.write(TextCha(request).render()) | |
+ from MoinMoin.security.sec_recaptcha import ReCaptcha | |
+ request.write(ReCaptcha(request).render()) | |
+ | |
self.sendconfirmleaving() # TODO update state of flgChange to make this work, see PageEditor | |
# Add textarea with page text | |
diff --git a/action/AttachFile.py b/action/AttachFile.py | |
index 2df164b..b7fd63f 100755 | |
--- a/action/AttachFile.py | |
+++ b/action/AttachFile.py | |
@@ -43,6 +43,7 @@ from MoinMoin import config, packages | |
from MoinMoin.Page import Page | |
from MoinMoin.util import filesys, timefuncs | |
from MoinMoin.security.textcha import TextCha | |
+from MoinMoin.security.sec_recaptcha import ReCaptcha | |
from MoinMoin.events import FileAttachedEvent, FileRemovedEvent, send_event | |
from MoinMoin.support import tarfile | |
@@ -484,6 +485,7 @@ def send_uploadform(pagename, request): | |
<dd><input type="checkbox" name="overwrite" value="1" %(overwrite_checked)s></dd> | |
</dl> | |
%(textcha)s | |
+%(recaptcha)s | |
<p> | |
<input type="hidden" name="action" value="%(action_name)s"> | |
<input type="hidden" name="do" value="upload"> | |
@@ -501,6 +503,7 @@ def send_uploadform(pagename, request): | |
'overwrite_checked': ('', 'checked')[request.form.get('overwrite', '0') == '1'], | |
'upload_button': _('Upload'), | |
'textcha': TextCha(request).render(), | |
+ 'recaptcha': ReCaptcha(request).render(), | |
'ticket': wikiutil.createTicket(request), | |
}) | |
@@ -558,6 +561,8 @@ def _do_upload(pagename, request): | |
# but it could be extended to more/all attachment write access | |
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...') | |
form = request.form | |
diff --git a/action/CopyPage.py b/action/CopyPage.py | |
index c2b151a..d47879b 100755 | |
--- a/action/CopyPage.py | |
+++ b/action/CopyPage.py | |
@@ -14,6 +14,7 @@ from MoinMoin.Page import Page | |
from MoinMoin.PageEditor import PageEditor | |
from MoinMoin.action import ActionBase | |
from MoinMoin.security.textcha import TextCha | |
+from MoinMoin.security.sec_recaptcha import ReCaptcha | |
class CopyPage(ActionBase): | |
""" Copy page action | |
@@ -45,11 +46,14 @@ class CopyPage(ActionBase): | |
def do_action(self): | |
""" copy this page to "pagename" """ | |
+ status = False | |
_ = self._ | |
# Currently we only check TextCha for upload (this is what spammers ususally do), | |
# but it could be extended to more/all attachment write access | |
if not TextCha(self.request).check_answer_from_form(): | |
return status, _('TextCha: Wrong answer! Go back and try again...') | |
+ if not ReCaptcha(self.request).check_answer_from_form(): | |
+ return status, _('ReCaptcha: Wrong answer! Go back and try again...') | |
form = self.form | |
newpagename = form.get('newpagename', u'') | |
@@ -90,6 +94,7 @@ class CopyPage(ActionBase): | |
d = { | |
'textcha': TextCha(self.request).render(), | |
+ 'recaptcha': ReCaptcha(self.request).render(), | |
'subpage': subpages, | |
'subpages_checked': ('', 'checked')[self.request.args.get('subpages_checked', '0') == '1'], | |
'subpage_label': _('Copy all /subpages too?'), | |
@@ -105,6 +110,7 @@ class CopyPage(ActionBase): | |
<br> | |
<br> | |
%(textcha)s | |
+%(recaptcha)s | |
<table> | |
<tr> | |
<dd> | |
@@ -140,6 +146,7 @@ class CopyPage(ActionBase): | |
else: | |
d = { | |
'textcha': TextCha(self.request).render(), | |
+ 'recaptcha': ReCaptcha(self.request).render(), | |
'pagename': wikiutil.escape(self.pagename, True), | |
'newname_label': _("New name"), | |
'comment_label': _("Optional reason for the copying"), | |
@@ -147,6 +154,7 @@ class CopyPage(ActionBase): | |
} | |
return ''' | |
%(textcha)s | |
+%(recaptcha)s | |
<table> | |
<tr> | |
<td class="label"><label>%(newname_label)s</label></td> | |
diff --git a/action/Load.py b/action/Load.py | |
index 2d71f8b..1b168dc 100755 | |
--- a/action/Load.py | |
+++ b/action/Load.py | |
@@ -14,6 +14,7 @@ from MoinMoin.action import ActionBase, AttachFile | |
from MoinMoin.PageEditor import PageEditor | |
from MoinMoin.Page import Page | |
from MoinMoin.security.textcha import TextCha | |
+from MoinMoin.security.sec_recaptcha import ReCaptcha | |
class Load(ActionBase): | |
""" Load page action | |
@@ -40,6 +41,8 @@ class Load(ActionBase): | |
# but it could be extended to more/all attachment write access | |
if not TextCha(request).check_answer_from_form(): | |
return status, _('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...') | |
comment = form.get('comment', u'') | |
comment = wikiutil.clean_input(comment) | |
@@ -97,6 +100,7 @@ class Load(ActionBase): | |
<dd><input type="text" name="comment" size="80" maxlength="200"></dd> | |
</dl> | |
%(textcha)s | |
+%(recaptcha)s | |
<p> | |
<input type="hidden" name="action" value="%(action_name)s"> | |
<input type="hidden" name="do" value="upload"> | |
@@ -115,6 +119,7 @@ class Load(ActionBase): | |
'buttons_html': buttons_html, | |
'action_name': self.form_trigger, | |
'textcha': TextCha(self.request).render(), | |
+ 'recaptcha': ReCaptcha(self.request).render(), | |
} | |
def execute(pagename, request): | |
diff --git a/action/edit.py b/action/edit.py | |
index e8fc23a..ea5b08b 100755 | |
--- a/action/edit.py | |
+++ b/action/edit.py | |
@@ -161,6 +161,9 @@ def execute(pagename, request): | |
from MoinMoin.security.textcha import TextCha | |
if not TextCha(request).check_answer_from_form(): | |
raise pg.SaveError(_('TextCha: Wrong answer! Try again below...')) | |
+ from MoinMoin.security.sec_recaptcha import ReCaptcha | |
+ if not ReCaptcha(request).check_answer_from_form(): | |
+ raise pg.SaveError(_('ReCaptcha: Wrong answer! Try again below...')) | |
if request.cfg.comment_required and not comment: | |
raise pg.SaveError(_('Supplying a comment is mandatory. Write a comment below and try again...')) | |
savemsg = pg.saveText(savetext, rev, trivial=trivial, comment=comment) | |
diff --git a/action/newaccount.py b/action/newaccount.py | |
index 4643b50..a5fae37 100755 | |
--- a/action/newaccount.py | |
+++ b/action/newaccount.py | |
@@ -10,6 +10,7 @@ from MoinMoin import user, wikiutil | |
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 @@ def _create_user(request): | |
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") | |
@@ -134,7 +138,7 @@ def _create_form(request): | |
textcha = TextCha(request) | |
if textcha.is_enabled(): | |
row = html.TR() | |
- tbl.append(row) | |
+ tbl.append(row) | |
row.append(html.TD().append(html.STRONG().append( | |
html.Text(_('TextCha (required)'))))) | |
td = html.TD() | |
@@ -142,6 +146,17 @@ def _create_form(request): | |
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()) | |
diff --git a/security/sec_recaptcha.py b/security/sec_recaptcha.py | |
new file mode 100644 | |
index 0000000..37dfdd7 | |
--- /dev/null | |
+++ b/security/sec_recaptcha.py | |
@@ -0,0 +1,74 @@ | |
+# -*- 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 | |
+ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment