From 2a6579430649d6514384ca592730c6995e140c43 Mon Sep 17 00:00:00 2001 From: David Lord Date: Mon, 15 May 2017 16:58:01 -0700 Subject: [PATCH] safe_join on Windows uses posixpath fixes #2033 closes #2059 --- flask/helpers.py | 22 ++++++++++++++-------- tests/test_helpers.py | 25 ++++++++++++------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/flask/helpers.py b/flask/helpers.py index 51c3b064..f37be677 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -638,18 +638,24 @@ def safe_join(directory, *pathnames): :raises: :class:`~werkzeug.exceptions.NotFound` if one or more passed paths fall out of its boundaries. """ + + parts = [directory] + for filename in pathnames: if filename != '': filename = posixpath.normpath(filename) - for sep in _os_alt_seps: - if sep in filename: - raise NotFound() - if os.path.isabs(filename) or \ - filename == '..' or \ - filename.startswith('../'): + + if ( + any(sep in filename for sep in _os_alt_seps) + or os.path.isabs(filename) + or filename == '..' + or filename.startswith('../') + ): raise NotFound() - directory = os.path.join(directory, filename) - return directory + + parts.append(filename) + + return posixpath.join(*parts) def send_from_directory(directory, filename, **options): diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 325713c0..d5706521 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -903,21 +903,20 @@ class TestStreaming(object): class TestSafeJoin(object): - def test_safe_join(self): # Valid combinations of *args and expected joined paths. passing = ( - (('a/b/c', ), 'a/b/c'), - (('/', 'a/', 'b/', 'c/', ), '/a/b/c'), - (('a', 'b', 'c', ), 'a/b/c'), - (('/a', 'b/c', ), '/a/b/c'), - (('a/b', 'X/../c'), 'a/b/c', ), - (('/a/b', 'c/X/..'), '/a/b/c', ), + (('a/b/c',), 'a/b/c'), + (('/', 'a/', 'b/', 'c/'), '/a/b/c'), + (('a', 'b', 'c'), 'a/b/c'), + (('/a', 'b/c'), '/a/b/c'), + (('a/b', 'X/../c'), 'a/b/c'), + (('/a/b', 'c/X/..'), '/a/b/c'), # If last path is '' add a slash - (('/a/b/c', '', ), '/a/b/c/', ), + (('/a/b/c', ''), '/a/b/c/'), # Preserve dot slash - (('/a/b/c', './', ), '/a/b/c/.', ), - (('a/b/c', 'X/..'), 'a/b/c/.', ), + (('/a/b/c', './'), '/a/b/c/.'), + (('a/b/c', 'X/..'), 'a/b/c/.'), # Base directory is always considered safe (('../', 'a/b/c'), '../a/b/c'), (('/..', ), '/..'), @@ -931,12 +930,12 @@ class TestSafeJoin(object): failing = ( # path.isabs and ``..'' checks ('/a', 'b', '/c'), - ('/a', '../b/c', ), + ('/a', '../b/c'), ('/a', '..', 'b/c'), # Boundaries violations after path normalization - ('/a', 'b/../b/../../c', ), + ('/a', 'b/../b/../../c'), ('/a', 'b', 'c/../..'), - ('/a', 'b/../../c', ), + ('/a', 'b/../../c'), ) for args in failing: