Skip to content

Commit 220fc4e

Browse files
Always only emit a warning.
1 parent e9db343 commit 220fc4e

File tree

6 files changed

+67
-31
lines changed

6 files changed

+67
-31
lines changed

Doc/library/base64.rst

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,20 @@ POST request.
8484
A :exc:`binascii.Error` exception is raised
8585
if *s* is incorrectly padded.
8686

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

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

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

97102
.. function:: standard_b64encode(s)
98103

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

131+
.. deprecated:: next
132+
Accepting the ``+`` and ``/`` characters is now deprecated.
133+
126134

127135
.. function:: b32encode(s)
128136

Doc/whatsnew/3.15.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,15 @@ Deprecated
11431143
New deprecations
11441144
----------------
11451145

1146+
* :mod:`base64`:
1147+
1148+
* Accepting the ``+`` and ``/`` characters with an alternative alphabet in
1149+
:func:`~base64.b64decode` and :func:`~base64.urlsafe_b64decode` is now
1150+
deprecated.
1151+
In future Python versions they will be errors in the strict mode and
1152+
discarded in the non-strict mode.
1153+
(Contributed by Serhiy Storchaka in :gh:`125346`.)
1154+
11461155
* CLI:
11471156

11481157
* Deprecate :option:`-b` and :option:`!-bb` command-line options

Lib/base64.py

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ def b64decode(s, altchars=None, validate=False):
7272
The result is returned as a bytes object. A binascii.Error is raised if
7373
s is incorrectly padded.
7474
75-
If validate is False (the default), characters that are neither in the
75+
If validate is false (the default), characters that are neither in the
7676
normal base-64 alphabet nor the alternative alphabet are discarded prior
77-
to the padding check. If validate is True, these non-alphabet characters
77+
to the padding check. If validate is true, these non-alphabet characters
7878
in the input result in a binascii.Error.
7979
For more information about the strict base64 check, see:
8080
@@ -86,21 +86,24 @@ def b64decode(s, altchars=None, validate=False):
8686
altchars = _bytes_from_decode_data(altchars)
8787
if len(altchars) != 2:
8888
raise ValueError(f'invalid altchars: {altchars!r}')
89-
if validate:
90-
s = s.translate(bytes.maketrans(b'+/' + altchars, altchars + b'+/'))
91-
else:
92-
for b in set(b'+/') - set(altchars):
93-
if b in s:
94-
badchar = b
95-
break
96-
s = s.translate(bytes.maketrans(altchars, b'+/'))
89+
for b in b'+/':
90+
if b not in altchars and b in s:
91+
badchar = b
92+
break
93+
s = s.translate(bytes.maketrans(altchars, b'+/'))
9794
result = binascii.a2b_base64(s, strict_mode=validate)
9895
if badchar is not None:
9996
import warnings
100-
warnings.warn(f'invalid character {chr(badchar)!a} in base64 data '
101-
f'with altchars={altchars!r} will be discarded in '
102-
f'future Python versions',
103-
FutureWarning, stacklevel=2)
97+
if validate:
98+
warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data '
99+
f'with altchars={altchars!r} and validate=True '
100+
f'will be an error in future Python versions',
101+
DeprecationWarning, stacklevel=2)
102+
else:
103+
warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data '
104+
f'with altchars={altchars!r} and validate=False '
105+
f'will be discarded in future Python versions',
106+
FutureWarning, stacklevel=2)
104107
return result
105108

106109

@@ -123,7 +126,7 @@ def standard_b64decode(s):
123126

124127

125128
_urlsafe_encode_translation = bytes.maketrans(b'+/', b'-_')
126-
_urlsafe_decode_translation = bytes.maketrans(b'+/-_', b'-_+/')
129+
_urlsafe_decode_translation = bytes.maketrans(b'-_', b'+/')
127130

128131
def urlsafe_b64encode(s):
129132
"""Encode bytes using the URL- and filesystem-safe Base64 alphabet.
@@ -146,8 +149,19 @@ def urlsafe_b64decode(s):
146149
The alphabet uses '-' instead of '+' and '_' instead of '/'.
147150
"""
148151
s = _bytes_from_decode_data(s)
152+
badchar = None
153+
for b in b'+/':
154+
if b in s:
155+
badchar = b
156+
break
149157
s = s.translate(_urlsafe_decode_translation)
150-
return b64decode(s)
158+
result = binascii.a2b_base64(s, strict_mode=False)
159+
if badchar is not None:
160+
import warnings
161+
warnings.warn(f'invalid character {chr(badchar)!a} in URL-safe Base64 data '
162+
f'will be discarded in future Python versions',
163+
FutureWarning, stacklevel=2)
164+
return result
151165

152166

153167

Lib/test/test_base64.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -335,12 +335,16 @@ def test_b64decode_invalid_chars(self):
335335
with self.assertWarns(FutureWarning):
336336
self.assertEqual(base64.b64decode(b'////', altchars=b'-_'),
337337
b'\xff\xff\xff')
338-
self.assertEqual(base64.urlsafe_b64decode(b'++++'), b'')
339-
self.assertEqual(base64.urlsafe_b64decode(b'////'), b'')
340-
with self.assertRaises(binascii.Error):
341-
base64.b64decode(b'++++', altchars=b'-_', validate=True)
342-
with self.assertRaises(binascii.Error):
343-
base64.b64decode(b'////', altchars=b'-_', validate=True)
338+
with self.assertWarns(DeprecationWarning):
339+
self.assertEqual(base64.b64decode(b'++++', altchars=b'-_', validate=True),
340+
b'\xfb\xef\xbe')
341+
with self.assertWarns(DeprecationWarning):
342+
self.assertEqual(base64.b64decode(b'////', altchars=b'-_', validate=True),
343+
b'\xff\xff\xff')
344+
with self.assertWarns(FutureWarning):
345+
self.assertEqual(base64.urlsafe_b64decode(b'++++'), b'\xfb\xef\xbe')
346+
with self.assertWarns(FutureWarning):
347+
self.assertEqual(base64.urlsafe_b64decode(b'////'), b'\xff\xff\xff')
344348
with self.assertRaises(binascii.Error):
345349
base64.b64decode(b'+/!', altchars=b'-_')
346350

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Accepting ``+`` and ``/`` characters with an alternative alphabet in
2+
:func:`base64.b64decode` and :func:`base64.urlsafe_b64decode` is now
3+
deprecated.
4+
In future Python versions they will be errors in the strict mode and
5+
discarded in the non-strict mode.

Misc/NEWS.d/next/Security/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)