-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_archives.py
More file actions
executable file
·64 lines (55 loc) · 2.33 KB
/
Copy pathtest_archives.py
File metadata and controls
executable file
·64 lines (55 loc) · 2.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import zipfile
from pathlib import Path
from tempfile import TemporaryDirectory
from unittest import mock
import archives
from archives import extract_game, safe_zip_extract, validate_7z_paths
def _fake_7z_script(root, *members):
"""An executable stand-in for 7z that prints a -slt listing.
Real 7z separates records with blank lines; only the final trailing
separator is omitted, which is the case the flush must handle.
"""
records = []
for path, size in members:
records.append(f"Path = {path}\nSize = {size}")
listing = "\n\n".join(records)
script = root / "fake-7z"
script.write_text(f"#!/bin/sh\nprintf '%b' {listing!r}\n")
script.chmod(0o755)
return str(script)
def test():
with TemporaryDirectory() as directory:
root = Path(directory)
archive = root / "game.zip"
with zipfile.ZipFile(archive, "w") as package:
package.writestr("readme.txt", "notes")
package.writestr("game.rom", b"real game data")
selected = extract_game(archive, root / "cache")
assert selected.name == "game.rom"
unsafe = root / "unsafe.zip"
with zipfile.ZipFile(unsafe, "w") as package:
package.writestr("../escape.rom", b"bad")
try:
safe_zip_extract(unsafe, root / "unsafe")
except ValueError:
pass
else:
raise AssertionError("path traversal must be rejected")
# A listing without a trailing blank separator must still count its
# final member against the archive safety limits.
fake = _fake_7z_script(root, ("last.rom", 5))
with mock.patch.object(archives, "MAX_ARCHIVE_MEMBERS", 1):
validate_7z_paths(fake, root / "listing.7z")
# Two members cross MAX_ARCHIVE_MEMBERS=1; the second must trip the
# limit even though the listing has no trailing blank line.
fake = _fake_7z_script(root, ("last.rom", 5), ("last2.rom", 5))
with mock.patch.object(archives, "MAX_ARCHIVE_MEMBERS", 1):
try:
validate_7z_paths(fake, root / "listing.7z")
except ValueError as error:
assert "beyond" in str(error)
else:
raise AssertionError("final members must not dodge the limits")
print("archive self-test: ok")
if __name__ == "__main__":
test()