Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions Doc/library/base64.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,20 @@ POST request.
A :exc:`binascii.Error` exception is raised
if *s* is incorrectly padded.

If *validate* is ``False`` (the default), characters that are neither
If *validate* is false (the default), characters that are neither
in the normal base-64 alphabet nor the alternative alphabet are
discarded prior to the padding check. If *validate* is ``True``,
these non-alphabet characters in the input result in a
:exc:`binascii.Error`.
discarded prior to the padding check, but the ``+`` and ``/`` characters
keep their meaning if they are not in *altchars* (they will be discarded
in future Python versions).
If *validate* is true, these non-alphabet characters in the input
result in a :exc:`binascii.Error`.

For more information about the strict base64 check, see :func:`binascii.a2b_base64`

May assert or raise a :exc:`ValueError` if the length of *altchars* is not 2.
.. deprecated:: next
Accepting the ``+`` and ``/`` characters with an alternative alphabet
is now deprecated.


.. function:: standard_b64encode(s)

Expand Down Expand Up @@ -123,6 +128,9 @@ POST request.
``/`` in the standard Base64 alphabet, and return the decoded
:class:`bytes`.

.. deprecated:: next
Accepting the ``+`` and ``/`` characters is now deprecated.


.. function:: b32encode(s)

Expand Down
9 changes: 9 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,15 @@ Deprecated
New deprecations
----------------

* :mod:`base64`:

* Accepting the ``+`` and ``/`` characters with an alternative alphabet in
:func:`~base64.b64decode` and :func:`~base64.urlsafe_b64decode` is now
deprecated.
In future Python versions they will be errors in the strict mode and
discarded in the non-strict mode.
(Contributed by Serhiy Storchaka in :gh:`125346`.)

* CLI:

* Deprecate :option:`-b` and :option:`!-bb` command-line options
Expand Down
40 changes: 35 additions & 5 deletions Lib/base64.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,39 @@ def b64decode(s, altchars=None, validate=False):
The result is returned as a bytes object. A binascii.Error is raised if
s is incorrectly padded.

If validate is False (the default), characters that are neither in the
If validate is false (the default), characters that are neither in the
normal base-64 alphabet nor the alternative alphabet are discarded prior
to the padding check. If validate is True, these non-alphabet characters
to the padding check. If validate is true, these non-alphabet characters
in the input result in a binascii.Error.
For more information about the strict base64 check, see:

https://docs.python.org/3.11/library/binascii.html#binascii.a2b_base64
"""
s = _bytes_from_decode_data(s)
badchar = None
if altchars is not None:
altchars = _bytes_from_decode_data(altchars)
assert len(altchars) == 2, repr(altchars)
if len(altchars) != 2:
raise ValueError(f'invalid altchars: {altchars!r}')
for b in b'+/':
if b not in altchars and b in s:
badchar = b
break
s = s.translate(bytes.maketrans(altchars, b'+/'))
return binascii.a2b_base64(s, strict_mode=validate)
result = binascii.a2b_base64(s, strict_mode=validate)
if badchar is not None:
import warnings
if validate:
warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data '
f'with altchars={altchars!r} and validate=True '
f'will be an error in future Python versions',
DeprecationWarning, stacklevel=2)
else:
warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data '
f'with altchars={altchars!r} and validate=False '
f'will be discarded in future Python versions',
FutureWarning, stacklevel=2)
return result


def standard_b64encode(s):
Expand Down Expand Up @@ -130,8 +149,19 @@ def urlsafe_b64decode(s):
The alphabet uses '-' instead of '+' and '_' instead of '/'.
"""
s = _bytes_from_decode_data(s)
badchar = None
for b in b'+/':
if b in s:
badchar = b
break
s = s.translate(_urlsafe_decode_translation)
return b64decode(s)
result = binascii.a2b_base64(s, strict_mode=False)
if badchar is not None:
import warnings
warnings.warn(f'invalid character {chr(badchar)!a} in URL-safe Base64 data '
f'will be discarded in future Python versions',
FutureWarning, stacklevel=2)
return result



Expand Down
31 changes: 24 additions & 7 deletions Lib/test/test_base64.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,11 @@ def test_b64decode_altchars(self):
eq(base64.b64decode(data, altchars=altchars_str), res)
eq(base64.b64decode(data_str, altchars=altchars_str), res)

self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+')
self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+/-')
self.assertRaises(ValueError, base64.b64decode, '', altchars='+')
self.assertRaises(ValueError, base64.b64decode, '', altchars='+/-')

def test_b64decode_padding_error(self):
self.assertRaises(binascii.Error, base64.b64decode, b'abc')
self.assertRaises(binascii.Error, base64.b64decode, 'abc')
Expand Down Expand Up @@ -323,13 +328,25 @@ def test_b64decode_invalid_chars(self):
with self.assertRaises(binascii.Error):
base64.b64decode(bstr.decode('ascii'), validate=True)

# Normal alphabet characters not discarded when alternative given
res = b'\xfb\xef\xff'
self.assertEqual(base64.b64decode(b'++//', validate=True), res)
self.assertEqual(base64.b64decode(b'++//', '-_', validate=True), res)
self.assertEqual(base64.b64decode(b'--__', '-_', validate=True), res)
self.assertEqual(base64.urlsafe_b64decode(b'++//'), res)
self.assertEqual(base64.urlsafe_b64decode(b'--__'), res)
# Normal alphabet characters will be discarded when alternative given
with self.assertWarns(FutureWarning):
self.assertEqual(base64.b64decode(b'++++', altchars=b'-_'),
b'\xfb\xef\xbe')
with self.assertWarns(FutureWarning):
self.assertEqual(base64.b64decode(b'////', altchars=b'-_'),
b'\xff\xff\xff')
with self.assertWarns(DeprecationWarning):
self.assertEqual(base64.b64decode(b'++++', altchars=b'-_', validate=True),
b'\xfb\xef\xbe')
with self.assertWarns(DeprecationWarning):
self.assertEqual(base64.b64decode(b'////', altchars=b'-_', validate=True),
b'\xff\xff\xff')
with self.assertWarns(FutureWarning):
self.assertEqual(base64.urlsafe_b64decode(b'++++'), b'\xfb\xef\xbe')
with self.assertWarns(FutureWarning):
self.assertEqual(base64.urlsafe_b64decode(b'////'), b'\xff\xff\xff')
with self.assertRaises(binascii.Error):
base64.b64decode(b'+/!', altchars=b'-_')

def _altchars_strategy():
"""Generate 'altchars' for base64 encoding."""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Accepting ``+`` and ``/`` characters with an alternative alphabet in
:func:`base64.b64decode` and :func:`base64.urlsafe_b64decode` is now
deprecated.
In future Python versions they will be errors in the strict mode and
discarded in the non-strict mode.
Loading