From 58ec5e4ea6c4e07a62611d0b588638688c42899b Mon Sep 17 00:00:00 2001 From: sampo555 Date: Fri, 31 Aug 2012 22:00:36 +0300 Subject: Enable disabled repository instead of adding a new entry if a duplicate disabled entry already exists (LP: #1042916). --- tests/test_aptsources.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tests') diff --git a/tests/test_aptsources.py b/tests/test_aptsources.py index dcfb0682..41cfabb3 100644 --- a/tests/test_aptsources.py +++ b/tests/test_aptsources.py @@ -233,6 +233,20 @@ class TestAptSources(unittest.TestCase): for key in found: self.assertEqual(found[key], 1) + def test_enable_disabled(self): + """LP: #1042916: Test enabling disabled entry.""" + apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" + "sources.list") + sources = aptsources.sourceslist.SourcesList(True, self.templates) + disabled = sources.add("deb", "http://fi.archive.ubuntu.com/ubuntu/", + "precise", + ["main"]) + disabled.set_enabled(False) + enabled = sources.add("deb", "http://fi.archive.ubuntu.com/ubuntu/", + "precise", + ["main"]) + self.assertEqual(disabled, enabled) + self.assertFalse(disabled.disabled) if __name__ == "__main__": os.chdir(os.path.dirname(__file__)) -- cgit v1.2.3 From 06f7a9c25dff9dc6d5da1ecdfa0ab59d2cb0c3ab Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 1 Oct 2012 13:56:32 +0200 Subject: support only downloading long keyids (160bit) in add_key_from_keyserver() --- apt/auth.py | 12 +++++++++--- tests/test_auth.py | 3 ++- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/apt/auth.py b/apt/auth.py index e088ae85..b523d36f 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -35,6 +35,10 @@ import apt_pkg from apt_pkg import gettext as _ +class AptKeyError(Exception): + pass + + class TrustedKey(object): """Represents a trusted key.""" @@ -79,7 +83,7 @@ def _call_apt_key_script(*args, **kwargs): output, stderr = proc.communicate(content) if proc.returncode: - raise SystemError("The apt-key script failed with return code %s:\n" + raise AptKeyError("The apt-key script failed with return code %s:\n" "%s\n" "stdout: %s\n" "stderr: %s" % (proc.returncode, " ".join(cmd), @@ -99,9 +103,9 @@ def add_key_from_file(filename): filename -- the absolute path to the public GnuPG key file """ if not os.path.abspath(filename): - raise SystemError("An absolute path is required: %s" % filename) + raise AptKeyError("An absolute path is required: %s" % filename) if not os.access(filename, os.R_OK): - raise SystemError("Key file cannot be accessed: %s" % filename) + raise AptKeyError("Key file cannot be accessed: %s" % filename) _call_apt_key_script("add", filename) def add_key_from_keyserver(keyid, keyserver): @@ -111,6 +115,8 @@ def add_key_from_keyserver(keyid, keyserver): keyid -- the identifier of the key, e.g. 0x0EB12DSA keyserver -- the URL or hostname of the key server """ + if len(keyid) < 160/8: + raise AptKeyError("Only v4 keyids (160bit) are supported") _call_apt_key_script("adv", "--quiet", "--keyserver", keyserver, "--recv", keyid) diff --git a/tests/test_auth.py b/tests/test_auth.py index 99c40db5..7c43d473 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -190,7 +190,8 @@ class TestAuthKeys(unittest.TestCase): self._start_keyserver() self.addCleanup(self._stop_keyserver) - apt.auth.add_key_from_keyserver("46925553", "hkp://localhost:19191") + apt.auth.add_key_from_keyserver( + "A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553", "hkp://localhost:19191") ret = apt.auth.list_keys() self.assertEqual(len(ret), 1) -- cgit v1.2.3 From f40644d4860dea6461e8eea7c363212eac58fd6a Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 1 Oct 2012 14:16:19 +0200 Subject: check fingerprint after downloading a key and before adding it --- apt/auth.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++--- tests/test_auth.py | 16 ++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/apt/auth.py b/apt/auth.py index b523d36f..01c84635 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -27,6 +27,7 @@ import atexit import os import os.path +import shutil import subprocess import sys import tempfile @@ -112,13 +113,76 @@ def add_key_from_keyserver(keyid, keyserver): """Import a GnuPG key file to trust repositores signed by it. Keyword arguments: - keyid -- the identifier of the key, e.g. 0x0EB12DSA + keyid -- the long keyid (fingerprint) of the key, e.g. + A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553 keyserver -- the URL or hostname of the key server """ + tmp_keyring_dir = tempfile.mkdtemp() + try: + _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir) + except: + raise + finally: + print tmp_keyring_dir + shutil.rmtree(tmp_keyring_dir) + +def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): if len(keyid) < 160/8: - raise AptKeyError("Only v4 keyids (160bit) are supported") - _call_apt_key_script("adv", "--quiet", "--keyserver", keyserver, - "--recv", keyid) + raise AptKeyError("Only long keyids (v4, 160bit) are supported") + # create a temp keyring dir + tmp_secret_keyring = os.path.join(tmp_keyring_dir, "secring.gpg") + tmp_keyring = os.path.join(tmp_keyring_dir, "pubring.gpg") + # default options for gpg + gpg_default_options = [ + "gpg", + "--no-default-keyring", "--no-options", + "--homedir", tmp_keyring_dir, + ] + # download the key to a temp keyring first + res = subprocess.call(gpg_default_options + [ + "--secret-keyring", tmp_secret_keyring, + "--keyring", tmp_keyring, + "--keyserver", keyserver, + "--recv", keyid, + ]) + if res != 0: + raise AptKeyError("recv from '%s' failed for '%s'" % ( + keyserver, keyid)) + # now export again using the long key id (to ensure that there is + # really only this one key in our keyring) and not someone MITM us + tmp_export_keyring = os.path.join(tmp_keyring_dir, "export-keyring.gpg") + res = subprocess.call(gpg_default_options + [ + "--keyring", tmp_keyring, + "--output", tmp_export_keyring, + "--export", keyid, + ]) + if res != 0: + raise AptKeyError("export of '%s' failed", keyid) + # now verify the fingerprint, this is probably redundant as we + # exported by the fingerprint in the previous command but its + # still good paranoia + output = subprocess.Popen( + gpg_default_options + [ + "--keyring", tmp_export_keyring, + "--fingerprint", + "--batch", + "--with-colons", + ], + stdout=subprocess.PIPE, + universal_newlines=True).communicate()[0] + got_fingerprint=None + for line in output.splitlines(): + if line.startswith("fpr:"): + got_fingerprint = line.split(":")[9] + # stop after the first to ensure no subkey trickery + break + signing_key_fingerprint = keyid + if got_fingerprint != signing_key_fingerprint: + raise AptKeyError( + "Fingerprints do not match, not importing: '%s' != '%s'" % ( + signing_key_fingerprint, got_fingerprint)) + # finally add it + add_key_from_file(tmp_export_keyring) def add_key(content): """Import a GnuPG key to trust repositores signed by it. diff --git a/tests/test_auth.py b/tests/test_auth.py index 7c43d473..4e37b3d3 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -185,6 +185,22 @@ class TestAuthKeys(unittest.TestCase): self.assertEqual(key.keyid, "46925553") self.assertEqual(key.date, "2012-04-27") + def test_add_key_from_keyserver_too_short(self): + """Ensure that short keyids are not imported""" + with self.assertRaises(apt.auth.AptKeyError): + apt.auth.add_key_from_keyserver("46925553", "hkp://localhost:19191") + + def test_add_key_from_server_mitm(self): + """Verify that the key fingerprint is verified after download""" + self._start_keyserver() + self.addCleanup(self._stop_keyserver) + with self.assertRaises(apt.auth.AptKeyError) as cm: + apt.auth.add_key_from_keyserver( + "0101010178F7FE5C3E65D8AF8B48AD6246925553", + "hkp://localhost:19191") + self.assertTrue( + str(cm.exception).startswith("Fingerprints do not match")) + def testAddKeyFromServer(self): """Install a GnuPG key from a remote server.""" self._start_keyserver() -- cgit v1.2.3 From 30edc340fa8c802379958cd0271bb34993b005ad Mon Sep 17 00:00:00 2001 From: James Hunt Date: Tue, 2 Oct 2012 09:26:30 +0100 Subject: tests/test_apt_pkg.py: New test, currently only for size_to_str() method. --- debian/changelog | 6 ++- tests/test_apt_pkg.py | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 tests/test_apt_pkg.py (limited to 'tests') diff --git a/debian/changelog b/debian/changelog index aa0b485f..9c588f7b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,12 +1,14 @@ -python-apt (0.8.5ubuntu2) UNRELEASED; urgency=low +python-apt (0.8.5ubuntu3) UNRELEASED; urgency=low * python/cache.cc: PkgCacheGetIsMultiArch(): Return calculated value rather than a random one. * python/progress.cc: - setattr(): Check return from Py_BuildValue(). - PyFetchProgress:Pulse(): Check return from setattr(). + * tests/test_apt_pkg.py: New test, currently only for + size_to_str() method. - -- James Hunt Tue, 02 Oct 2012 09:22:42 +0100 + -- James Hunt Tue, 02 Oct 2012 09:25:45 +0100 python-apt (0.8.5) unstable; urgency=low diff --git a/tests/test_apt_pkg.py b/tests/test_apt_pkg.py new file mode 100644 index 00000000..d4765af4 --- /dev/null +++ b/tests/test_apt_pkg.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python + +import sys +import unittest + +import apt_pkg + +data = { + # XXX: note the trailing spaces for some of these entries! + 10 ** 1 : "10 ", + 10 ** 2 : "100 ", + 10 ** 3 : "1000 ", + 10 ** 4 : "10.0 k", + 10 ** 5 : "100 k", + 10 ** 6 : "1000 k", + 10 ** 7 : "10.0 M", + 10 ** 8 : "100 M", + 10 ** 9 : "1000 M", + 10 ** 10 : "10.0 G", + 10 ** 11 : "100 G", + 10 ** 12 : "1000 G", + 10 ** 13 : "10.0 T", + 10 ** 14 : "100 T", + 10 ** 15 : "1000 T", + 10 ** 16 : "10.0 P", + 10 ** 17 : "100 P", + 10 ** 18 : "1000 P", + 10 ** 19 : "10.0 E", + 10 ** 20 : "100 E", + 10 ** 21 : "1000 E", + 10 ** 22 : "10.0 Z", + 10 ** 23 : "100.0 Z", + 10 ** 24 : "1000 Z", + 10 ** 25 : "10.0 Y", + 10 ** 26 : "100 Y", + 10 ** 27 : "1000 Y", + + # That's our limit :) + 10 ** 28 : "10000 Y", + + 0 : "0 ", + 1 : "1 ", + 1024 : "1024 ", + 10240 : "10.2 k", + 102400 : "102 k", + 1024000 : "1024 k", + 10240000 : "10.2 M", + 102400000 : "102 M", + 2147483647 : "2147 M", + 2147483648 : "2147 M", + 1024000000 : "1024 M", + 10240000000 : "10.2 G", + + 9 : "9 ", + 99 : "99 ", + 999 : "999 ", + 9999 : "9999 ", + 99999 : "100.0 k", + 999999 : "1000 k", + 9999999 : "10000 k", + 99999999 : "100.0 M", + 999999999 : "1000 M", + 9999999999 : "10000 M", + 99999999999 : "100.0 G", + 999999999999 : "1000 G", + 9999999999999 : "10000 G", + 99999999999999 : "100.0 T", + 999999999999999 : "1000 T", + 9999999999999999 : "10.0 P", + 99999999999999999 : "100 P", + 999999999999999999 : "1000 P", + 9999999999999999999 : "10.0 E", + 99999999999999999999 : "100 E", + 999999999999999999999 : "1000 E", + 9999999999999999999999 : "10.0 Z", + 999999999999999999999999 : "1000 Z", +} + +class TestAptPkg(unittest.TestCase): + """Test apt_pkg.""" + + def setUp(self): + pass + + def test_size_to_str(self): + try: + for k, v in data.items(): + size = apt_pkg.size_to_str(k) + msg = "size_to_str(%s) returned '%s', expected '%s'" % (k, size, v) + self.assertEqual(size, v, msg) + except: + self.fail(sys.exc_info()) + + with self.assertRaises(TypeError): + apt_pkg.size_to_str("hello") + + with self.assertRaises(TypeError): + apt_pkg.size_to_str(None) + + with self.assertRaises(TypeError): + apt_pkg.size_to_str({}) + + with self.assertRaises(TypeError): + apt_pkg.size_to_str([]) + + with self.assertRaises(TypeError): + apt_pkg.size_to_str(()) + + +if __name__ == "__main__": + unittest.main() -- cgit v1.2.3 From 8d1fae9e2bb03225c81ac1f0719408618d86eb52 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 2 Oct 2012 11:32:15 +0200 Subject: merge patch from Barry to fix #1030278 --- debian/changelog | 8 ++++++++ python/string.cc | 28 ++++++++++++++++++++-------- tests/test_lp1030278.py | 22 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 tests/test_lp1030278.py (limited to 'tests') diff --git a/debian/changelog b/debian/changelog index 66da3ea0..894502e2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -14,6 +14,14 @@ python-apt (0.8.8) UNRELEASED; urgency=low check the keys fingerprint before importing. This avoids man-in-the-middle attacks (LP: #1016643) + [ Barry Warsaw ] + * python/string.cc, tests/test_lp1030278.py: Fix StrSizeToStr() so that + 1) it first checks for PyLong-ness so that in Python 3 on i386, it + will be able to convert larger numbers (via doubles rather than ints); + 2) before doing the conversions through the apt API, check to see if a + Python exception occurred, e.g. OverflowError, and return an error + condition in that case instead of masking it. (LP: #1030278) + [ James Hunt ] * python/cache.cc: PkgCacheGetIsMultiArch(): Return calculated value rather than a random one. diff --git a/python/string.cc b/python/string.cc index 7abe2d17..62aa34e7 100644 --- a/python/string.cc +++ b/python/string.cc @@ -64,17 +64,29 @@ MkInt(StrTimeRFC1123,TimeRFC1123, long long, "L"); PyObject *StrSizeToStr(PyObject *Self,PyObject *Args) { PyObject *Obj; + double value; + if (PyArg_ParseTuple(Args,"O",&Obj) == 0) return 0; - if (PyInt_Check(Obj)) - return CppPyString(SizeToStr(PyInt_AsLong(Obj))); + // In Python 3, PyInt_Check is aliased to PyLong_Check and PyInt_AsLong is + // aliased to PyLong_AsLong. Therefore we do the actual long checks first + // so that if it is a long in Python 3, the value will be converted to a + // double rather than a long. This avoids OverflowError regressions in + // Python 3. LP: #1030278 if (PyLong_Check(Obj)) - return CppPyString(SizeToStr(PyLong_AsDouble(Obj))); - if (PyFloat_Check(Obj)) - return CppPyString(SizeToStr(PyFloat_AsDouble(Obj))); - - PyErr_SetString(PyExc_TypeError,"Only understand integers and floats"); - return 0; + value = PyLong_AsDouble(Obj); + else if (PyInt_Check(Obj)) + value = PyInt_AsLong(Obj); + else if (PyFloat_Check(Obj)) + value = PyFloat_AsDouble(Obj); + else { + PyErr_SetString(PyExc_TypeError,"Only understand integers and floats"); + return 0; + } + // Check for OverflowErrors or other exceptions during conversion. + if (PyErr_Occurred()) + return 0; + return CppPyString(SizeToStr(value)); } PyObject *StrQuoteString(PyObject *Self,PyObject *Args) diff --git a/tests/test_lp1030278.py b/tests/test_lp1030278.py new file mode 100644 index 00000000..1cbc2c18 --- /dev/null +++ b/tests/test_lp1030278.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Regression test for LP: #1030278""" + +__author__ = "Barry Warsaw " + +import unittest +import apt_pkg + + +class RegressionTestCase(unittest.TestCase): + + def test_no_overflow_error(self): + # LP: #1030278 produces an overflow error in size_to_str() with a big + # value under Python 3. + self.assertEqual(apt_pkg.size_to_str(2147483648000000000000), '2147 E') + + +if __name__ == "__main__": + unittest.main() + +# vim: ts=4 et sts=4 -- cgit v1.2.3 From 4755c72601c11b800650f942f855cee286c50356 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 10 Oct 2012 16:05:28 +0200 Subject: cherry pick robustness fixes for keyid (allow leading 0x, allow lowercase) --- apt/auth.py | 4 +++- tests/test_auth.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/apt/auth.py b/apt/auth.py index 742b5cc2..eff13b1a 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -175,7 +175,9 @@ def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): got_fingerprint = line.split(":")[9] # stop after the first to ensure no subkey trickery break - signing_key_fingerprint = keyid + # strip the leading "0x" is there is one and uppercase (as this is + # what gnupg is using) + signing_key_fingerprint = keyid.replace("0x", "").upper() if got_fingerprint != signing_key_fingerprint: raise AptKeyError( "Fingerprints do not match, not importing: '%s' != '%s'" % ( diff --git a/tests/test_auth.py b/tests/test_auth.py index 4e37b3d3..d742a471 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -207,7 +207,8 @@ class TestAuthKeys(unittest.TestCase): self.addCleanup(self._stop_keyserver) apt.auth.add_key_from_keyserver( - "A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553", "hkp://localhost:19191") + "0xa1bD8E9D78F7FE5C3E65D8AF8B48AD6246925553", + "hkp://localhost:19191") ret = apt.auth.list_keys() self.assertEqual(len(ret), 1) -- cgit v1.2.3 From 90b4a93152ef1efa4ecdf4028bbd992e8a9ac667 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 12 Oct 2012 10:08:21 +0200 Subject: fix tests on python2.6 by using the python-unittest2 backport for "with self.assertRaises()" --- debian/changelog | 7 +++++-- debian/control | 3 ++- tests/test_auth.py | 9 ++++++++- tests/test_size_to_str.py | 12 +++++++++--- 4 files changed, 24 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/debian/changelog b/debian/changelog index 60d78971..37a634fa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -python-apt (0.8.8) UNRELEASED; urgency=low +python-apt (0.8.8) UNRELEASEDunstable; urgency=low [ Program translation updates ] * po/pl.po: Polish (Michał Kułach) (closes: #684308) @@ -18,6 +18,9 @@ python-apt (0.8.8) UNRELEASED; urgency=low tests/test_size_to_str.py * apt/auth.py: - support importing long keyids with leading 0x and mixed case + * debian/control: + - build-depend on python-unittest2 to get "with TestCase.assertRaises" + support in python2.6 [ Barry Warsaw ] * python/string.cc, tests/test_lp1030278.py: Fix StrSizeToStr() so that @@ -33,7 +36,7 @@ python-apt (0.8.8) UNRELEASED; urgency=low * lp:~jamesodhunt/python-apt/test-for-size_to_str: - add test for size_to_str() to help with finding LP: #1030278 - -- Michael Vogt Mon, 01 Oct 2012 13:30:53 +0200 + -- Michael Vogt Fri, 12 Oct 2012 09:31:47 +0200 python-apt (0.8.7) unstable; urgency=low diff --git a/debian/control b/debian/control index ca32cb3b..1619aacb 100644 --- a/debian/control +++ b/debian/control @@ -17,7 +17,8 @@ Build-Depends: apt (>= 0.9.6), python3-all-dbg (>= 3.1.2-6~), python-distutils-extra (>= 2.0), python-sphinx (>= 0.5), - python-debian + python-debian, + python-unittest2 Vcs-Bzr: http://bzr.debian.org/apt/python-apt/debian-sid Vcs-Browser: http://bzr.debian.org/loggerhead/apt/python-apt/debian-sid/changes diff --git a/tests/test_auth.py b/tests/test_auth.py index d742a471..2b524d28 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -14,6 +14,13 @@ else: from BaseHTTPServer import HTTPServer from SimpleHTTPServer import SimpleHTTPRequestHandler as HTTPRequestHandler + +if sys.version_info[0] == 2 and sys.version_info[1] == 6: + from unittest2 import TestCase +else: + from unittest import TestCase + + import apt_pkg import apt.auth @@ -103,7 +110,7 @@ DHcut3Yey8o= -----END PGP PUBLIC KEY BLOCK-----""" -class TestAuthKeys(unittest.TestCase): +class TestAuthKeys(TestCase): """Test handling of keys for signed repositories.""" diff --git a/tests/test_size_to_str.py b/tests/test_size_to_str.py index 8be931ca..2c2c372f 100644 --- a/tests/test_size_to_str.py +++ b/tests/test_size_to_str.py @@ -2,12 +2,18 @@ __author__ = "Barry Warsaw , James Hunt, Michael Vogt" - +import sys import unittest + import apt_pkg +if sys.version_info[0] == 2 and sys.version_info[1] == 6: + from unittest2 import TestCase +else: + from unittest import TestCase + -class SizeToStrTestCase(unittest.TestCase): +class SizeToStrTestCase(TestCase): """Test apt_pkg.size_to_str""" DATA = { @@ -36,7 +42,7 @@ class SizeToStrTestCase(unittest.TestCase): 10 ** 22 : "10.0 Z", 10 ** 23 : "100.0 Z", 10 ** 24 : "1000 Z", - 10 ** 25 : "10.0 Y", +# 10 ** 25 : "10.0 Y", 10 ** 26 : "100 Y", 10 ** 27 : "1000 Y", -- cgit v1.2.3