Please note this question is about relative paths and must account for cross-platform functionality.
When a user uploads a file, I want to generate a timestamped path to it:
def get_filepath(instance, filename) -> str:
"""
Returns a timestamped directory path to deposit files into.
i.e. "evidence/2023/02/23/96672aa5-94d9-4289-8531-d7a8dc8f060d/data.jpg"
"""
dt = timezone.now()
YYYY = dt.year
MM = str(dt.month).zfill(2)
DD = str(dt.day).zfill(2)
UID = str(uuid.uuid4())
# settings.MEDIA_URL = 'media/', I just checked
path = (str(x) for x in (
settings.MEDIA_URL, 'evidence', YYYY, MM, DD, UID, filename
))
path = os.path.join(*path) # dubious
return path
This is raising SuspiciousFileOperation, which is not at all surprising:
raise SuspiciousFileOperation(
django.core.exceptions.SuspiciousFileOperation: Detected path traversal attempt in '/media/evidence\2023\02\23\1cfa40b9-b522-4c70-b59b-fd270d722ab2\templeos.txt'
I'm at a loss as to how to normalize this though.
pathlib.PurePath-- didn't work, DjangoFileFielddoesn't like thePathobject, which want to treat the string as an absolute path by stickingC:\in front.os.path.normpath-- didn't work either (SuspiciousFileOperation: The joined path (C:\media\evidence\2023\02\23\cc32be4a-76d8-47c5-a274-9783707844b3\templeos.txt) is located outside of the base path component (C:\Users\...)- This does appear to work if I do
str(x).strip('/\\')when defining the path, but this is hacky and the sort of thing I'd expect a proper library to handle...
What am I "supposed" to do to normalize relative paths such that this works on Windows and Linux?