11import os
2- import sys
3- from unittest import skipIf
42
53from django .core .exceptions import SuspiciousFileOperation
64from django .core .files .base import ContentFile
@@ -64,19 +62,37 @@ def test_storage_dangerous_paths_dir_name(self):
6462 s .generate_filename (file_name )
6563
6664 def test_filefield_dangerous_filename (self ):
67- candidates = ['..' , '.' , '' , '???' , '$.$.$' ]
65+ candidates = [
66+ ('..' , 'some/folder/..' ),
67+ ('.' , 'some/folder/.' ),
68+ ('' , 'some/folder/' ),
69+ ('???' , '???' ),
70+ ('$.$.$' , '$.$.$' ),
71+ ]
6872 f = FileField (upload_to = 'some/folder/' )
69- msg = "Could not derive file name from '%s'"
70- for file_name in candidates :
73+ for file_name , msg_file_name in candidates :
74+ msg = f"Could not derive file name from ' { msg_file_name } '"
7175 with self .subTest (file_name = file_name ):
72- with self .assertRaisesMessage (SuspiciousFileOperation , msg % file_name ):
76+ with self .assertRaisesMessage (SuspiciousFileOperation , msg ):
7377 f .generate_filename (None , file_name )
7478
75- def test_filefield_dangerous_filename_dir (self ):
79+ def test_filefield_dangerous_filename_dot_segments (self ):
7680 f = FileField (upload_to = 'some/folder/' )
77- msg = "File name '/tmp/ path' includes path elements "
81+ msg = "Detected path traversal attempt in 'some/folder/../ path'"
7882 with self .assertRaisesMessage (SuspiciousFileOperation , msg ):
79- f .generate_filename (None , '/tmp/path' )
83+ f .generate_filename (None , '../path' )
84+
85+ def test_filefield_generate_filename_absolute_path (self ):
86+ f = FileField (upload_to = 'some/folder/' )
87+ candidates = [
88+ '/tmp/path' ,
89+ '/tmp/../path' ,
90+ ]
91+ for file_name in candidates :
92+ msg = f"Detected path traversal attempt in '{ file_name } '"
93+ with self .subTest (file_name = file_name ):
94+ with self .assertRaisesMessage (SuspiciousFileOperation , msg ):
95+ f .generate_filename (None , file_name )
8096
8197 def test_filefield_generate_filename (self ):
8298 f = FileField (upload_to = 'some/folder/' )
@@ -95,7 +111,57 @@ def upload_to(instance, filename):
95111 os .path .normpath ('some/folder/test_with_space.txt' )
96112 )
97113
98- @skipIf (sys .platform == 'win32' , 'Path components in filename are not supported after 0b79eb3.' )
114+ def test_filefield_generate_filename_upload_to_overrides_dangerous_filename (self ):
115+ def upload_to (instance , filename ):
116+ return 'test.txt'
117+
118+ f = FileField (upload_to = upload_to )
119+ candidates = [
120+ '/tmp/.' ,
121+ '/tmp/..' ,
122+ '/tmp/../path' ,
123+ '/tmp/path' ,
124+ 'some/folder/' ,
125+ 'some/folder/.' ,
126+ 'some/folder/..' ,
127+ 'some/folder/???' ,
128+ 'some/folder/$.$.$' ,
129+ 'some/../test.txt' ,
130+ '' ,
131+ ]
132+ for file_name in candidates :
133+ with self .subTest (file_name = file_name ):
134+ self .assertEqual (f .generate_filename (None , file_name ), 'test.txt' )
135+
136+ def test_filefield_generate_filename_upload_to_absolute_path (self ):
137+ def upload_to (instance , filename ):
138+ return '/tmp/' + filename
139+
140+ f = FileField (upload_to = upload_to )
141+ candidates = [
142+ 'path' ,
143+ '../path' ,
144+ '???' ,
145+ '$.$.$' ,
146+ ]
147+ for file_name in candidates :
148+ msg = f"Detected path traversal attempt in '/tmp/{ file_name } '"
149+ with self .subTest (file_name = file_name ):
150+ with self .assertRaisesMessage (SuspiciousFileOperation , msg ):
151+ f .generate_filename (None , file_name )
152+
153+ def test_filefield_generate_filename_upload_to_dangerous_filename (self ):
154+ def upload_to (instance , filename ):
155+ return '/tmp/' + filename
156+
157+ f = FileField (upload_to = upload_to )
158+ candidates = ['..' , '.' , '' ]
159+ for file_name in candidates :
160+ msg = f"Could not derive file name from '/tmp/{ file_name } '"
161+ with self .subTest (file_name = file_name ):
162+ with self .assertRaisesMessage (SuspiciousFileOperation , msg ):
163+ f .generate_filename (None , file_name )
164+
99165 def test_filefield_awss3_storage (self ):
100166 """
101167 Simulate a FileField with an S3 storage which uses keys rather than
0 commit comments