From 8d855d83046dd8a55cd216e642470191e6eab55f Mon Sep 17 00:00:00 2001 From: "R. David Murray" Date: Tue, 21 Dec 2010 21:53:37 +0000 Subject: [PATCH] #4871: check that zipfile password is bytes, and give useful error message. Previously passing a string in as the password would fail either with an assertion error or a TypeError with a confusing error message. Note that a string can't be accepted since zipfile has no way to guess what encoding should be used to turn it into bytes. Patch by Victor Stinner. --- Lib/test/test_zipfile.py | 6 ++++++ Lib/zipfile.py | 14 ++++++++++---- Misc/NEWS | 3 +++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index a0367e188d1..d90e771ccbc 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -1089,6 +1089,12 @@ class DecryptionTests(unittest.TestCase): self.zip2.setpassword(b"12345") self.assertEqual(self.zip2.read("zero"), self.plain2) + def test_unicode_password(self): + self.assertRaises(TypeError, self.zip.setpassword, "unicode") + self.assertRaises(TypeError, self.zip.read, "test.txt", "python") + self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python") + self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python") + class TestsWithRandomBinaryFiles(unittest.TestCase): def setUp(self): diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 35bba7323bd..197f0bc6e1b 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -877,8 +877,12 @@ class ZipFile: def setpassword(self, pwd): """Set default password for encrypted files.""" - assert isinstance(pwd, bytes) - self.pwd = pwd + if pwd and not isinstance(pwd, bytes): + raise TypeError("pwd: expected bytes, got %s" % type(pwd)) + if pwd: + self.pwd = pwd + else: + self.pwd = None def read(self, name, pwd=None): """Return file bytes (as a string) for name.""" @@ -889,6 +893,8 @@ class ZipFile: """Return file-like object for 'name'.""" if mode not in ("r", "U", "rU"): raise RuntimeError('open() requires mode "r", "U", or "rU"') + if pwd and not isinstance(pwd, bytes): + raise TypeError("pwd: expected bytes, got %s" % type(pwd)) if not self.fp: raise RuntimeError( "Attempt to read ZIP archive that was already closed") @@ -949,8 +955,8 @@ class ZipFile: # completely random, while the 12th contains the MSB of the CRC, # or the MSB of the file time depending on the header type # and is used to check the correctness of the password. - bytes = zef_file.read(12) - h = list(map(zd, bytes[0:12])) + header = zef_file.read(12) + h = list(map(zd, header[0:12])) if zinfo.flag_bits & 0x8: # compare against the file type from extended local headers check_byte = (zinfo._raw_time >> 8) & 0xff diff --git a/Misc/NEWS b/Misc/NEWS index 12a5a0ac1e1..9462981d9d1 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -11,6 +11,9 @@ Core and Builtins Library ------- +- Issue #4871: The zipfile module now gives a more useful error message if + an attempt is made to use a string to specify the archive password. + - Issue #10750: The ``raw`` attribute of buffered IO objects is now read-only. - Deprecated assertDictContainsSubclass() in the unittest module.