Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5209857

Browse files
committed
Removed implicit convertions of str object to bytes from base64.
This also exposed some bugs in urlib2 and email.base64mime, which I tried my best to fix. However, someone will probably have to double check.
1 parent 8cb02b6 commit 5209857

4 files changed

Lines changed: 42 additions & 16 deletions

File tree

Lib/base64.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,13 @@ def b64encode(s, altchars=None):
5353
The encoded byte string is returned.
5454
"""
5555
if not isinstance(s, bytes_types):
56-
s = bytes(s, "ascii")
56+
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
5757
# Strip off the trailing newline
5858
encoded = binascii.b2a_base64(s)[:-1]
5959
if altchars is not None:
6060
if not isinstance(altchars, bytes_types):
61-
altchars = bytes(altchars, "ascii")
61+
altchars = TypeError("expected bytes, not %s"
62+
% altchars.__class__.__name__)
6263
assert len(altchars) == 2, repr(altchars)
6364
return _translate(encoded, {'+': altchars[0:1], '/': altchars[1:2]})
6465
return encoded
@@ -76,10 +77,11 @@ def b64decode(s, altchars=None):
7677
present in the string.
7778
"""
7879
if not isinstance(s, bytes_types):
79-
s = bytes(s)
80+
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
8081
if altchars is not None:
8182
if not isinstance(altchars, bytes_types):
82-
altchars = bytes(altchars, "ascii")
83+
raise TypeError("expected bytes, not %s"
84+
% altchars.__class__.__name__)
8385
assert len(altchars) == 2, repr(altchars)
8486
s = _translate(s, {chr(altchars[0]): b'+', chr(altchars[1]): b'/'})
8587
return binascii.a2b_base64(s)
@@ -148,7 +150,7 @@ def b32encode(s):
148150
s is the byte string to encode. The encoded byte string is returned.
149151
"""
150152
if not isinstance(s, bytes_types):
151-
s = bytes(s)
153+
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
152154
quanta, leftover = divmod(len(s), 5)
153155
# Pad the last quantum with zero bits if necessary
154156
if leftover:
@@ -205,16 +207,16 @@ def b32decode(s, casefold=False, map01=None):
205207
characters present in the input.
206208
"""
207209
if not isinstance(s, bytes_types):
208-
s = bytes(s)
210+
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
209211
quanta, leftover = divmod(len(s), 8)
210212
if leftover:
211213
raise binascii.Error('Incorrect padding')
212214
# Handle section 2.4 zero and one mapping. The flag map01 will be either
213215
# False, or the character to map the digit 1 (one) to. It should be
214216
# either L (el) or I (eye).
215-
if map01:
217+
if map01 is not None:
216218
if not isinstance(map01, bytes_types):
217-
map01 = bytes(map01)
219+
raise TypeError("expected bytes, not %s" % map01.__class__.__name__)
218220
assert len(map01) == 1, repr(map01)
219221
s = _translate(s, {b'0': b'O', b'1': map01})
220222
if casefold:
@@ -269,6 +271,8 @@ def b16encode(s):
269271
270272
s is the byte string to encode. The encoded byte string is returned.
271273
"""
274+
if not isinstance(s, bytes_types):
275+
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
272276
return binascii.hexlify(s).upper()
273277

274278

@@ -284,7 +288,7 @@ def b16decode(s, casefold=False):
284288
present in the string.
285289
"""
286290
if not isinstance(s, bytes_types):
287-
s = bytes(s)
291+
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
288292
if casefold:
289293
s = s.upper()
290294
if re.search('[^0-9A-F]', s):

