Ignore:
Timestamp:
19 May 2018, 21:47:54 (6 years ago)
Author:
uli
Message:

Use the 'new' recaptcha v2.

The old one was turned off in March.

Location:
main/waeup.kofa/trunk/src/waeup/kofa/browser
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/captcha.py

    r12858 r15012  
    2121"""
    2222import grok
     23import json
    2324import urllib
    2425import urllib2
     
    163164
    164165##
    165 ## ReCaptcha
    166 ##
    167 API_SSL_SERVER = "https://www.google.com/recaptcha/api"
    168 VERIFY_SERVER = "https://www.google.com/recaptcha/api"
    169 
     166## ReCaptcha (v2)
     167##
    170168class ReCaptcha(StaticCaptcha):
    171169    """ReCaptcha - strong captchas with images, sound, etc.
    172170
    173171    This is the Kofa implementation to support captchas as provided by
    174     http://www.google.com/recaptcha.
     172    http://www.google.com/recaptcha (v2).
    175173
    176174    ReCaptcha is widely used and adopted in web applications. See the
     
    220218    This captcha is available at runtime as a global utility named
    221219    ``'ReCaptcha'``.
     220
     221    Shortcomings:
     222        - no support for selecting theme
     223        - no support for selecting box layout (normal, compact)
     224        - no support for non-javascript users
     225        - Google will get the data of our clients
     226        - Google will track all activity of our clients
    222227    """
    223228
    224229    grok.implements(ICaptcha)
    225230
    226     #: name of solution field in HTTP request
    227     sol_field = 'recaptcha_response_field'
    228     #: name of challenge field in HTTP request
    229     chal_field = 'recaptcha_challenge_field'
     231    #: name of response token field in HTTP request
     232    token_field = 'g-recaptcha-response'
    230233
    231234    # Do not use the following keys in productive environments!  As
     
    235238    PRIVATE_KEY = "6Lc0y8oSAAAAAMHVbMrGWLLjw2pm8v2Uprwm9AbR"
    236239
     240    VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify'
     241
    237242    def verify(self, request):
    238243        """Grab challenge/solution from HTTP request and verify it.
    239244
    240245        Verification happens against recaptcha remote API servers. It
    241         only happens, when really a solution was sent with the
     246        only happens, when a repsonse token was sent with the
    242247        request.
    243248
     
    246251        """
    247252        form = getattr(request, 'form', {})
    248         solution=form.get(self.sol_field, None)
    249         challenge=form.get(self.chal_field, None)
    250         if not challenge or not solution:
    251             # Might be first-time display of the captcha: not a valid
    252             # solution but no error code to prevent any error
    253             # messages. Skip further verification.
    254             return CaptchaResponse(
    255                 is_valid=False)
     253        token = form.get(self.token_field, None)
     254        if not token:
     255            # on first-time display, we won't get a token
     256            return CaptchaResponse(is_valid=False)
    256257        params = urllib.urlencode(
    257258            {
    258                 'privatekey': self.PRIVATE_KEY,
     259                'secret': self.PRIVATE_KEY,
     260                'response': token,
    259261                'remoteip': '127.0.0.1',
    260                 'challenge': challenge,
    261                 'response': solution,
    262262                })
    263263        request = urllib2.Request(
    264             url = "%s/verify" % VERIFY_SERVER,
     264            url = self.VERIFY_URL,
    265265            data = params,
    266266            headers = {
     
    269269                }
    270270            )
    271         resp = urllib2.urlopen(request)
    272         ret_vals = resp.read().splitlines()
    273         resp.close()
    274         ret_code, err_code = ret_vals
    275 
    276         if ret_code == "true":
     271        conn = urllib2.urlopen(request)
     272        ret_vals = json.loads(conn.read())
     273        conn.close()
     274        if ret_vals.get('success', False) is True:
    277275            return CaptchaResponse(is_valid=True)
    278         return CaptchaResponse(is_valid=False, error_code=ret_vals[1])
     276        return CaptchaResponse(
     277            is_valid=False, error_code="%s" % ret_vals['error-codes'])
    279278
    280279    def display(self, error_code=None):
    281         """Display challenge and input field for solution as HTML.
     280        """Display captcha widget snippet.
    282281
    283282        Returns the HTML code to be placed inside an existing ``<form>``
     
    297296        html = (
    298297            u'<script type="text/javascript" '
    299             u'src="%(ApiServer)s/challenge?k=%(PublicKey)s%(ErrorParam)s">'
     298            u'src="%(ApiServer)s" async defer>'
    300299            u'</script>'
    301             u''
    302             u'<noscript>'
    303             u'<iframe'
    304             u'    src="%(ApiServer)s/noscript?k=%(PublicKey)s%(ErrorParam)s"'
    305             u'    height="300" width="500" frameborder="0"></iframe><br />'
    306             u'<textarea name="recaptcha_challenge_field"'
    307             u'          rows="3" cols="40"></textarea>'
    308             u'<input type="hidden" name="recaptcha_response_field"'
    309             u'       value="manual_challenge" />'
    310             u'</noscript>' % {
    311                 'ApiServer' : API_SSL_SERVER,
    312                 'PublicKey' : self.PUBLIC_KEY,
    313                 'ErrorParam' : error_param,
     300            u'<div class="g-recaptcha" data-sitekey="%(SiteKey)s"></div>' % {
     301                'ApiServer': "https://www.google.com/recaptcha/api.js",
     302                'SiteKey': self.PUBLIC_KEY,
    314303                }
    315             )
     304        )
    316305        return html
     306
    317307
    318308grok.global_utility(ReCaptcha, name=u'ReCaptcha')
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_captcha.py

    r7811 r15012  
    171171        result = captcha.display()
    172172        self.assertMatches(
    173             '<script type="text/javascript" src="..."></script>'
    174             '<noscript>'
    175             '<iframe src="..." height="300" width="500" '
    176             '        frameborder="0"></iframe><br />'
    177             '<textarea name="recaptcha_challenge_field" rows="3" '
    178             '          cols="40"></textarea>'
    179             '<input type="hidden" name="recaptcha_response_field" '
    180             '       value="manual_challenge" /></noscript>',
     173            '<script type="text/javascript" '
     174            'src="..." async defer></script>'
     175            '<div class="g-recaptcha" data-sitekey="..."></div>',
    181176            result)
    182177        return
Note: See TracChangeset for help on using the changeset viewer.