Skip to content

Commit

Permalink
Merge branch 'release-0.7.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
chipx86 committed Oct 10, 2013
2 parents 944246a + 0558ebe commit 36cd157
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 2 deletions.
4 changes: 3 additions & 1 deletion AUTHORS
Expand Up @@ -14,15 +14,17 @@ Contributors:
* Brad Taylor
* Cory McWilliams
* Dave Druska
* Emmanuel Gil Peyrot
* Hongbin Lu
* Hussain Bohra
* Jesus Zambrano
* Jim Chen
* Kalil Amlani
* Kevin Quinn
* Lee Loucks
* Mark Cote
* Mark Côté
* Micah Dowty
* Natasha Dalal
* Niklas Hambuechen
* Onkar Shinde
* Paolo Borelli
Expand Down
61 changes: 61 additions & 0 deletions NEWS
@@ -1,3 +1,56 @@
version 0.7.19 final (10-October-2013):
* Security updates:
* JSONField now corrects incorrectly stored contents in a safer way,
to remove the risk of any exploits in a JSON payload.

This is CVE-2013-4409

* General:
* Updated much of the codebase to be more compatible with Django 1.5
and newer. The upcoming Djblets 0.8 releases will be geared more
heavily toward Django 1.5 compatibility.

* Packaging:
* Fixed building the static media for Djblets when using a Python
interpreter other than the one named 'python' in the system path.
Patch by Emmanuel Gil Peyrot.

* Djblets now requires django-pipeline 1.2.24. This version of
Djblets does not work correctly with newer versions.

* djblets.extensions:
* Extensions can now add additional middleware by setting
Extension.middleware to a list of middleware classes.

Patch by Mark Côté.

* Updated ExtensionResource to use the modern, type-checked,
documented field style, and to add missing documentation.

* djblets.util.templatetags.djblets_js:
* The json_dumps filter no longer defaults to indenting at all.
Previously, it defaulted to 0, which did not indent code, but
did preserve newlines.

* djblets.webapi:
* WebAPIError.with_message no longer overrides the original message
for all other instances of that error.

* Added WebAPIError.with_overrides, which allows overriding the
message and HTTP headers.

* The webapi decorators now preserve and merge webapi-related
information from other decorators, such as the lists of
response errors and optional/required fields.

* jquery.gravy:
* The modalBox z-index has been increased from its previously
low z-index, to prevent other UI elements from more easily
popping up over it.

Patch by Natasha Dalal.


version 0.7.18 final (15-September-2013):
* Security updates:
* We now require Django 1.4.8, which has some important security
Expand Down Expand Up @@ -528,6 +581,14 @@ version 0.7.0 final (2-August-2012):
a dependency of djblets.


version 0.6.30 final (10-October-2013);
* Security updates:
* JSONField now corrects incorrectly stored contents in a safer way,
to remove the risk of any exploits in a JSON payload.

This is CVE-2013-4409


version 0.6.29 final (27-July-2013):
* djblets.datagrid:
* Data pulled from the database and rendered into cells are always
Expand Down
Empty file added djblets/util/compat/__init__.py
Empty file.
51 changes: 51 additions & 0 deletions djblets/util/compat/ast_compat.py
@@ -0,0 +1,51 @@
#
# Backwards-compatibility functions from Python's ast module, used for
# Python 2.5 and lower.
#
# This code is Copyright 2008 by Armin Ronacher under the Python License.
#
from compiler import parse
from compiler.ast import *


def literal_eval(node_or_string):
"""
Safely evaluate an expression node or a string containing a Python
expression. The string or node provided may only consist of the following
Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
and None.
"""
_safe_names = {'None': None, 'True': True, 'False': False}
if isinstance(node_or_string, basestring):
node_or_string = parse(node_or_string, mode='eval')
if isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
def _convert(node):
if isinstance(node, Str):
return node.s
elif isinstance(node, Num):
return node.n
elif isinstance(node, Tuple):
return tuple(map(_convert, node.elts))
elif isinstance(node, List):
return list(map(_convert, node.elts))
elif isinstance(node, Dict):
return dict((_convert(k), _convert(v)) for k, v
in zip(node.keys, node.values))
elif isinstance(node, Name):
if node.id in _safe_names:
return _safe_names[node.id]
elif isinstance(node, BinOp) and \
isinstance(node.op, (Add, Sub)) and \
isinstance(node.right, Num) and \
isinstance(node.right.n, complex) and \
isinstance(node.left, Num) and \
isinstance(node.left.n, (int, long, float)):
left = node.left.n
right = node.right.n
if isinstance(node.op, Add):
return left + right
else:
return left - right
raise ValueError('malformed string')
return _convert(node_or_string)
17 changes: 16 additions & 1 deletion djblets/util/fields.py
Expand Up @@ -28,6 +28,11 @@
import logging
from datetime import datetime

try:
from ast import literal_eval
except ImportError:
from djblets.util.compat.ast_compat import literal_eval

from django.conf import settings
from django.core.serializers.json import DjangoJSONEncoder
from django.db import models
Expand Down Expand Up @@ -209,7 +214,17 @@ def loads(self, val):
except ValueError:
# There's probably embedded unicode markers (like u'foo') in the
# string. We have to eval it.
val = eval(val)
try:
val = literal_eval(val)
except Exception, e:
logging.error('Failed to eval JSONField data "%r": %s'
% (val, e))
val = {}

if isinstance(val, basestring):
logging.warning('JSONField decode error after literal_eval: '
'Expected dictionary, got string: %r' % val)
val = {}

return val

Expand Down
46 changes: 46 additions & 0 deletions djblets/util/tests.py
Expand Up @@ -348,6 +348,52 @@ def testLevel2(self):
"> > foo\n> > bar")


class JSONFieldTests(unittest.TestCase):
"""Unit tests for JSONField."""

def setUp(self):
from djblets.util.fields import JSONField
self.field = JSONField()

def test_loading_json_dict(self):
"""Testing JSONField with loading a JSON dictionary"""
result = self.field.loads('{"a": 1, "b": 2}')
self.assertTrue(isinstance(result, dict))
self.assertTrue('a' in result)
self.assertTrue('b' in result)

def test_loading_json_broken_dict(self):
"""Testing JSONField with loading a badly serialized JSON dictionary"""
result = self.field.loads('{u"a": 1, u"b": 2}')
self.assertTrue(isinstance(result, dict))
self.assertTrue('a' in result)
self.assertTrue('b' in result)

def test_loading_json_array(self):
"""Testing JSONField with loading a JSON array"""
result = self.field.loads('[1, 2, 3]')
self.assertTrue(isinstance(result, list))
self.assertEqual(result, [1, 2, 3])

def test_loading_string(self):
"""Testing JSONField with loading a stored string"""
result = self.field.loads('"foo"')
self.assertTrue(isinstance(result, dict))
self.assertEqual(result, {})

def test_loading_broken_string(self):
"""Testing JSONField with loading a broken stored string"""
result = self.field.loads('u"foo"')
self.assertTrue(isinstance(result, dict))
self.assertEqual(result, {})

def test_loading_python_code(self):
"""Testing JSONField with loading Python code"""
result = self.field.loads('locals()')
self.assertTrue(isinstance(result, dict))
self.assertEqual(result, {})


class URLResolverTests(unittest.TestCase):
def setUp(self):
self._old_root_urlconf = settings.ROOT_URLCONF
Expand Down

0 comments on commit 36cd157

Please sign in to comment.