Hello community, here is the log from the commit of package python-Flask-WTF for openSUSE:Factory checked in at 2015-03-27 09:41:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Flask-WTF (Old) and /work/SRC/openSUSE:Factory/.python-Flask-WTF.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Flask-WTF" Changes: -------- --- /work/SRC/openSUSE:Factory/python-Flask-WTF/python-Flask-WTF.changes 2014-12-03 22:51:15.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python-Flask-WTF.new/python-Flask-WTF.changes 2015-03-27 09:41:09.000000000 +0100 @@ -1,0 +2,9 @@ +Wed Mar 25 20:03:09 UTC 2015 - [email protected] + +- Updated to 0.11 + - Use the new reCAPTCHA API via #164. + - Add configuration: WTF_CSRF_HEADERS via #159. + - Support customize hidden tags via #150. + - And many more bug fixes + +------------------------------------------------------------------- Old: ---- Flask-WTF-0.10.2.tar.gz New: ---- Flask-WTF-0.11.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Flask-WTF.spec ++++++ --- /var/tmp/diff_new_pack.vjIUj0/_old 2015-03-27 09:41:09.000000000 +0100 +++ /var/tmp/diff_new_pack.vjIUj0/_new 2015-03-27 09:41:09.000000000 +0100 @@ -16,7 +16,7 @@ # Name: python-Flask-WTF -Version: 0.10.2 +Version: 0.11 Release: 0 Url: http://github.com/lepture/flask-wtf Summary: WTForms support for Flask ++++++ Flask-WTF-0.10.2.tar.gz -> Flask-WTF-0.11.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/Flask_WTF.egg-info/PKG-INFO new/Flask-WTF-0.11/Flask_WTF.egg-info/PKG-INFO --- old/Flask-WTF-0.10.2/Flask_WTF.egg-info/PKG-INFO 2014-09-03 08:02:53.000000000 +0200 +++ new/Flask-WTF-0.11/Flask_WTF.egg-info/PKG-INFO 2015-01-21 11:39:11.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: Flask-WTF -Version: 0.10.2 +Version: 0.11 Summary: Simple integration of Flask and WTForms Home-page: http://github.com/lepture/flask-wtf Author: Hsiaoming Yang @@ -32,6 +32,7 @@ Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/PKG-INFO new/Flask-WTF-0.11/PKG-INFO --- old/Flask-WTF-0.10.2/PKG-INFO 2014-09-03 08:02:53.000000000 +0200 +++ new/Flask-WTF-0.11/PKG-INFO 2015-01-21 11:39:18.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: Flask-WTF -Version: 0.10.2 +Version: 0.11 Summary: Simple integration of Flask and WTForms Home-page: http://github.com/lepture/flask-wtf Author: Hsiaoming Yang @@ -32,6 +32,7 @@ Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/docs/changelog.rst new/Flask-WTF-0.11/docs/changelog.rst --- old/Flask-WTF-0.10.2/docs/changelog.rst 2014-09-03 07:55:44.000000000 +0200 +++ new/Flask-WTF-0.11/docs/changelog.rst 2015-01-21 11:22:32.000000000 +0100 @@ -3,6 +3,28 @@ Full list of changes between each Flask-WTF release. +Version 0.11 +------------ + +Released 2015/01/21 + +- Use the new reCAPTCHA API via `#164`_. + +.. _`#164`: https://github.com/lepture/flask-wtf/pull/164 + + +Version 0.10.3 +-------------- + +Released 2014/11/16 + +- Add configuration: WTF_CSRF_HEADERS via `#159`_. +- Support customize hidden tags via `#150`_. +- And many more bug fixes + +.. _`#150`: https://github.com/lepture/flask-wtf/pull/150 +.. _`#159`: https://github.com/lepture/flask-wtf/pull/159 + Version 0.10.2 -------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/docs/config.rst new/Flask-WTF-0.11/docs/config.rst --- old/Flask-WTF-0.10.2/docs/config.rst 2014-08-26 09:32:56.000000000 +0200 +++ new/Flask-WTF-0.11/docs/config.rst 2014-10-29 07:12:57.000000000 +0100 @@ -9,21 +9,27 @@ The full list of configuration for Flask-WTF. Usually, you don't need to configure any of them. It just works. -=================== =============================================== -WTF_CSRF_ENABLED Disable/enable CSRF protection for forms. - Default is True. -WTF_I18N_ENABLED Disable/enable I18N support. This should work - together with Flask-Babel. Default is True. -WTF_CSRF_SECRET_KEY A random string for generating CSRF token. - Default is the same as SECRET_KEY. -WTF_CSRF_TIME_LIMIT CSRF token expiring time. Default is **3600** - seconds. -WTF_CSRF_SSL_STRICT Strictly protection on SSL. This will check - the referrer, validate if it is from the same - origin. Default is True. -WTF_CSRF_METHODS CSRF protection on these request methods. - Default is **['POST', 'PUT', 'PATCH']** -=================== =============================================== +==================== =============================================== +WTF_CSRF_ENABLED Disable/enable CSRF protection for forms. + Default is True. +WTF_I18N_ENABLED Disable/enable I18N support. This should work + together with Flask-Babel. Default is True. +WTF_CSRF_HEADERS CSRF token HTTP headers checked. Default is + **['X-CSRFToken', 'X-CSRF-Token']** +WTF_CSRF_SECRET_KEY A random string for generating CSRF token. + Default is the same as SECRET_KEY. +WTF_CSRF_TIME_LIMIT CSRF token expiring time. Default is **3600** + seconds. +WTF_CSRF_SSL_STRICT Strictly protection on SSL. This will check + the referrer, validate if it is from the same + origin. Default is True. +WTF_CSRF_METHODS CSRF protection on these request methods. + Default is **['POST', 'PUT', 'PATCH']** +WTF_HIDDEN_TAG HTML tag name of the hidden tag wrapper. + Default is **div** +WTF_HIDDEN_TAG_ATTRS HTML tag attributes of the hidden tag wrapper. + Default is **{'style': 'display:none;'}** +==================== =============================================== Recaptcha diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/docs/csrf.rst new/Flask-WTF-0.11/docs/csrf.rst --- old/Flask-WTF-0.10.2/docs/csrf.rst 2014-09-03 07:54:33.000000000 +0200 +++ new/Flask-WTF-0.11/docs/csrf.rst 2015-01-21 11:19:45.000000000 +0100 @@ -80,12 +80,12 @@ Sending POST requests via AJAX is possible where there is no forms at all. This feature is only available since 0.9.0. -Assume you have done ``CsrfProtect(app)``, you can get the csrf token via +Assumimg you have done ``CsrfProtect(app)``, you can get the csrf token via ``{{ csrf_token() }}``. This method is available in every templates, that -you don't have to worry if there is no forms for rendering the csrf token +way you don't have to worry if there are no forms for rendering the csrf token field. -The suggest way is that you render the token in a ``<meta>`` tag: +The suggested way is that you render the token in a ``<meta>`` tag: .. sourcecode:: html+jinja @@ -115,3 +115,17 @@ } } }) + +Troubleshooting +--------------- + +When you define your forms, if you make `the mistake`_ of importing +``Form`` from ``wtforms`` instead of from ``flask.ext.wtf``, most +features besides CSRF protection will work (aside from +``form.validate_on_submit()``), but CSRF protection will fail. Upon +submitting forms, you’ll get +``Bad Request``/``CSRF token missing or incorrect`` (and the +``form.csrf_token`` in your template will produce no output). The +problem is in your broken import statements, not your configuration. + +.. _the mistake: http://stackoverflow.com/a/20577177/884640 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/flask_wtf/__init__.py new/Flask-WTF-0.11/flask_wtf/__init__.py --- old/Flask-WTF-0.10.2/flask_wtf/__init__.py 2014-09-03 07:56:11.000000000 +0200 +++ new/Flask-WTF-0.11/flask_wtf/__init__.py 2015-01-21 11:20:08.000000000 +0100 @@ -16,4 +16,4 @@ from .csrf import CsrfProtect from .recaptcha import * -__version__ = '0.10.2' +__version__ = '0.11' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/flask_wtf/_compat.py new/Flask-WTF-0.11/flask_wtf/_compat.py --- old/Flask-WTF-0.10.2/flask_wtf/_compat.py 2014-08-26 09:32:56.000000000 +0200 +++ new/Flask-WTF-0.11/flask_wtf/_compat.py 2015-01-21 11:19:50.000000000 +0100 @@ -12,3 +12,10 @@ if isinstance(text, text_type): text = text.encode('utf-8') return text + + +def to_unicode(input_bytes, encoding='utf-8'): + """Decodes input_bytes to text if needed.""" + if not isinstance(input_bytes, string_types): + input_bytes = input_bytes.decode(encoding) + return input_bytes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/flask_wtf/csrf.py new/Flask-WTF-0.11/flask_wtf/csrf.py --- old/Flask-WTF-0.10.2/flask_wtf/csrf.py 2014-08-26 09:32:56.000000000 +0200 +++ new/Flask-WTF-0.11/flask_wtf/csrf.py 2014-10-29 10:19:50.000000000 +0100 @@ -49,7 +49,7 @@ session['csrf_token'] = hashlib.sha1(os.urandom(64)).hexdigest() if time_limit: - expires = time.time() + time_limit + expires = int(time.time() + time_limit) csrf_build = '%s%s' % (session['csrf_token'], expires) else: expires = '' @@ -75,18 +75,21 @@ if not data or '##' not in data: return False - expires, hmac_csrf = data.split('##', 1) + try: + expires, hmac_csrf = data.split('##', 1) + except ValueError: + return False # unpack error if time_limit is None: time_limit = current_app.config.get('WTF_CSRF_TIME_LIMIT', 3600) if time_limit: try: - expires = float(expires) - except: + expires = int(expires) + except ValueError: return False - now = time.time() + now = int(time.time()) if now > expires: return False @@ -136,10 +139,29 @@ def init_app(self, app): app.jinja_env.globals['csrf_token'] = generate_csrf + app.config.setdefault( + 'WTF_CSRF_HEADERS', ['X-CSRFToken', 'X-CSRF-Token'] + ) app.config.setdefault('WTF_CSRF_SSL_STRICT', True) app.config.setdefault('WTF_CSRF_ENABLED', True) app.config.setdefault('WTF_CSRF_METHODS', ['POST', 'PUT', 'PATCH']) + def _get_csrf_token(): + # find the ``csrf_token`` field in the subitted form + # if the form had a prefix, the name will be + # ``{prefix}-csrf_token`` + for key in request.form: + if key.endswith('csrf_token'): + csrf_token = request.form[key] + if csrf_token: + return csrf_token + + for header_name in app.config['WTF_CSRF_HEADERS']: + csrf_token = request.headers.get(header_name) + if csrf_token: + return csrf_token + return None + # expose csrf_token as a helper in all templates @app.context_processor def csrf_token(): @@ -151,7 +173,7 @@ if not app.config['WTF_CSRF_ENABLED']: return - if request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): + if request.method not in app.config['WTF_CSRF_METHODS']: return if self._exempt_views or self._exempt_blueprints: @@ -168,21 +190,7 @@ if request.blueprint in self._exempt_blueprints: return - csrf_token = None - if request.method in app.config['WTF_CSRF_METHODS']: - # find the ``csrf_token`` field in the subitted form - # if the form had a prefix, the name will be ``{prefix}-csrf_token`` - for key in request.form: - if key.endswith('csrf_token'): - csrf_token = request.form[key] - if not csrf_token: - # You can get csrf token from header - # The header name is the same as Django - csrf_token = request.headers.get('X-CSRFToken') - if not csrf_token: - # The header name is the same as Rails - csrf_token = request.headers.get('X-CSRF-Token') - if not validate_csrf(csrf_token): + if not validate_csrf(_get_csrf_token()): reason = 'CSRF token missing or incorrect.' return self._error_response(reason) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/flask_wtf/form.py new/Flask-WTF-0.11/flask_wtf/form.py --- old/Flask-WTF-0.10.2/flask_wtf/form.py 2014-08-26 09:32:56.000000000 +0200 +++ new/Flask-WTF-0.11/flask_wtf/form.py 2014-10-29 07:12:57.000000000 +0100 @@ -2,7 +2,7 @@ import werkzeug.datastructures -from jinja2 import Markup +from jinja2 import Markup, escape from flask import request, session, current_app from wtforms.fields import HiddenField from wtforms.widgets import HiddenInput @@ -13,8 +13,8 @@ try: from .i18n import translations -except: - translations = None +except ImportError: + translations = None # babel not installed class _Auto(): @@ -57,6 +57,7 @@ csrf behavior is suppressed. Default: WTF_CSRF_ENABLED config value """ + SECRET_KEY = None TIME_LIMIT = None @@ -139,12 +140,21 @@ if not fields: fields = [f for f in self if _is_hidden(f)] - rv = [u'<div style="display:none;">'] + name = current_app.config.get('WTF_HIDDEN_TAG', 'div') + attrs = current_app.config.get( + 'WTF_HIDDEN_TAG_ATTRS', {'style': 'display:none;'}) + + tag_attrs = u' '.join( + u'%s="%s"' % (escape(k), escape(v)) for k, v in attrs.items()) + tag_start = u'<%s %s>' % (escape(name), tag_attrs) + tag_end = u'</%s>' % escape(name) + + rv = [tag_start] for field in fields: if isinstance(field, string_types): field = getattr(self, field) rv.append(text_type(field)) - rv.append(u"</div>") + rv.append(tag_end) return Markup(u"".join(rv)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/flask_wtf/recaptcha/validators.py new/Flask-WTF-0.11/flask_wtf/recaptcha/validators.py --- old/Flask-WTF-0.10.2/flask_wtf/recaptcha/validators.py 2014-08-26 09:36:39.000000000 +0200 +++ new/Flask-WTF-0.11/flask_wtf/recaptcha/validators.py 2015-01-21 11:19:50.000000000 +0100 @@ -7,30 +7,28 @@ from flask import request, current_app from wtforms import ValidationError from werkzeug import url_encode -from .._compat import to_bytes +from .._compat import to_bytes, to_unicode +import json -RECAPTCHA_VERIFY_SERVER = 'https://www.google.com/recaptcha/api/verify' +RECAPTCHA_VERIFY_SERVER = 'https://www.google.com/recaptcha/api/siteverify' __all__ = ["Recaptcha"] class Recaptcha(object): + """Validates a ReCaptcha.""" _error_codes = { - 'invalid-site-public-key': 'The public key for reCAPTCHA is invalid', - 'invalid-site-private-key': 'The private key for reCAPTCHA is invalid', - 'invalid-referrer': ( - 'The public key for reCAPTCHA is not valid for ' - 'this domainin' - ), - 'verify-params-incorrect': ( - 'The parameters passed to reCAPTCHA ' - 'verification are incorrect' - ) + 'missing-input-secret': 'The secret parameter is missing.', + 'invalid-input-secret': 'The secret parameter is invalid or malformed.', + 'missing-input-response': 'The response parameter is missing.', + 'invalid-input-response': 'The response parameter is invalid or malformed.', } - def __init__(self, message=u'Invalid word. Please try again.'): + def __init__(self, message=None): + if message is None: + message = self._error_codes['missing-input-response'] self.message = message def __call__(self, form, field): @@ -38,21 +36,19 @@ return True if request.json: - challenge = request.json.get('recaptcha_challenge_field', '') - response = request.json.get('recaptcha_response_field', '') + response = request.json.get('g-recaptcha-response', '') else: - challenge = request.form.get('recaptcha_challenge_field', '') - response = request.form.get('recaptcha_response_field', '') + response = request.form.get('g-recaptcha-response', '') remote_ip = request.remote_addr - if not challenge or not response: + if not response: raise ValidationError(field.gettext(self.message)) - if not self._validate_recaptcha(challenge, response, remote_ip): + if not self._validate_recaptcha(response, remote_ip): field.recaptcha_error = 'incorrect-captcha-sol' raise ValidationError(field.gettext(self.message)) - def _validate_recaptcha(self, challenge, response, remote_addr): + def _validate_recaptcha(self, response, remote_addr): """Performs the actual validation.""" try: private_key = current_app.config['RECAPTCHA_PRIVATE_KEY'] @@ -60,25 +56,23 @@ raise RuntimeError("No RECAPTCHA_PRIVATE_KEY config set") data = url_encode({ - 'privatekey': private_key, + 'secret': private_key, 'remoteip': remote_addr, - 'challenge': challenge, 'response': response }) - response = http.urlopen(RECAPTCHA_VERIFY_SERVER, to_bytes(data)) + http_response = http.urlopen(RECAPTCHA_VERIFY_SERVER, to_bytes(data)) - if response.code != 200: + if http_response.code != 200: return False - rv = [l.strip() for l in response.readlines()] + json_resp = json.loads(to_unicode(http_response.read())) - if rv and rv[0] == to_bytes('true'): + if json_resp["success"]: return True - if len(rv) > 1: - error = rv[1] + for error in json_resp["error-codes"]: if error in self._error_codes: - raise RuntimeError(self._error_codes[error]) + raise ValidationError(self._error_codes[error]) return False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/flask_wtf/recaptcha/widgets.py new/Flask-WTF-0.11/flask_wtf/recaptcha/widgets.py --- old/Flask-WTF-0.10.2/flask_wtf/recaptcha/widgets.py 2014-09-03 07:54:33.000000000 +0200 +++ new/Flask-WTF-0.11/flask_wtf/recaptcha/widgets.py 2015-01-21 11:19:50.000000000 +0100 @@ -1,31 +1,31 @@ # -*- coding: utf-8 -*- from flask import current_app, Markup -from werkzeug import url_encode from flask import json -from .._compat import text_type JSONEncoder = json.JSONEncoder -try: - from speaklater import _LazyString - - class _JSONEncoder(JSONEncoder): - def default(self, o): - if isinstance(o, _LazyString): - return str(o) - return JSONEncoder.default(self, o) -except: - _JSONEncoder = JSONEncoder - - -RECAPTCHA_API_SERVER = '//www.google.com/recaptcha/api/' RECAPTCHA_HTML = u''' -<script type="text/javascript">var RecaptchaOptions = %(options)s;</script> -<script type="text/javascript" src="%(script_url)s"></script> +<script src='https://www.google.com/recaptcha/api.js'></script> +<div class="g-recaptcha" data-sitekey="%(public_key)s"></div> <noscript> - <iframe src="%(frame_url)s" height="300" width="500" frameborder="0"></iframe><br> - <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea> - <input type="hidden" name="recaptcha_response_field" value="manual_challenge"> + <div style="width: 302px; height: 352px;"> + <div style="width: 302px; height: 352px; position: relative;"> + <div style="width: 302px; height: 352px; position: absolute;"> + <iframe src="https://www.google.com/recaptcha/api/fallback?k=%(public_key)s" + frameborder="0" scrolling="no" + style="width: 302px; height:352px; border-style: none;"> + </iframe> + </div> + <div style="width: 250px; height: 80px; position: absolute; border-style: none; + bottom: 21px; left: 25px; margin: 0px; padding: 0px; right: 25px;"> + <textarea id="g-recaptcha-response" name="g-recaptcha-response" + class="g-recaptcha-response" + style="width: 250px; height: 80px; border: 1px solid #c1c1c1; + margin: 0px; padding: 0px; resize: none;" value=""> + </textarea> + </div> + </div> + </div> </noscript> ''' @@ -34,15 +34,11 @@ class RecaptchaWidget(object): - def recaptcha_html(self, query, options): + def recaptcha_html(self, public_key): html = current_app.config.get('RECAPTCHA_HTML', RECAPTCHA_HTML) - server = current_app.config.get( - 'RECAPTCHA_API_SERVER', RECAPTCHA_API_SERVER - ) + return Markup(html % dict( - script_url='%schallenge?%s' % (server, query), - frame_url='%snoscript?%s' % (server, query), - options=json.dumps(options, cls=_JSONEncoder) + public_key=public_key )) def __call__(self, field, error=None, **kwargs): @@ -52,32 +48,5 @@ public_key = current_app.config['RECAPTCHA_PUBLIC_KEY'] except KeyError: raise RuntimeError("RECAPTCHA_PUBLIC_KEY config not set") - query_options = dict(k=public_key) - - if field.recaptcha_error is not None: - query_options['error'] = text_type(field.recaptcha_error) - - query = url_encode(query_options) - - _ = field.gettext - - options = { - 'theme': 'clean', - 'custom_translations': { - 'audio_challenge': _('Get an audio challenge'), - 'cant_hear_this': _('Download sound as MP3'), - 'help_btn': _('Help'), - 'image_alt_text': _('reCAPTCHA challenge image'), - 'incorrect_try_again': _('Incorrect. Try again.'), - 'instructions_audio': _('Type what you hear'), - 'instructions_visual': _('Type the text'), - 'play_again': _('Play sound again'), - 'privacy_and_terms': _('Privacy & Terms'), - 'refresh_btn': _('Get a new challenge'), - 'visual_challenge': _('Get a visual challenge'), - } - } - - options.update(current_app.config.get('RECAPTCHA_OPTIONS', {})) - return self.recaptcha_html(query, options) + return self.recaptcha_html(public_key) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/setup.py new/Flask-WTF-0.11/setup.py --- old/Flask-WTF-0.10.2/setup.py 2014-08-26 09:32:56.000000000 +0200 +++ new/Flask-WTF-0.11/setup.py 2014-10-29 07:14:38.000000000 +0100 @@ -64,6 +64,7 @@ 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: Implementation', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/tests/test_csrf.py new/Flask-WTF-0.11/tests/test_csrf.py --- old/Flask-WTF-0.10.2/tests/test_csrf.py 2014-08-26 09:32:56.000000000 +0200 +++ new/Flask-WTF-0.11/tests/test_csrf.py 2014-10-29 07:12:57.000000000 +0100 @@ -170,6 +170,40 @@ ) assert response.status_code == 200 + def test_empty_csrf_headers(self): + response = self.client.get("/", base_url='https://localhost/') + csrf_token = get_csrf_token(response.data) + self.app.config['WTF_CSRF_HEADERS'] = list() + response = self.client.post( + "/", + data={"name": "danny"}, + headers={ + 'X-CSRFToken': csrf_token, + }, + environ_base={ + 'HTTP_REFERER': 'https://localhost/', + }, + base_url='https://localhost/', + ) + assert response.status_code == 400 + + def test_custom_csrf_headers(self): + response = self.client.get("/", base_url='https://localhost/') + csrf_token = get_csrf_token(response.data) + self.app.config['WTF_CSRF_HEADERS'] = ['X-XSRF-TOKEN'] + response = self.client.post( + "/", + data={"name": "danny"}, + headers={ + 'X-XSRF-TOKEN': csrf_token, + }, + environ_base={ + 'HTTP_REFERER': 'https://localhost/', + }, + base_url='https://localhost/', + ) + assert response.status_code == 200 + def test_not_endpoint(self): response = self.client.post('/not-endpoint') assert response.status_code == 404 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-WTF-0.10.2/tests/test_recaptcha.py new/Flask-WTF-0.11/tests/test_recaptcha.py --- old/Flask-WTF-0.10.2/tests/test_recaptcha.py 2014-08-26 09:33:14.000000000 +0200 +++ new/Flask-WTF-0.11/tests/test_recaptcha.py 2015-01-21 11:19:50.000000000 +0100 @@ -34,31 +34,28 @@ response = self.client.get('/') assert b'//www.google.com/recaptcha/api/' in response.data - def test_invalid_recaptcha(self): response = self.client.post('/', data={}) - assert b'Invalid word' in response.data + assert b'missing' in response.data def test_send_recaptcha_request(self): response = self.client.post('/', data={ - 'recaptcha_challenge_field': 'test', - 'recaptcha_response_field': 'test' + 'g-recaptcha-response': 'test' }) - assert b'Invalid word' in response.data + assert b'invalid' in response.data def test_testing(self): self.app.testing = True response = self.client.post('/', data={ - 'recaptcha_challenge_field': 'test', - 'recaptcha_response_field': 'test' + 'g-recaptcha-response': 'test' }) - assert b'Invalid word' not in response.data + assert b'invalid' not in response.data def test_no_private_key(self): + self.app.testing = False self.app.config.pop('RECAPTCHA_PRIVATE_KEY', None) response = self.client.post('/', data={ - 'recaptcha_challenge_field': 'test', - 'recaptcha_response_field': 'test' + 'g-recaptcha-response': 'test' }) assert response.status_code == 500 -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
