Skip to content

Commit

Permalink
Merge pull request jsonpickle#545 from davvid/main
Browse files Browse the repository at this point in the history
* davvid/main:
  jsonpickle: guard against invalid b85 and b64 data
  • Loading branch information
davvid committed Dec 14, 2024
2 parents 49af293 + 9b68143 commit d4e49ae
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 5 deletions.
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Upcoming
========
* The unpickler is now more resilient to malformed "py/reduce", "py/set",
"py/tuple", and "py/iterator" input data. (+544)
"py/tuple", "py/b64", "py/b85", and "py/iterator" input data. (+544) (+545)
* The test suite was updated to leverage more pytest features.
* The ``jsonpickle.compat`` module is no longer used. It is still provided
for backwards compatibility but it may be removed in a future version.
Expand Down
10 changes: 8 additions & 2 deletions jsonpickle/unpickler.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,10 +433,16 @@ def register_classes(self, classes):
self._classes[util.importable_name(classes)] = classes

def _restore_base64(self, obj):
return util.b64decode(obj[tags.B64].encode('utf-8'))
try:
return util.b64decode(obj[tags.B64].encode('utf-8'))
except AttributeError:
return b''

def _restore_base85(self, obj):
return util.b85decode(obj[tags.B85].encode('utf-8'))
try:
return util.b85decode(obj[tags.B85].encode('utf-8'))
except AttributeError:
return b''

def _refname(self):
"""Calculates the name of the current location in the JSON stack.
Expand Down
11 changes: 9 additions & 2 deletions jsonpickle/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
determining the type of an object.
"""
import base64
import binascii
import collections
import inspect
import io
Expand Down Expand Up @@ -557,7 +558,10 @@ def b64decode(payload):
"""
Decode payload - must be ascii text.
"""
return base64.b64decode(payload)
try:
return base64.b64decode(payload)
except (TypeError, binascii.Error):
return b''


def b85encode(data):
Expand All @@ -571,7 +575,10 @@ def b85decode(payload):
"""
Decode payload - must be ascii text.
"""
return base64.b85decode(payload)
try:
return base64.b85decode(payload)
except (TypeError, ValueError):
return b''


def itemgetter(obj, getter=operator.itemgetter(0)):
Expand Down
16 changes: 16 additions & 0 deletions tests/jsonpickle_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,29 @@ def test_decode_base85(unpickler):
assert unpickler.restore(pickled) == expected


@pytest.mark.parametrize('value', ['', '/', 1, True, False, None, [], {}])
def test_decode_invalid_b85(value, unpickler):
"""Invalid base85 data restores to an empty string"""
expected = b''
pickled = {tags.B85: value}
assert unpickler.restore(pickled) == expected


def test_base85_still_handles_base64(unpickler):
"""base64 must be restored even though base85 is the default"""
expected = 'Pÿthöñ 3!'.encode()
pickled = {tags.B64: util.b64encode(expected)}
assert unpickler.restore(pickled) == expected


@pytest.mark.parametrize('value', ['', 'x', '!', 0, 1, True, False, None, [], {}])
def test_decode_invalid_b64(value, unpickler):
"""Invalid base85 data restores to an empty string"""
expected = b''
pickled = {tags.B64: value}
assert unpickler.restore(pickled) == expected


def test_string(pickler, unpickler):
"""Strings must roundtrip"""
assert pickler.flatten('a string') == 'a string'
Expand Down

0 comments on commit d4e49ae

Please sign in to comment.