Python / Django - Safest way to normalize relative paths cross-platform?

87 views Asked by At

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, Django FileField doesn't like the Path object, which want to treat the string as an absolute path by sticking C:\ 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?

0

There are 0 answers