diff --git a/django/utils/archive.py b/django/utils/archive.py
index 13f8afa..f8032d8 100644
a
|
b
|
|
27 | 27 | import zipfile |
28 | 28 | |
29 | 29 | from django.utils import six |
| 30 | from django.utils._os import safe_join |
30 | 31 | |
31 | 32 | |
32 | 33 | class ArchiveException(Exception): |
… |
… |
def extract(self, to_path):
|
146 | 147 | name = member.name |
147 | 148 | if leading: |
148 | 149 | name = self.split_leading_dir(name)[1] |
149 | | filename = os.path.join(to_path, name) |
| 150 | filename = safe_join(to_path, name) |
150 | 151 | if member.isdir(): |
151 | 152 | if filename and not os.path.exists(filename): |
152 | 153 | os.makedirs(filename) |
… |
… |
def extract(self, to_path):
|
187 | 188 | data = self._archive.read(name) |
188 | 189 | if leading: |
189 | 190 | name = self.split_leading_dir(name)[1] |
190 | | filename = os.path.join(to_path, name) |
| 191 | if not name: |
| 192 | continue |
| 193 | filename = safe_join(to_path, name) |
191 | 194 | dirname = os.path.dirname(filename) |
192 | 195 | if dirname and not os.path.exists(dirname): |
193 | 196 | os.makedirs(dirname) |
194 | | if filename.endswith(('/', '\\')): |
| 197 | if name.endswith(('/', '\\')): |
195 | 198 | # A directory |
196 | 199 | if not os.path.exists(filename): |
197 | 200 | os.makedirs(filename) |
diff --git a/tests/utils_tests/archives/absolute.tar b/tests/utils_tests/archives/absolute.tar
new file mode 100644
index 0000000..4522447
Binary files /dev/null and b/tests/utils_tests/archives/absolute.tar differ
diff --git a/tests/utils_tests/archives/dotdot.tar b/tests/utils_tests/archives/dotdot.tar
new file mode 100644
index 0000000..30cf436
Binary files /dev/null and b/tests/utils_tests/archives/dotdot.tar differ
diff --git a/tests/utils_tests/test_archive.py b/tests/utils_tests/test_archive.py
index d1dc5f2..929d22a 100644
a
|
b
|
|
3 | 3 | import tempfile |
4 | 4 | import unittest |
5 | 5 | |
| 6 | from django.core.exceptions import SuspiciousFileOperation |
6 | 7 | from django.utils._os import upath |
7 | 8 | from django.utils.archive import Archive, extract |
8 | 9 | |
… |
… |
def check_files(self, tmpdir):
|
60 | 61 | self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, 'foo', 'bar', '2'))) |
61 | 62 | |
62 | 63 | |
| 64 | class TestSafeUnarchival(unittest.TestCase): |
| 65 | |
| 66 | def setUp(self): |
| 67 | """ |
| 68 | Create temporary directory for testing extraction. |
| 69 | """ |
| 70 | self.old_cwd = os.getcwd() |
| 71 | self.tmpdir = tempfile.mkdtemp() |
| 72 | self.addCleanup(shutil.rmtree, self.tmpdir) |
| 73 | # Always start off in TEST_DIR. |
| 74 | os.chdir(TEST_DIR) |
| 75 | |
| 76 | def test_absolute_path(self): |
| 77 | path = os.path.join(TEST_DIR, 'absolute.tar') |
| 78 | with self.assertRaises(SuspiciousFileOperation): |
| 79 | extract(path) |
| 80 | |
| 81 | def test_no_dotdot_in_path(self): |
| 82 | path = os.path.join(TEST_DIR, 'dotdot.tar') |
| 83 | with self.assertRaises(SuspiciousFileOperation): |
| 84 | extract(path) |
| 85 | |
| 86 | |
63 | 87 | class TestZip(ArchiveTester, unittest.TestCase): |
64 | 88 | archive = 'foobar.zip' |
65 | 89 | |