152 lines
4.1 KiB
Python
152 lines
4.1 KiB
Python
#!/usr/bin/env python
|
|
|
|
import os
|
|
import tarfile
|
|
import tempfile
|
|
import zipfile
|
|
|
|
import mozfile
|
|
import mozunit
|
|
import pytest
|
|
import stubs
|
|
|
|
|
|
@pytest.fixture
|
|
def ensure_directory_contents():
|
|
"""ensure the directory contents match"""
|
|
|
|
def inner(directory):
|
|
for f in stubs.files:
|
|
path = os.path.join(directory, *f)
|
|
exists = os.path.exists(path)
|
|
if not exists:
|
|
print("%s does not exist" % (os.path.join(f)))
|
|
assert exists
|
|
if exists:
|
|
contents = open(path).read().strip()
|
|
assert contents == f[-1]
|
|
|
|
return inner
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def tarpath(tmpdir_factory):
|
|
"""create a stub tarball for testing"""
|
|
tmpdir = tmpdir_factory.mktemp("test_extract")
|
|
|
|
tempdir = tmpdir.join("stubs").strpath
|
|
stubs.create_stub(tempdir)
|
|
filename = tmpdir.join("bundle.tar").strpath
|
|
archive = tarfile.TarFile(filename, mode="w")
|
|
for path in stubs.files:
|
|
archive.add(os.path.join(tempdir, *path), arcname=os.path.join(*path))
|
|
archive.close()
|
|
|
|
assert os.path.exists(filename)
|
|
return filename
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def zippath(tmpdir_factory):
|
|
"""create a stub zipfile for testing"""
|
|
tmpdir = tmpdir_factory.mktemp("test_extract")
|
|
|
|
tempdir = tmpdir.join("stubs").strpath
|
|
stubs.create_stub(tempdir)
|
|
filename = tmpdir.join("bundle.zip").strpath
|
|
archive = zipfile.ZipFile(filename, mode="w")
|
|
for path in stubs.files:
|
|
archive.write(os.path.join(tempdir, *path), arcname=os.path.join(*path))
|
|
archive.close()
|
|
|
|
assert os.path.exists(filename)
|
|
return filename
|
|
|
|
|
|
@pytest.fixture(scope="module", params=["tar", "zip"])
|
|
def bundlepath(request, tarpath, zippath):
|
|
if request.param == "tar":
|
|
return tarpath
|
|
else:
|
|
return zippath
|
|
|
|
|
|
def test_extract(tmpdir, bundlepath, ensure_directory_contents):
|
|
"""test extracting a zipfile"""
|
|
dest = tmpdir.mkdir("dest").strpath
|
|
mozfile.extract(bundlepath, dest)
|
|
ensure_directory_contents(dest)
|
|
|
|
|
|
def test_extract_zipfile_missing_file_attributes(tmpdir):
|
|
"""if files do not have attributes set the default permissions have to be inherited."""
|
|
_zipfile = os.path.join(
|
|
os.path.dirname(__file__), "files", "missing_file_attributes.zip"
|
|
)
|
|
assert os.path.exists(_zipfile)
|
|
dest = tmpdir.mkdir("dest").strpath
|
|
|
|
# Get the default file permissions for the user
|
|
fname = os.path.join(dest, "foo")
|
|
with open(fname, "w"):
|
|
pass
|
|
default_stmode = os.stat(fname).st_mode
|
|
|
|
files = mozfile.extract_zip(_zipfile, dest)
|
|
for filename in files:
|
|
assert os.stat(os.path.join(dest, filename)).st_mode == default_stmode
|
|
|
|
|
|
def test_extract_non_archive(tarpath, zippath):
|
|
"""test the generalized extract function"""
|
|
# test extracting some non-archive; this should fail
|
|
fd, filename = tempfile.mkstemp()
|
|
os.write(fd, b"This is not a zipfile or tarball")
|
|
os.close(fd)
|
|
exception = None
|
|
|
|
try:
|
|
dest = tempfile.mkdtemp()
|
|
mozfile.extract(filename, dest)
|
|
except Exception as exc:
|
|
exception = exc
|
|
finally:
|
|
os.remove(filename)
|
|
os.rmdir(dest)
|
|
|
|
assert isinstance(exception, Exception)
|
|
|
|
|
|
def test_extract_ignore(tmpdir, bundlepath):
|
|
dest = tmpdir.mkdir("dest").strpath
|
|
ignore = ("foo", "**/fleem.txt", "read*.txt")
|
|
mozfile.extract(bundlepath, dest, ignore=ignore)
|
|
|
|
assert sorted(os.listdir(dest)) == ["bar.txt", "foo.txt"]
|
|
|
|
|
|
def test_tarball_escape(tmpdir):
|
|
"""Ensures that extracting a tarball can't write outside of the intended
|
|
destination directory.
|
|
"""
|
|
workdir = tmpdir.mkdir("workdir")
|
|
os.chdir(workdir)
|
|
|
|
# Generate a "malicious" bundle.
|
|
with open("bad.txt", "w") as fh:
|
|
fh.write("pwned!")
|
|
|
|
def change_name(tarinfo):
|
|
tarinfo.name = "../" + tarinfo.name
|
|
return tarinfo
|
|
|
|
with tarfile.open("evil.tar", "w:xz") as tar:
|
|
tar.add("bad.txt", filter=change_name)
|
|
|
|
with pytest.raises(RuntimeError):
|
|
mozfile.extract_tarball("evil.tar", workdir)
|
|
assert not os.path.exists(tmpdir.join("bad.txt"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
mozunit.main()
|