Lib/email/base64mime.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,10 @@ def header_encode(header_bytes, charset='iso-8859-1'):
6666
charset names the character set to use to encode the header. It defaults
6767
to iso-8859-1. Base64 encoding is defined in RFC 2045.
6868
"""
69-
# Return empty headers unchanged
7069
if not header_bytes:
71-
return str(header_bytes)
70+
return ""
71+
if isinstance(header_bytes, str):
72+
header_bytes = header_bytes.encode(charset)
7273
encoded = b64encode(header_bytes).decode("ascii")
7374
return '=?%s?b?%s?=' % (charset, encoded)
7475

Lib/test/test_base64.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def test_encodestring(self):
1919
b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
2020
b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT"
2121
b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n")
22+
self.assertRaises(TypeError, base64.encodestring, "")
2223

2324
def test_decodestring(self):
2425
eq = self.assertEqual
@@ -33,6 +34,7 @@ def test_decodestring(self):
3334
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3435
b"0123456789!@#0^&*();:<>,. []{}")
3536
eq(base64.decodestring(b''), b'')
37+
self.assertRaises(TypeError, base64.decodestring, "")
3638

3739
def test_encode(self):
3840
eq = self.assertEqual
@@ -54,7 +56,6 @@ def test_decode(self):
5456
base64.decode(infp, outfp)
5557
self.assertEqual(outfp.getvalue(), b'www.python.org')
5658

57-
5859

5960
class BaseXYTestCase(unittest.TestCase):
6061
def test_b64encode(self):
@@ -73,7 +74,10 @@ def test_b64encode(self):
7374
b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT"
7475
b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==")
7576
# Test with arbitrary alternative characters
76-
eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars='*$'), b'01a*b$cd')
77+
eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=b'*$'), b'01a*b$cd')
78+
# Check if passing a str object raises an error
79+
self.assertRaises(TypeError, base64.b64encode, "")
80+
self.assertRaises(TypeError, base64.b64encode, b"", altchars="")
7781
# Test standard alphabet
7882
eq(base64.standard_b64encode(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=")
7983
eq(base64.standard_b64encode(b"a"), b"YQ==")
@@ -86,8 +90,13 @@ def test_b64encode(self):
8690
b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
8791
b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT"
8892
b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==")
93+
# Check if passing a str object raises an error
94+
self.assertRaises(TypeError, base64.standard_b64encode, "")
95+
self.assertRaises(TypeError, base64.standard_b64encode, b"", altchars="")
8996
# Test with 'URL safe' alternative characters
9097
eq(base64.urlsafe_b64encode(b'\xd3V\xbeo\xf7\x1d'), b'01a-b_cd')
98+
# Check if passing a str object raises an error
99+
self.assertRaises(TypeError, base64.urlsafe_b64encode, "")
91100

92101
def test_b64decode(self):
93102
eq = self.assertEqual
@@ -104,7 +113,10 @@ def test_b64decode(self):
104113
b"0123456789!@#0^&*();:<>,. []{}")
105114
eq(base64.b64decode(b''), b'')
106115
# Test with arbitrary alternative characters
107-
eq(base64.b64decode(b'01a*b$cd', altchars='*$'), b'\xd3V\xbeo\xf7\x1d')
116+
eq(base64.b64decode(b'01a*b$cd', altchars=b'*$'), b'\xd3V\xbeo\xf7\x1d')
117+
# Check if passing a str object raises an error
118+
self.assertRaises(TypeError, base64.b64decode, "")
119+
self.assertRaises(TypeError, base64.b64decode, b"", altchars="")
108120
# Test standard alphabet
109121
eq(base64.standard_b64decode(b"d3d3LnB5dGhvbi5vcmc="), b"www.python.org")
110122
eq(base64.standard_b64decode(b"YQ=="), b"a")
@@ -117,8 +129,12 @@ def test_b64decode(self):
117129
b"abcdefghijklmnopqrstuvwxyz"
118130
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
119131
b"0123456789!@#0^&*();:<>,. []{}")
132+
# Check if passing a str object raises an error
133+
self.assertRaises(TypeError, base64.standard_b64decode, "")
134+
self.assertRaises(TypeError, base64.standard_b64decode, b"", altchars="")
120135
# Test with 'URL safe' alternative characters
121136
eq(base64.urlsafe_b64decode(b'01a-b_cd'), b'\xd3V\xbeo\xf7\x1d')
137+
self.assertRaises(TypeError, base64.urlsafe_b64decode, "")
122138

123139
def test_b64decode_error(self):
124140
self.assertRaises(binascii.Error, base64.b64decode, b'abc')
@@ -132,6 +148,7 @@ def test_b32encode(self):
132148
eq(base64.b32encode(b'abc'), b'MFRGG===')
133149
eq(base64.b32encode(b'abcd'), b'MFRGGZA=')
134150
eq(base64.b32encode(b'abcde'), b'MFRGGZDF')
151+
self.assertRaises(TypeError, base64.b32encode, "")
135152

136153
def test_b32decode(self):
137154
eq = self.assertEqual
@@ -142,6 +159,7 @@ def test_b32decode(self):
142159
eq(base64.b32decode(b'MFRGG==='), b'abc')
143160
eq(base64.b32decode(b'MFRGGZA='), b'abcd')
144161
eq(base64.b32decode(b'MFRGGZDF'), b'abcde')
162+
self.assertRaises(TypeError, base64.b32decode, "")
145163

146164
def test_b32decode_casefold(self):
147165
eq = self.assertEqual
@@ -163,6 +181,7 @@ def test_b32decode_casefold(self):
163181
eq(base64.b32decode(b'MLO23456'), b'b\xdd\xad\xf3\xbe')
164182
eq(base64.b32decode(b'M1023456', map01=b'L'), b'b\xdd\xad\xf3\xbe')
165183
eq(base64.b32decode(b'M1023456', map01=b'I'), b'b\x1d\xad\xf3\xbe')
184+
self.assertRaises(TypeError, base64.b32decode, b"", map01="")
166185

167186
def test_b32decode_error(self):
168187
self.assertRaises(binascii.Error, base64.b32decode, b'abc')
@@ -172,6 +191,7 @@ def test_b16encode(self):
172191
eq = self.assertEqual
173192
eq(base64.b16encode(b'\x01\x02\xab\xcd\xef'), b'0102ABCDEF')
174193
eq(base64.b16encode(b'\x00'), b'00')
194+
self.assertRaises(TypeError, base64.b16encode, "")
175195

176196
def test_b16decode(self):
177197
eq = self.assertEqual
@@ -181,6 +201,7 @@ def test_b16decode(self):
181201
self.assertRaises(binascii.Error, base64.b16decode, b'0102abcdef')
182202
# Case fold
183203
eq(base64.b16decode(b'0102abcdef', True), b'\x01\x02\xab\xcd\xef')
204+
self.assertRaises(TypeError, base64.b16decode, "")
184205

185206
def test_ErrorHeritage(self):
186207
self.assert_(issubclass(binascii.Error, ValueError))

Lib/urllib2.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ def proxy_open(self, req, proxy, type):
682682
proxy_type = orig_type
683683
if user and password:
684684
user_pass = '%s:%s' % (unquote(user), unquote(password))
685-
creds = str(base64.b64encode(user_pass)).strip()
685+
creds = base64.b64encode(user_pass.encode()).decode("ascii")
686686
req.add_header('Proxy-authorization', 'Basic ' + creds)
687687
hostport = unquote(hostport)
688688
req.set_proxy(hostport, proxy_type)
@@ -808,7 +808,7 @@ def retry_http_basic_auth(self, host, req, realm):
808808
user, pw = self.passwd.find_user_password(realm, host)
809809
if pw is not None:
810810
raw = "%s:%s" % (user, pw)
811-
auth = 'Basic %s' % base64.b64encode(raw).strip().decode()
811+
auth = "Basic " + base64.b64encode(raw.encode()).decode("ascii")
812812
if req.headers.get(self.auth_header, None) == auth:
813813
return None
814814
req.add_header(self.auth_header, auth)

0 commit comments

Comments
 (0)