re-captcha: adjust for v2 that is the only left one supported since 1st of May.

This commit is contained in:
Marcin Kuzminski 2018-05-06 23:19:05 +02:00
parent 12d382294e
commit 96c8fb8a21
9 changed files with 72 additions and 63 deletions

View file

@ -225,13 +225,6 @@ self: super: {
};
});
recaptcha-client = super.recaptcha-client.override (attrs: {
meta = {
# TODO: It is MIT/X11
license = pkgs.lib.licenses.mit;
};
});
python-editor = super.python-editor.override (attrs: {
meta = {
license = pkgs.lib.licenses.asl20;

View file

@ -1627,19 +1627,6 @@
license = [ pkgs.lib.licenses.bsdOriginal { fullName = "LGPL+BSD"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
};
};
recaptcha-client = super.buildPythonPackage {
name = "recaptcha-client-1.0.6";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [];
src = fetchurl {
url = "https://pypi.python.org/packages/0a/ea/5f2fbbfd894bdac1c68ef8d92019066cfcf9fbff5fe3d728d2b5c25c8db4/recaptcha-client-1.0.6.tar.gz";
md5 = "74228180f7e1fb76c4d7089160b0d919";
};
meta = {
license = [ { fullName = "MIT/X11"; } ];
};
};
redis = super.buildPythonPackage {
name = "redis-2.10.6";
buildInputs = with self; [];
@ -1683,7 +1670,7 @@
name = "rhodecode-enterprise-ce-4.12.0";
buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj];
doCheck = true;
propagatedBuildInputs = with self; [setuptools-scm amqp authomatic Babel Beaker celery Chameleon channelstream click colander configobj cssselect decorator deform docutils dogpile.cache dogpile.core ecdsa FormEncode future futures gnureadline infrae.cache iso8601 itsdangerous Jinja2 billiard kombu lxml Mako Markdown MarkupSafe msgpack-python MySQL-python objgraph packaging Paste PasteDeploy PasteScript pathlib2 peppercorn psutil psycopg2 py-bcrypt pycrypto pycurl pyflakes pygments-markdown-lexer Pygments pyparsing pyramid-beaker pyramid-debugtoolbar pyramid-jinja2 pyramid-mako pyramid pysqlite python-dateutil python-ldap python-memcached python-pam pytz tzlocal pyzmq py-gfm recaptcha-client redis repoze.lru requests Routes setproctitle simplejson six SQLAlchemy sshpubkeys subprocess32 supervisor Tempita translationstring trollius urllib3 URLObject venusian WebError WebHelpers2 WebHelpers WebOb Whoosh wsgiref zope.cachedescriptors zope.deprecation zope.event zope.interface nbconvert bleach nbformat jupyter-client alembic invoke bumpversion transifex-client gevent greenlet gunicorn waitress uWSGI ipdb ipython CProfileV bottle rhodecode-tools appenlight-client pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage];
propagatedBuildInputs = with self; [setuptools-scm amqp authomatic Babel Beaker celery Chameleon channelstream click colander configobj cssselect decorator deform docutils dogpile.cache dogpile.core ecdsa FormEncode future futures gnureadline infrae.cache iso8601 itsdangerous Jinja2 billiard kombu lxml Mako Markdown MarkupSafe msgpack-python MySQL-python objgraph packaging Paste PasteDeploy PasteScript pathlib2 peppercorn psutil psycopg2 py-bcrypt pycrypto pycurl pyflakes pygments-markdown-lexer Pygments pyparsing pyramid-beaker pyramid-debugtoolbar pyramid-jinja2 pyramid-mako pyramid pysqlite python-dateutil python-ldap python-memcached python-pam pytz tzlocal pyzmq py-gfm redis repoze.lru requests Routes setproctitle simplejson six SQLAlchemy sshpubkeys subprocess32 supervisor Tempita translationstring trollius urllib3 URLObject venusian WebError WebHelpers2 WebHelpers WebOb Whoosh wsgiref zope.cachedescriptors zope.deprecation zope.event zope.interface nbconvert bleach nbformat jupyter-client alembic invoke bumpversion transifex-client gevent greenlet gunicorn waitress uWSGI ipdb ipython CProfileV bottle rhodecode-tools appenlight-client pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage];
src = ./.;
meta = {
license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];

View file

@ -65,7 +65,6 @@ pytz==2018.3
tzlocal==1.5.1
pyzmq==14.6.0
py-gfm==0.1.3
recaptcha-client==1.0.6
redis==2.10.6
repoze.lru==0.7
requests==2.9.1

View file

@ -97,16 +97,16 @@ class TestRegisterCaptcha(object):
assertr.no_element_exists('#recaptcha_field')
@pytest.mark.parametrize('valid', [False, True])
@mock.patch('rhodecode.apps.login.views.submit')
@mock.patch.object(LoginView, 'validate_captcha')
@mock.patch.object(LoginView, '_get_captcha_data')
def test_register_with_active_captcha(
self, m_get_captcha_data, m_submit, valid, app, csrf_token):
self, m_get_captcha_data, m_validate_captcha, valid, app, csrf_token):
captcha = CaptchaData(
active=True, private_key='PRIVATE_KEY', public_key='PUBLIC_KEY')
m_get_captcha_data.return_value = captcha
m_response = mock.Mock()
m_response.is_valid = valid
m_submit.return_value = m_response
m_validate_captcha.return_value = valid, 'ok'
params = {
'csrf_token': csrf_token,

View file

@ -25,10 +25,10 @@ import formencode
import formencode.htmlfill
import logging
import urlparse
import requests
from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config
from recaptcha.client.captcha import submit
from rhodecode.apps._base import BaseAppView
from rhodecode.authentication.base import authenticate, HTTP_TYPE
@ -124,6 +124,29 @@ class LoginView(BaseAppView):
return CaptchaData(
active=active, private_key=private_key, public_key=public_key)
def validate_captcha(self, private_key):
captcha_rs = self.request.POST.get('g-recaptcha-response')
url = "https://www.google.com/recaptcha/api/siteverify"
params = {
'secret': private_key,
'response': captcha_rs,
'remoteip': get_ip_addr(self.request.environ)
}
verify_rs = requests.get(url, params=params, verify=True)
verify_rs = verify_rs.json()
captcha_status = verify_rs.get('success', False)
captcha_errors = verify_rs.get('error-codes', [])
if not isinstance(captcha_errors, list):
captcha_errors = [captcha_errors]
captcha_errors = ', '.join(captcha_errors)
captcha_message = ''
if captcha_status is False:
captcha_message = "Bad captcha. Errors: {}".format(
captcha_errors)
return captcha_status, captcha_message
@view_config(
route_name='login', request_method='GET',
renderer='rhodecode:templates/login.mako')
@ -262,17 +285,15 @@ class LoginView(BaseAppView):
form_result['active'] = auto_active
if captcha.active:
response = submit(
self.request.POST.get('recaptcha_challenge_field'),
self.request.POST.get('recaptcha_response_field'),
private_key=captcha.private_key,
remoteip=get_ip_addr(self.request.environ))
if not response.is_valid:
captcha_status, captcha_message = self.validate_captcha(
captcha.private_key)
if not captcha_status:
_value = form_result
_msg = _('Bad captcha')
error_dict = {'recaptcha_field': _msg}
raise formencode.Invalid(_msg, _value, None,
error_dict=error_dict)
error_dict = {'recaptcha_field': captcha_message}
raise formencode.Invalid(
_msg, _value, None, error_dict=error_dict)
new_user = UserModel().create_registration(form_result)
@ -339,15 +360,13 @@ class LoginView(BaseAppView):
user_email = form_result['email']
if captcha.active:
response = submit(
self.request.POST.get('recaptcha_challenge_field'),
self.request.POST.get('recaptcha_response_field'),
private_key=captcha.private_key,
remoteip=get_ip_addr(self.request.environ))
if not response.is_valid:
captcha_status, captcha_message = self.validate_captcha(
captcha.private_key)
if not captcha_status:
_value = form_result
_msg = _('Bad captcha')
error_dict = {'recaptcha_field': _msg}
error_dict = {'recaptcha_field': captcha_message}
raise formencode.Invalid(
_msg, _value, None, error_dict=error_dict)

View file

@ -305,9 +305,6 @@
"python2.7-pyzmq-14.6.0": {
"BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
},
"python2.7-recaptcha-client-1.0.6": {
"MIT License": "http://spdx.org/licenses/MIT"
},
"python2.7-repoze.lru-0.6": {
"Repoze License": "http://www.repoze.org/LICENSE.txt"
},

View file

@ -65,26 +65,26 @@ ${h.secure_form(h.route_path('admin_settings_global_update'), request=request)}
</div>
<div class="panel-body">
<div class="label">
<label for="rhodecode_captcha_public_key">${_('Google ReCaptcha public key')}</label>
<label for="rhodecode_captcha_public_key">${_('Google reCaptcha v2 site key.')}</label>
</div>
<div class="field input">
${h.text('rhodecode_captcha_public_key',size=60)}
</div>
<div class="field">
<span class="help-block">
${_('Public key for reCaptcha system.')}
${_('Site key for reCaptcha v2 system.')}
</span>
</div>
<div class="label">
<label for="rhodecode_captcha_private_key">${_('Google ReCaptcha private key')}</label>
<label for="rhodecode_captcha_private_key">${_('Google reCaptcha v2 secret key.')}</label>
</div>
<div class="field input">
${h.text('rhodecode_captcha_private_key',size=60)}
</div>
<div class="field">
<span class="help-block">
${_('Private key for reCaptcha system. Setting this value will enable captcha on registration')}
${_('Secret key for reCaptcha v2 system. Setting this value will enable captcha on registration and password reset forms.')}
</span>
</div>
</div>

View file

@ -61,6 +61,7 @@
<label for="email">${_('Captcha')}:</label>
${h.hidden('recaptcha_field')}
<div id="recaptcha"></div>
%if 'recaptcha_field' in errors:
<span class="error-message">${errors.get('recaptcha_field')}</span>
<br />
@ -78,14 +79,20 @@
</div>
</div>
%if 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 captcha_active:
Recaptcha.create("${captcha_public_key}", "recaptcha", {theme: "white"});
%endif
});
</script>
% if captcha_active:
<script type="text/javascript">
var onloadCallback = function() {
grecaptcha.render('recaptcha', {
'sitekey' : "${captcha_public_key}"
});
};
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
% endif

View file

@ -110,14 +110,21 @@
</div>
</div>
%if 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(){
$(document).ready(function(){
$('#username').focus();
%if captcha_active:
Recaptcha.create("${captcha_public_key}", "recaptcha", {theme: "white"});
%endif
});
});
</script>
% if captcha_active:
<script type="text/javascript">
var onloadCallback = function() {
grecaptcha.render('recaptcha', {
'sitekey' : "${captcha_public_key}"
});
};
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
% endif