New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed #35326 -- added allow_overwrite
parameter to FileSystemStorage.
#18020
base: main
Are you sure you want to change the base?
Conversation
e9653cd
to
027188b
Compare
027188b
to
0ec0a4d
Compare
What about using the |
OK, so then I would add an |
ce1431e
to
59124ab
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this @bcail! I have initial comments 👍
def get_available_name(self, name, max_length=None): | ||
if self._allow_overwrite: | ||
name = str(name).replace("\\", "/") | ||
dir_name, file_name = os.path.split(name) | ||
if ".." in pathlib.PurePath(dir_name).parts: | ||
raise SuspiciousFileOperation( | ||
"Detected path traversal attempt in '%s'" % dir_name | ||
) | ||
validate_file_name(file_name) | ||
return name | ||
else: | ||
return super().get_available_name(name, max_length) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain why this change is required? I also believe it is untested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is needed so that the name is allowed even if there's already a file by that name. If I remove this change, the two file_storage.tests.OverwritingStorageTests
tests fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to add file_storage.test_generate_filename.GenerateFilenameStorageTests.test_storage_dangerous_paths_dir_name
or create a very similar test for when to FileSystemStorage
has allow_overwrite=True
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think instead of overwriting get_available_name
here, we can overwrite exists
to something like:
def exists(self, name):
exists = os.path.lexists(self.path(name))
if self._allow_overwrite:
return False
return exists
It requires some test updates (these need a think and can probably be better) but something like:
@@ -99,14 +99,14 @@ class FileStorageTests(SimpleTestCase):
f = self.storage.open("storage_test", "w")
f.write("storage contents")
f.close()
- self.assertTrue(self.storage.exists("storage_test"))
+ self.assertTrue(os.path.exists(os.path.join(self.temp_dir, "storage_test")))
f = self.storage.open("storage_test", "r")
self.assertEqual(f.read(), "storage contents")
f.close()
self.storage.delete("storage_test")
- self.assertFalse(self.storage.exists("storage_test"))
+ self.assertFalse(os.path.exists(os.path.join(self.temp_dir, "storage_test")))
def _test_file_time_getter(self, getter):
# Check for correct behavior under both USE_TZ=True and USE_TZ=False.
@@ -275,10 +275,10 @@ class FileStorageTests(SimpleTestCase):
"""
Saving a pathname should create intermediate directories as necessary.
"""
- self.assertFalse(self.storage.exists("path/to"))
+ self.assertFalse(os.path.exists(os.path.join(self.temp_dir, "path/to")))
self.storage.save("path/to/test.file", ContentFile("file saved with path"))
- self.assertTrue(self.storage.exists("path/to"))
+ self.assertTrue(os.path.exists(os.path.join(self.temp_dir, "path/to")))
with self.storage.open("path/to/test.file") as f:
self.assertEqual(f.read(), b"file saved with path")
@@ -694,13 +694,11 @@ class OverwritingStorageTests(FileStorageTests):
stored_name_1 = self.storage.save(name, f_1)
try:
self.assertEqual(stored_name_1, name)
- self.assertTrue(self.storage.exists(name))
self.assertTrue(os.path.exists(os.path.join(self.temp_dir, name)))
with self.storage.open(name) as fp:
self.assertEqual(fp.read(), content_1)
stored_name_2 = self.storage.save(name, f_2)
self.assertEqual(stored_name_2, name)
- self.assertTrue(self.storage.exists(name))
self.assertTrue(os.path.exists(os.path.join(self.temp_dir, name)))
with self.storage.open(name) as fp:
self.assertEqual(fp.read(), content_2)
@@ -722,13 +720,11 @@ class OverwritingStorageTests(FileStorageTests):
stored_name_1 = self.storage.save(name, f_1)
try:
self.assertEqual(stored_name_1, name)
- self.assertTrue(self.storage.exists(name))
self.assertTrue(os.path.exists(os.path.join(self.temp_dir, name)))
with self.storage.open(name) as fp:
self.assertEqual(fp.read(), content_1)
stored_name_2 = self.storage.save(name, f_2)
self.assertEqual(stored_name_2, name)
- self.assertTrue(self.storage.exists(name))
self.assertTrue(os.path.exists(os.path.join(self.temp_dir, name)))
with self.storage.open(name) as fp:
59124ab
to
46802d8
Compare
@sarahboyce Thanks for your review. I've added I added a commit with a warning if the default |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a commit with a warning if the default OS_OPEN_FLAGS is overridden.
Thank you for doing this @bcail, I think this approach looks good to me.
I have a few minor comments, this is getting really close 👍
bb1bfef
to
a876585
Compare
Kind of derailed the original ticket so would rename the title |
allow_overwrite
parameter to FileSystemStorage.
Thank you for the updates @bcail, have you seen this suggestion? |
@sarahboyce I wonder if there would be any downstream code that would want to call But I'll do it whichever way you think is best. |
To clarify my thoughts, if we look at the docs for
I believe it is available for a new file when we are in overwrite mode regardless of whether a file already exists (though we might want to slightly tweak the wording of the true case). I also believe this would better suit the documented approach for writing a custom file storage system (i.e. defining
Thank you for raising this. 👍 @jschneier do you have an opinion here? |
2cb63d6
to
f2b4ec1
Compare
f2b4ec1
to
6375678
Compare
Thank you @bcail 🥳 this looks great, I pushed up small edits and will seek a second opinion before merging 👍 |
Thanks, @sarahboyce. |
Trac ticket number
ticket-35326
Branch description
This patch handled temporary uploaded files when the filesystem storage allows overwriting files.
Checklist
main
branch.