changeset 7239:44f7f73da4a6

recaptcha: Update to Google recaptcha API v2 (Issue #313) Recaptcha stopped working. It was using google recaptcha v1, and https://developers.google.com/recaptcha/docs/faq says: "Any calls to the v1 API will not work after March 31, 2018." Note: 1) Not using 'async defer' - it's not used anywhere else, plus I have no idea of what exactly it does. 2) The recaptcha div has an ID so the label for="recaptcha_field" can reference it (although I'm not certain a div can technically have a label, but it's better than removing the label, or the for="").
author Patrick Vane <patrick_vane@lowentry.com>
date Tue, 03 Apr 2018 16:20:05 +0200
parents 70262a0dca6b
children bfb6a25ecbd5
files kallithea/controllers/login.py kallithea/lib/recaptcha.py kallithea/templates/password_reset.html kallithea/templates/register.html
diffstat 4 files changed, 34 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/controllers/login.py	Tue Apr 03 16:20:05 2018 +0200
+++ b/kallithea/controllers/login.py	Tue Apr 03 16:20:05 2018 +0200
@@ -133,11 +133,10 @@
 
                 if c.captcha_active:
                     from kallithea.lib.recaptcha import submit
-                    response = submit(request.POST.get('recaptcha_challenge_field'),
-                                      request.POST.get('recaptcha_response_field'),
+                    response = submit(request.POST.get('g-recaptcha-response'),
                                       private_key=captcha_private_key,
                                       remoteip=request.ip_addr)
-                    if c.captcha_active and not response.is_valid:
+                    if not response.is_valid:
                         _value = form_result
                         _msg = _('Bad captcha')
                         error_dict = {'recaptcha_field': _msg}
@@ -179,11 +178,10 @@
                 form_result = password_reset_form.to_python(dict(request.POST))
                 if c.captcha_active:
                     from kallithea.lib.recaptcha import submit
-                    response = submit(request.POST.get('recaptcha_challenge_field'),
-                                      request.POST.get('recaptcha_response_field'),
+                    response = submit(request.POST.get('g-recaptcha-response'),
                                       private_key=captcha_private_key,
                                       remoteip=request.ip_addr)
-                    if c.captcha_active and not response.is_valid:
+                    if not response.is_valid:
                         _value = form_result
                         _msg = _('Bad captcha')
                         error_dict = {'recaptcha_field': _msg}
--- a/kallithea/lib/recaptcha.py	Tue Apr 03 16:20:05 2018 +0200
+++ b/kallithea/lib/recaptcha.py	Tue Apr 03 16:20:05 2018 +0200
@@ -1,10 +1,7 @@
 # -*- coding: utf-8 -*-
 import urllib
 import urllib2
-
-API_SSL_SERVER = "https://www.google.com/recaptcha/api"
-API_SERVER = "http://www.google.com/recaptcha/api"
-VERIFY_SERVER = "www.google.com"
+import json
 
 
 class RecaptchaResponse(object):
@@ -16,23 +13,17 @@
         return '<RecaptchaResponse:%s>' % (self.is_valid)
 
 
-def submit(recaptcha_challenge_field, recaptcha_response_field, private_key,
-           remoteip):
+def submit(g_recaptcha_response, private_key, remoteip):
     """
-    Submits a reCAPTCHA request for verification. Returns RecaptchaResponse
-    for the request
+    Submits a reCAPTCHA request for verification. Returns RecaptchaResponse for the request
 
-    recaptcha_challenge_field -- The value of recaptcha_challenge_field from the form
-    recaptcha_response_field -- The value of recaptcha_response_field from the form
+    g_recaptcha_response -- The value of g_recaptcha_response from the form
     private_key -- your reCAPTCHA private key
     remoteip -- the user's IP address
     """
 
-    if not (recaptcha_response_field and recaptcha_challenge_field and
-                len(recaptcha_response_field) and len(
-            recaptcha_challenge_field)):
-        return RecaptchaResponse(is_valid=False,
-                                 error_code='incorrect-captcha-sol')
+    if not (g_recaptcha_response and len(g_recaptcha_response)):
+        return RecaptchaResponse(is_valid=False, error_code='incorrect-captcha-sol')
 
     def encode_if_necessary(s):
         if isinstance(s, unicode):
@@ -40,14 +31,13 @@
         return s
 
     params = urllib.urlencode({
-        'privatekey': encode_if_necessary(private_key),
+        'secret': encode_if_necessary(private_key),
         'remoteip': encode_if_necessary(remoteip),
-        'challenge': encode_if_necessary(recaptcha_challenge_field),
-        'response': encode_if_necessary(recaptcha_response_field),
+        'response': encode_if_necessary(g_recaptcha_response),
     })
 
     req = urllib2.Request(
-        url="http://%s/recaptcha/api/verify" % VERIFY_SERVER,
+        url="https://www.google.com/recaptcha/api/siteverify",
         data=params,
         headers={
             "Content-type": "application/x-www-form-urlencoded",
@@ -56,13 +46,14 @@
     )
 
     httpresp = urllib2.urlopen(req)
-
-    return_values = httpresp.read().splitlines()
+    return_values = json.loads(httpresp.read())
     httpresp.close()
 
-    return_code = return_values[0]
-
-    if return_code == "true":
+    if not (isinstance(return_values, dict)):
+        return RecaptchaResponse(is_valid=False, error_code='incorrect-captcha-sol')
+    elif (("success" in return_values) and ((return_values["success"] == True) or (return_values["success"] == "true"))):
         return RecaptchaResponse(is_valid=True)
+    elif (("error-codes" in return_values) and isinstance(return_values["error-codes"], list) and (len(return_values["error-codes"]) > 0)):
+        return RecaptchaResponse(is_valid=False, error_code=return_values["error-codes"][0])
     else:
-        return RecaptchaResponse(is_valid=False, error_code=return_values[1])
+        return RecaptchaResponse(is_valid=False, error_code='incorrect-captcha-sol')
--- a/kallithea/templates/password_reset.html	Tue Apr 03 16:20:05 2018 +0200
+++ b/kallithea/templates/password_reset.html	Tue Apr 03 16:20:05 2018 +0200
@@ -5,6 +5,12 @@
     ${_('Password Reset')}
 </%block>
 
+<%block name="js_extra">
+    %if c.captcha_active:
+        <script type="text/javascript" src="https://www.google.com/recaptcha/api.js"></script>
+    %endif
+</%block>
+
 <%include file="/base/flash_msg.html"/>
 <div class="container">
 <div class="row">
@@ -31,8 +37,7 @@
                 <div class="form-group">
                     <label class="control-label" for="recaptcha_field">${_('Captcha')}:</label>
                     <div>
-                        ${h.hidden('recaptcha_field')}
-                        <div id="recaptcha"></div>
+                        <div id="recaptcha_field" class="g-recaptcha" data-sitekey="${c.captcha_public_key}"></div>
                     </div>
                 </div>
                 %endif
@@ -48,19 +53,9 @@
                 </div>
         </div>
         ${h.end_form()}
-        %if c.captcha_active:
-        <script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
-        %endif
         <script type="text/javascript">
          $(document).ready(function(){
             $('#email').focus();
-            %if c.captcha_active:
-            Recaptcha.create(${h.js(c.captcha_public_key)}, "recaptcha",
-                {
-                  theme: "white"
-                }
-            );
-            %endif
          });
         </script>
     </div>
--- a/kallithea/templates/register.html	Tue Apr 03 16:20:05 2018 +0200
+++ b/kallithea/templates/register.html	Tue Apr 03 16:20:05 2018 +0200
@@ -5,6 +5,12 @@
     ${_('Sign Up')}
 </%block>
 
+<%block name="js_extra">
+    %if c.captcha_active:
+        <script type="text/javascript" src="https://www.google.com/recaptcha/api.js"></script>
+    %endif
+</%block>
+
 <%include file="/base/flash_msg.html"/>
 
 <div class="container">
@@ -67,8 +73,7 @@
                 <div class="form-group">
                     <label class="control-label" for="recaptcha_field">${_('Captcha')}:</label>
                     <div>
-                        ${h.hidden('recaptcha_field')}
-                        <div id="recaptcha"></div>
+                        <div id="recaptcha_field" class="g-recaptcha" data-sitekey="${c.captcha_public_key}"></div>
                     </div>
                 </div>
                 %endif
@@ -85,20 +90,9 @@
                 </div>
         </div>
         ${h.end_form()}
-        %if c.captcha_active:
-        <script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
-        %endif
         <script type="text/javascript">
         $(document).ready(function(){
             $('#username').focus();
-
-            %if c.captcha_active:
-            Recaptcha.create(${h.js(c.captcha_public_key)}, "recaptcha",
-                {
-                  theme: "white"
-                }
-            );
-            %endif
         });
         </script>
     </div>