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
+
21
+
invalid_file_names = [
22
+
os.path.join("path", "to", os.pardir, "test.file"),
23
+
os.path.join(os.path.sep, "path", "to", "test.file"),
24
+
]
25
+
error_msg = "Detected path traversal attempt in '%s'"
26
+
27
+
def test_validate_before_get_available_name(self):
28
+
s = CustomStorage()
29
+
# The initial name passed to `save` is not valid nor safe, fail early.
30
+
for name in self.invalid_file_names:
31
+
with (
32
+
self.subTest(name=name),
33
+
mock.patch.object(s, "get_available_name") as mock_get_available_name,
34
+
mock.patch.object(s, "_save") as mock_internal_save,
35
+
):
36
+
with self.assertRaisesMessage(
37
+
SuspiciousFileOperation, self.error_msg % name
38
+
):
39
+
s.save(name, content="irrelevant")
40
+
self.assertEqual(mock_get_available_name.mock_calls, [])
41
+
self.assertEqual(mock_internal_save.mock_calls, [])
42
+
43
+
def test_validate_after_get_available_name(self):
44
+
s = CustomStorage()
45
+
# The initial name passed to `save` is valid and safe, but the returned
46
+
# name from `get_available_name` is not.
47
+
for name in self.invalid_file_names:
48
+
with (
49
+
self.subTest(name=name),
50
+
mock.patch.object(s, "get_available_name", return_value=name),
51
+
mock.patch.object(s, "_save") as mock_internal_save,
52
+
):
53
+
with self.assertRaisesMessage(
54
+
SuspiciousFileOperation, self.error_msg % name
55
+
):
56
+
s.save("valid-file-name.txt", content="irrelevant")
57
+
self.assertEqual(mock_internal_save.mock_calls, [])
58
+
59
+
def test_validate_after_internal_save(self):
60
+
s = CustomStorage()
61
+
# The initial name passed to `save` is valid and safe, but the result
62
+
# from `_save` is not (this is achieved by monkeypatching _save).
63
+
for name in self.invalid_file_names:
64
+
with (
65
+
self.subTest(name=name),
66
+
mock.patch.object(s, "_save", return_value=name),
67
+
):
68
+
69
+
with self.assertRaisesMessage(
70
+
SuspiciousFileOperation, self.error_msg % name
71
+
):
72
+
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