1
+
import os
2
+
from unittest import mock
3
+
4
+
from django.core.exceptions import SuspiciousFileOperation
5
+
from django.core.files.storage import Storage
6
+
from django.test import SimpleTestCase
7
+
8
+
9
+
class CustomStorage(Storage):
10
+
"""Simple Storage subclass implementing the bare minimum for testing."""
11
+
12
+
def exists(self, name):
13
+
return False
14
+
15
+
def _save(self, name):
16
+
return name
17
+
18
+
19
+
class StorageValidateFileNameTests(SimpleTestCase):
20
+
invalid_file_names = [
21
+
os.path.join("path", "to", os.pardir, "test.file"),
22
+
os.path.join(os.path.sep, "path", "to", "test.file"),
23
+
]
24
+
error_msg = "Detected path traversal attempt in '%s'"
25
+
26
+
def test_validate_before_get_available_name(self):
27
+
s = CustomStorage()
28
+
# The initial name passed to `save` is not valid nor safe, fail early.
29
+
for name in self.invalid_file_names:
30
+
with (
31
+
self.subTest(name=name),
32
+
mock.patch.object(s, "get_available_name") as mock_get_available_name,
33
+
mock.patch.object(s, "_save") as mock_internal_save,
34
+
):
35
+
with self.assertRaisesMessage(
36
+
SuspiciousFileOperation, self.error_msg % name
37
+
):
38
+
s.save(name, content="irrelevant")
39
+
self.assertEqual(mock_get_available_name.mock_calls, [])
40
+
self.assertEqual(mock_internal_save.mock_calls, [])
41
+
42
+
def test_validate_after_get_available_name(self):
43
+
s = CustomStorage()
44
+
# The initial name passed to `save` is valid and safe, but the returned
45
+
# name from `get_available_name` is not.
46
+
for name in self.invalid_file_names:
47
+
with (
48
+
self.subTest(name=name),
49
+
mock.patch.object(s, "get_available_name", return_value=name),
50
+
mock.patch.object(s, "_save") as mock_internal_save,
51
+
):
52
+
with self.assertRaisesMessage(
53
+
SuspiciousFileOperation, self.error_msg % name
54
+
):
55
+
s.save("valid-file-name.txt", content="irrelevant")
56
+
self.assertEqual(mock_internal_save.mock_calls, [])
57
+
58
+
def test_validate_after_internal_save(self):
59
+
s = CustomStorage()
60
+
# The initial name passed to `save` is valid and safe, but the result
61
+
# from `_save` is not (this is achieved by monkeypatching _save).
62
+
for name in self.invalid_file_names:
63
+
with (
64
+
self.subTest(name=name),
65
+
mock.patch.object(s, "_save", return_value=name),
66
+
):
67
+
with self.assertRaisesMessage(
68
+
SuspiciousFileOperation, self.error_msg % name
69
+
):
70
+
s.save("valid-file-name.txt", content="irrelevant")
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4