From 16685d2ff37f7de5bca5abd67ca468ca84970151 Mon Sep 17 00:00:00 2001 From: Vladimir Diaz Date: Mon, 4 May 2015 15:34:22 -0400 Subject: [PATCH] Add configuration option for supported URI schemes Support only 'http' and 'https' by default. Thanks Marcin W. --- tests/test_download.py | 12 ++++++++++-- tuf/conf.py | 7 +++++++ tuf/download.py | 44 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/tests/test_download.py b/tests/test_download.py index ba774498..136ea2f9 100755 --- a/tests/test_download.py +++ b/tests/test_download.py @@ -160,11 +160,12 @@ def test_download_url_to_tempfileobj_and_performance(self): def test_download_url_to_tempfileobj_and_urls(self): download_file = download.safe_download + unsafe_download_file = download.unsafe_download self.assertRaises(tuf.FormatError, download_file, None, self.target_data_length) - self.assertRaises(ValueError, + self.assertRaises(tuf.FormatError, download_file, self.random_string(), self.target_data_length) @@ -177,8 +178,15 @@ def test_download_url_to_tempfileobj_and_urls(self): download_file, 'http://localhost:' + str(self.PORT+1) + '/' + self.random_string(), self.target_data_length) - + # Specify an unsupported URI scheme. + url_with_unsupported_uri = self.url.replace('http', 'file') + self.assertRaises(tuf.FormatError, download_file, url_with_unsupported_uri, + self.target_data_length) + self.assertRaises(tuf.FormatError, unsafe_download_file, + url_with_unsupported_uri, self.target_data_length) + + def test__get_opener(self): # Test normal case. diff --git a/tuf/conf.py b/tuf/conf.py index 0d6e2a02..480f5d60 100755 --- a/tuf/conf.py +++ b/tuf/conf.py @@ -101,3 +101,10 @@ # to generate the digests listed in metadata and prepended to the filenames of # consistent snapshots. REPOSITORY_HASH_ALGORITHMS = ['sha256'] + +# Software updaters that integrate the framework are required to specify +# the URL prefix for the mirrors that clients can contact to download updates. +# The following URI schemes are those that download.py support. By default, +# the ['http', 'https'] URI schemes are supported, but may be modified by +# integrators to schemes that they wish to support for their integration. +SUPPORTED_URI_SCHEMES = ['http', 'https'] diff --git a/tuf/download.py b/tuf/download.py index 2f9816c2..7a4b2a8c 100755 --- a/tuf/download.py +++ b/tuf/download.py @@ -70,7 +70,8 @@ def safe_download(url, required_length): url: - A URL string that represents the location of the file. + A URL string that represents the location of the file. The URI scheme + component must be one of 'tuf.conf.SUPPORTED_URI_SCHEMES'. required_length: An integer value representing the length of the file. This is an exact @@ -92,6 +93,25 @@ def safe_download(url, required_length): A 'tuf.util.TempFile' file-like object that points to the contents of 'url'. """ + # Do all of the arguments have the appropriate format? + # Raise 'tuf.FormatError' if there is a mismatch. + tuf.formats.URL_SCHEMA.check_match(url) + tuf.formats.LENGTH_SCHEMA.check_match(required_length) + + # Ensure 'url' specifies one of the URI schemes in + # 'tuf.conf.SUPPORTED_URI_SCHEMES'. Be default, ['http', 'https'] is + # supported. If the URI scheme of 'url' is empty or "file", files on the + # local system can be accessed. Unexpected files may be accessed by + # compromised metadata (unlikely to happen if targets.json metadata is signed + # with offline keys). + parsed_url = six.moves.urllib.parse.urlparse(url) + + if parsed_url.scheme not in tuf.conf.SUPPORTED_URI_SCHEMES: + message = \ + repr(url) + ' specifies an unsupported URI scheme. Supported ' + \ + ' URI Schemes: ' + repr(tuf.conf.SUPPORTED_URI_SCHEMES) + raise tuf.FormatError(message) + return _download_file(url, required_length, STRICT_REQUIRED_LENGTH=True) @@ -114,7 +134,8 @@ def unsafe_download(url, required_length): url: - A URL string that represents the location of the file. + A URL string that represents the location of the file. The URI scheme + component must be one of 'tuf.conf.SUPPORTED_URI_SCHEMES'. required_length: An integer value representing the length of the file. This is an upper @@ -136,6 +157,25 @@ def unsafe_download(url, required_length): A 'tuf.util.TempFile' file-like object that points to the contents of 'url'. """ + # Do all of the arguments have the appropriate format? + # Raise 'tuf.FormatError' if there is a mismatch. + tuf.formats.URL_SCHEMA.check_match(url) + tuf.formats.LENGTH_SCHEMA.check_match(required_length) + + # Ensure 'url' specifies one of the URI schemes in + # 'tuf.conf.SUPPORTED_URI_SCHEMES'. Be default, ['http', 'https'] is + # supported. If the URI scheme of 'url' is empty or "file", files on the + # local system can be accessed. Unexpected files may be accessed by + # compromised metadata (unlikely to happen if targets.json metadata is signed + # with offline keys). + parsed_url = six.moves.urllib.parse.urlparse(url) + + if parsed_url.scheme not in tuf.conf.SUPPORTED_URI_SCHEMES: + message = \ + repr(url) + ' specifies an unsupported URI scheme. Supported ' + \ + ' URI Schemes: ' + repr(tuf.conf.SUPPORTED_URI_SCHEMES) + raise tuf.FormatError(message) + return _download_file(url, required_length, STRICT_REQUIRED_LENGTH=False)