diff options
author | Haibo Huang <hhb@google.com> | 2020-05-21 21:59:29 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-05-21 21:59:29 +0000 |
commit | 43ecfa8e0c7da5d0653f32296f6f7d218d7be9ea (patch) | |
tree | a417a4c0e74b108ad578d7a9bf188b450d01a485 | |
parent | 787bace63e4495d8e4f0bf74266c589d03eab43d (diff) | |
parent | 8cef85bf284a3b69abebb0ce179004cc74fbbced (diff) | |
download | httplib2-43ecfa8e0c7da5d0653f32296f6f7d218d7be9ea.tar.gz |
Upgrade python/httplib2 to v0.18.1 am: f6b4dcdd5a am: 312ef219b4 am: 8cef85bf28
Change-Id: I0994bafc88ce5f6dd5b343e1bc39a62382d35714
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | CHANGELOG | 23 | ||||
-rw-r--r-- | MANIFEST.in | 7 | ||||
-rw-r--r-- | METADATA | 6 | ||||
-rw-r--r-- | SECURITY.md | 19 | ||||
-rw-r--r-- | pyproject.toml | 9 | ||||
-rw-r--r-- | python2/httplib2/__init__.py | 7 | ||||
-rw-r--r-- | python3/httplib2/__init__.py | 5 | ||||
-rwxr-xr-x | script/release | 21 | ||||
-rwxr-xr-x | setup.py | 2 | ||||
-rw-r--r-- | tests/__init__.py | 2 | ||||
-rw-r--r-- | tests/test_http.py | 30 |
12 files changed, 114 insertions, 19 deletions
diff --git a/.travis.yml b/.travis.yml index 395c507..ed1aa72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ cache: env: global: - - pip_install_common='pip>=9.0 setuptools>=36.2 wheel>=0.30' + - pip_install_common='pip>=9.0 setuptools>=43.0 wheel>=0.30' python: - 2.7 - 3.5 @@ -1,3 +1,26 @@ +0.18.1 + + explicit build-backend workaround for pip build isolation bug + "AttributeError: 'module' object has no attribute '__legacy__'" on pip install + https://github.com/httplib2/httplib2/issues/169 + +0.18.0 + + IMPORTANT security vulnerability CWE-93 CRLF injection + Force %xx quote of space, CR, LF characters in uri. + Special thanks to Recar https://github.com/Ciyfly for discrete notification. + https://cwe.mitre.org/data/definitions/93.html + +0.17.4 + + Ship test suite in source dist + https://github.com/httplib2/httplib2/pull/168 + +0.17.3 + + IronPython2.7: relative import iri2uri fixes ImportError + https://github.com/httplib2/httplib2/pull/163 + 0.17.2 python3 + debug + IPv6 disabled: https raised diff --git a/MANIFEST.in b/MANIFEST.in index 12c4cc7..412def6 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,11 @@ recursive-include python2 *.py *.txt recursive-include python3 *.py *.txt +graft test +graft tests +include *.md +include CHANGELOG +include LICENSE include python2/httplib2/test/*.txt include requirements*.txt +global-exclude __pycache__ +global-exclude *.py[cod] @@ -9,11 +9,11 @@ third_party { type: GIT value: "https://github.com/httplib2/httplib2.git" } - version: "v0.17.2" + version: "v0.18.1" license_type: NOTICE last_upgrade_date { year: 2020 - month: 4 - day: 13 + month: 5 + day: 20 } } diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..5eb3903 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +## Supported Versions + +master branch and latest release get priority support. You should expect all known problems fixed in master. + +All other released versions receive security updates per request. +If you use some old version and can not upgrade for any or no reason, ask for security update release, most likely you will get it. + +## Reporting a Vulnerability + +Contact current maintainers. At 2020-05: temotor@gmail.com or https://t.me/temotor +If that doesn't work, open Github issue just asking for private communication channel. + +This is volunteer maintained project, all issues are processed on best effort basis, no deadlines promised. Of course, security vulnerabilities get priority over regular issues. + +You can expect fame in history or maybe you prefer anonymity - say what you prefer. + +Thank you for responsible handling of security problems. Your attention and effort are appreciated. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5f7cbbd --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ +[build-system] +requires = ["setuptools >= 40.8.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 121 + +[tool.check-manifest] +ignore = [".travis.yml", "script/*", "*.tex"] diff --git a/python2/httplib2/__init__.py b/python2/httplib2/__init__.py index 9057d1f..f35ba48 100644 --- a/python2/httplib2/__init__.py +++ b/python2/httplib2/__init__.py @@ -19,7 +19,7 @@ __contributors__ = [ "Alex Yu", ] __license__ = "MIT" -__version__ = '0.17.2' +__version__ = "0.18.1" import base64 import calendar @@ -129,7 +129,7 @@ if ssl is None: _ssl_wrap_socket = _ssl_wrap_socket_unsupported if sys.version_info >= (2, 3): - from iri2uri import iri2uri + from .iri2uri import iri2uri else: def iri2uri(uri): @@ -1985,6 +1985,9 @@ class Http(object): headers["user-agent"] = "Python-httplib2/%s (gzip)" % __version__ uri = iri2uri(uri) + # Prevent CWE-75 space injection to manipulate request via part of uri. + # Prevent CWE-93 CRLF injection to modify headers via part of uri. + uri = uri.replace(" ", "%20").replace("\r", "%0D").replace("\n", "%0A") (scheme, authority, request_uri, defrag_uri) = urlnorm(uri) diff --git a/python3/httplib2/__init__.py b/python3/httplib2/__init__.py index 135c6f6..cf2db60 100644 --- a/python3/httplib2/__init__.py +++ b/python3/httplib2/__init__.py @@ -15,7 +15,7 @@ __contributors__ = [ "Alex Yu", ] __license__ = "MIT" -__version__ = '0.17.2' +__version__ = "0.18.1" import base64 import calendar @@ -1790,6 +1790,9 @@ a string that contains the response entity body. headers["user-agent"] = "Python-httplib2/%s (gzip)" % __version__ uri = iri2uri(uri) + # Prevent CWE-75 space injection to manipulate request via part of uri. + # Prevent CWE-93 CRLF injection to modify headers via part of uri. + uri = uri.replace(" ", "%20").replace("\r", "%0D").replace("\n", "%0A") (scheme, authority, request_uri, defrag_uri) = urlnorm(uri) diff --git a/script/release b/script/release index 0f98e3e..a2ff80d 100755 --- a/script/release +++ b/script/release @@ -45,9 +45,9 @@ auto_prepare_release() { last_tag=$(git tag --sort=-version:refname |head -n1) last_tag=${last_tag##v} version_replace="${last_tag}.post$(date -u +%y%m%d%H%M)" - update_version "setup.py" "s/VERSION =.+/VERSION = '$version_replace'/" - update_version "python2/httplib2/__init__.py" "s/__version__ =.+/__version__ = '$version_replace'/" - update_version "python3/httplib2/__init__.py" "s/__version__ =.+/__version__ = '$version_replace'/" + update_version "setup.py" "s/VERSION =.+/VERSION = \"$version_replace\"/" + update_version "python2/httplib2/__init__.py" "s/__version__ =.+/__version__ = \"$version_replace\"/" + update_version "python3/httplib2/__init__.py" "s/__version__ =.+/__version__ = \"$version_replace\"/" version_check "$version_replace" fi } @@ -90,10 +90,11 @@ interactive() { local venv=./venv-release if [[ ! -d "$venv" ]] ; then virtualenv $venv - $venv/bin/pip install -U pip setuptools wheel twine + $venv/bin/pip install -U check-manifest pip 'setuptools>=43.0' wheel twine fi $venv/bin/python setup.py clean --all $venv/bin/python setup.py sdist bdist_wheel + $venv/bin/check-manifest || echo "FIXME check-manifest" >&2 if confirm "Upload to PyPI? Use in special situation, normally CI (Travis) will upload to PyPI. [yN] " ; then $venv/bin/twine upload dist/* || exit 1 @@ -132,9 +133,9 @@ bump_version() { fi echo "Next version: '$version_next'" >&2 - update_version "python3/httplib2/__init__.py" "s/__version__ =.+/__version__ = '$version_next'/" - update_version "python2/httplib2/__init__.py" "s/__version__ =.+/__version__ = '$version_next'/" - update_version "setup.py" "s/VERSION =.+/VERSION = '$version_next'/" + update_version "python3/httplib2/__init__.py" "s/__version__ =.+/__version__ = \"$version_next\"/" + update_version "python2/httplib2/__init__.py" "s/__version__ =.+/__version__ = \"$version_next\"/" + update_version "setup.py" "s/VERSION =.+/VERSION = \"$version_next\"/" confirm "Confirm changes? [yN] " || exit 1 } @@ -142,8 +143,8 @@ bump_version() { update_version() { local path="$1" local sed_expr="$2" - # sed -E --in-place='' -e "s/VERSION =.+/VERSION = '$version_replace'/" setup.py - # sed -E --in-place='' -e "s/__version__ =.+/__version__ = '$version_replace'/" python2/httplib2/__init__.py python3/httplib2/__init__.py + # sed -E --in-place='' -e "s/VERSION =.+/VERSION = \"$version_replace\"/" setup.py + # sed -E --in-place='' -e "s/__version__ =.+/__version__ = \"$version_replace\"/" python2/httplib2/__init__.py python3/httplib2/__init__.py echo "Updating file '$path'" >&2 if ! sed -E --in-place='' -e "$sed_expr" "$path" ; then echo "sed error $?" >&2 @@ -209,7 +210,7 @@ assert_tree_clean() { version_check() { local need=$1 - local version_setup=$(fgrep 'VERSION =' setup.py |tr -d " '" |cut -d\= -f2) + local version_setup=$(fgrep 'VERSION =' setup.py |tr -d " '\"" |cut -d\= -f2) local version_py2=$(cd python2 ; python2 -Es -c 'import httplib2;print(httplib2.__version__)') local version_py3=$(cd python3 ; python3 -Es -c 'import httplib2;print(httplib2.__version__)') if [[ "$version_setup" != "$need" ]] ; then @@ -4,7 +4,7 @@ import setuptools.command.test import sys pkgdir = {"": "python%s" % sys.version_info[0]} -VERSION = '0.17.2' +VERSION = "0.18.1" # `python setup.py test` uses existing Python environment, no virtualenv, no pip. diff --git a/tests/__init__.py b/tests/__init__.py index a15db9e..02a3ecf 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -75,7 +75,7 @@ class BufferedReader(object): chunk = b"" else: chunk = self._sock.recv(8 << 10) - # print('!!! recv', chunk) + # print("!!! recv", chunk) if not chunk: self._end = True if untilend: diff --git a/tests/test_http.py b/tests/test_http.py index df99016..f61992c 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -703,3 +703,33 @@ def test_custom_redirect_codes(): response, content = http.request(uri, "GET") assert response.status == 301 assert response.previous is None + + +def test_cwe93_inject_crlf(): + # https://cwe.mitre.org/data/definitions/93.html + # GET /?q= HTTP/1.1 <- injected "HTTP/1.1" from attacker + # injected: attack + # ignore-http: HTTP/1.1 <- nominal "HTTP/1.1" from library + # Host: localhost:57285 + http = httplib2.Http() + with tests.server_reflect() as uri: + danger_url = urllib.parse.urljoin( + uri, "?q= HTTP/1.1\r\ninjected: attack\r\nignore-http:" + ) + response, content = http.request(danger_url, "GET") + assert response.status == 200 + req = tests.HttpRequest.from_bytes(content) + assert req.headers.get("injected") is None + + +def test_inject_space(): + # Injecting space into request line is precursor to CWE-93 and possibly other injections + http = httplib2.Http() + with tests.server_reflect() as uri: + # "\r\nignore-http:" suffix is nuance for current server implementation + # please only pay attention to space after "?q=" + danger_url = urllib.parse.urljoin(uri, "?q= HTTP/1.1\r\nignore-http:") + response, content = http.request(danger_url, "GET") + assert response.status == 200 + req = tests.HttpRequest.from_bytes(content) + assert req.uri == "/?q=%20HTTP/1.1%0D%0Aignore-http:" |