Skip to content

Commit

Permalink
Removed SanitizedNames.
Browse files Browse the repository at this point in the history
Restores expectations around special characters in zipfiles, but also restores the infinite loop.
  • Loading branch information
jaraco committed Aug 26, 2024
1 parent 447e7d0 commit 3cb5609
Show file tree
Hide file tree
Showing 3 changed files with 3 additions and 65 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ test = [
"pytest-ignore-flaky",
"jaraco.test",
"importlib_resources; python_version < '3.9'",
"pytest-timeout",
]

doc = [
Expand Down
3 changes: 1 addition & 2 deletions tests/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ def test_getinfo_missing(self, alpharep):
alpharep.getinfo('does-not-exist')

@pytest.mark.xfail(reason="python/cpython#123270")
@pytest.mark.timeout(1)
def test_malformed_paths(self):
"""
Path should handle malformed paths.
Expand All @@ -604,7 +605,6 @@ def test_malformed_paths(self):
]
assert root.joinpath('..').joinpath('parent.txt').read_bytes() == b'content'

@pytest.mark.xfail(reason="python/cpython#123270")
def test_unsupported_names(self):
"""
Path segments with special characters are readable.
Expand All @@ -624,7 +624,6 @@ def test_unsupported_names(self):
assert next(contents).name == 'V: NMS.flac'
assert root.joinpath('V: NMS.flac').read_bytes() == b"fLaC..."

@pytest.mark.xfail(reason="python/cpython#123270")
def test_backslash_not_separator(self):
"""
In a zip file, backslashes are not separators.
Expand Down
64 changes: 1 addition & 63 deletions zipp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,69 +95,7 @@ def __setstate__(self, state):
super().__init__(*args, **kwargs)


class SanitizedNames:
"""
ZipFile mix-in to ensure names are sanitized.
"""

def namelist(self):
return list(map(self._sanitize, super().namelist()))

@staticmethod
def _sanitize(name):
r"""
Ensure a relative path with posix separators and no dot names.
Modeled after
https://github.com/python/cpython/blob/bcc1be39cb1d04ad9fc0bd1b9193d3972835a57c/Lib/zipfile/__init__.py#L1799-L1813
but provides consistent cross-platform behavior.
>>> san = SanitizedNames._sanitize
>>> san('/foo/bar')
'foo/bar'
>>> san('//foo.txt')
'foo.txt'
>>> san('foo/.././bar.txt')
'foo/bar.txt'
>>> san('foo../.bar.txt')
'foo../.bar.txt'
>>> san('\\foo\\bar.txt')
'foo/bar.txt'
>>> san('D:\\foo.txt')
'D/foo.txt'
>>> san('\\\\server\\share\\file.txt')
'server/share/file.txt'
>>> san('\\\\?\\GLOBALROOT\\Volume3')
'?/GLOBALROOT/Volume3'
>>> san('\\\\.\\PhysicalDrive1\\root')
'PhysicalDrive1/root'
Retain any trailing slash.
>>> san('abc/')
'abc/'
Raises a ValueError if the result is empty.
>>> san('../..')
Traceback (most recent call last):
...
ValueError: Empty filename
"""

def allowed(part):
return part and part not in {'..', '.'}

# Remove the drive letter.
# Don't use ntpath.splitdrive, because that also strips UNC paths
bare = re.sub('^([A-Z]):', r'\1', name, flags=re.IGNORECASE)
clean = bare.replace('\\', '/')
parts = clean.split('/')
joined = '/'.join(filter(allowed, parts))
if not joined:
raise ValueError("Empty filename")
return joined + '/' * name.endswith('/')


class CompleteDirs(InitializedState, SanitizedNames, zipfile.ZipFile):
class CompleteDirs(InitializedState, zipfile.ZipFile):
"""
A ZipFile subclass that ensures that implied directories
are always included in the namelist.
Expand Down

0 comments on commit 3cb5609

Please sign in to comment.