From 19c73249cae7982358f17311ddd908dc81820874 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 11:01:43 +0000 Subject: [PATCH 01/30] Sort vectors: acme/testdata, separate acme and letsencrypt. --- MANIFEST.in | 2 +- acme/challenges_test.py | 4 ++-- acme/client_test.py | 6 +++--- acme/jose/json_util_test.py | 4 ++-- acme/jose/jwa_test.py | 2 +- acme/jose/jwk_test.py | 8 ++++---- acme/jose/jws_test.py | 6 +++--- acme/jose/util_test.py | 6 +++--- acme/jws_test.py | 2 +- acme/messages_test.py | 8 ++++---- acme/other_test.py | 2 +- acme/{jose => }/testdata/README | 0 acme/testdata/cert-san.pem | 14 ++++++++++++++ acme/{jose => }/testdata/cert.der | Bin acme/testdata/cert.pem | 13 +++++++++++++ acme/testdata/csr-san.pem | 10 ++++++++++ acme/{jose => }/testdata/csr.der | Bin acme/testdata/csr.pem | 10 ++++++++++ acme/testdata/dsa512_key.pem | 14 ++++++++++++++ acme/{jose => }/testdata/rsa1024_key.pem | 0 acme/{jose => }/testdata/rsa256_key.pem | 0 acme/{jose => }/testdata/rsa512_key.pem | 0 letsencrypt/plugins/common_test.py | 5 +++-- .../standalone/tests/authenticator_test.py | 4 ++-- letsencrypt/tests/account_test.py | 2 +- letsencrypt/tests/achallenges_test.py | 3 ++- letsencrypt/tests/crypto_util_test.py | 4 ++-- letsencrypt/tests/proof_of_possession_test.py | 4 ++-- letsencrypt/tests/renewer_test.py | 6 +++--- letsencrypt/tests/revoker_test.py | 2 +- letsencrypt/tests/testdata/cert.der | Bin 0 -> 377 bytes letsencrypt/tests/testdata/rsa256_key.pem | 6 ++++++ letsencrypt/tests/testdata/rsa512_key.pem | 14 +++++++------- letsencrypt/tests/testdata/rsa512_key_2.pem | 9 +++++++++ letsencrypt_apache/tests/util.py | 4 ++-- letsencrypt_nginx/tests/util.py | 4 ++-- setup.py | 1 - 37 files changed, 128 insertions(+), 51 deletions(-) rename acme/{jose => }/testdata/README (100%) create mode 100644 acme/testdata/cert-san.pem rename acme/{jose => }/testdata/cert.der (100%) create mode 100644 acme/testdata/cert.pem create mode 100644 acme/testdata/csr-san.pem rename acme/{jose => }/testdata/csr.der (100%) create mode 100644 acme/testdata/csr.pem create mode 100644 acme/testdata/dsa512_key.pem rename acme/{jose => }/testdata/rsa1024_key.pem (100%) rename acme/{jose => }/testdata/rsa256_key.pem (100%) rename acme/{jose => }/testdata/rsa512_key.pem (100%) create mode 100644 letsencrypt/tests/testdata/cert.der create mode 100644 letsencrypt/tests/testdata/rsa256_key.pem create mode 100644 letsencrypt/tests/testdata/rsa512_key_2.pem diff --git a/MANIFEST.in b/MANIFEST.in index 7ff0a4d0c..900a7ab80 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -6,7 +6,7 @@ include letsencrypt/EULA recursive-include letsencrypt/tests/testdata * recursive-include acme/schemata *.json -recursive-include acme/jose/testdata * +recursive-include acme/testdata * recursive-include letsencrypt_apache/tests/testdata * include letsencrypt_apache/options-ssl-apache.conf diff --git a/acme/challenges_test.py b/acme/challenges_test.py index 94c04388d..40a2455d5 100644 --- a/acme/challenges_test.py +++ b/acme/challenges_test.py @@ -16,10 +16,10 @@ from acme import other CERT = jose.ComparableX509(OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', 'cert.pem')))) + 'acme', os.path.join('testdata', 'cert.pem')))) KEY = serialization.load_pem_private_key( pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'rsa512_key.pem')), + 'acme', os.path.join('testdata', 'rsa512_key.pem')), password=None, backend=default_backend()) diff --git a/acme/client_test.py b/acme/client_test.py index 7e433c91b..abd5e7172 100644 --- a/acme/client_test.py +++ b/acme/client_test.py @@ -18,11 +18,11 @@ from acme import messages_test CERT_DER = pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'cert.der')) + 'acme', os.path.join('testdata', 'cert.der')) KEY = jose.JWKRSA.load(pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'rsa512_key.pem'))) + 'acme', os.path.join('testdata', 'rsa512_key.pem'))) KEY2 = jose.JWKRSA.load(pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'rsa256_key.pem'))) + 'acme', os.path.join('testdata', 'rsa256_key.pem'))) class ClientTest(unittest.TestCase): diff --git a/acme/jose/json_util_test.py b/acme/jose/json_util_test.py index 9e493e80c..458d3b87c 100644 --- a/acme/jose/json_util_test.py +++ b/acme/jose/json_util_test.py @@ -14,10 +14,10 @@ from acme.jose import util CERT = util.ComparableX509(OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', 'cert.pem')))) + 'acme', os.path.join('testdata', 'cert.pem')))) CSR = util.ComparableX509(OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', 'csr.pem')))) + 'acme', os.path.join('testdata', 'csr.pem')))) class FieldTest(unittest.TestCase): diff --git a/acme/jose/jwa_test.py b/acme/jose/jwa_test.py index 147038788..898773716 100644 --- a/acme/jose/jwa_test.py +++ b/acme/jose/jwa_test.py @@ -12,7 +12,7 @@ from acme.jose import jwk_test RSA1024_KEY = serialization.load_pem_private_key( pkg_resources.resource_string( - __name__, os.path.join('testdata', 'rsa1024_key.pem')), + 'acme', os.path.join('testdata', 'rsa1024_key.pem')), password=None, backend=default_backend()) diff --git a/acme/jose/jwk_test.py b/acme/jose/jwk_test.py index 5be28ba17..2e317d3cc 100644 --- a/acme/jose/jwk_test.py +++ b/acme/jose/jwk_test.py @@ -11,14 +11,14 @@ from acme.jose import util DSA_PEM = pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', 'dsa512_key.pem')) + 'acme', os.path.join('testdata', 'dsa512_key.pem')) RSA256_KEY = serialization.load_pem_private_key( pkg_resources.resource_string( - __name__, os.path.join('testdata', 'rsa256_key.pem')), + 'acme', os.path.join('testdata', 'rsa256_key.pem')), password=None, backend=default_backend()) RSA512_KEY = serialization.load_pem_private_key( pkg_resources.resource_string( - __name__, os.path.join('testdata', 'rsa512_key.pem')), + 'acme', os.path.join('testdata', 'rsa512_key.pem')), password=None, backend=default_backend()) @@ -112,7 +112,7 @@ class JWKRSATest(unittest.TestCase): from acme.jose.jwk import JWKRSA self.assertEqual( self.private, JWKRSA.load(pkg_resources.resource_string( - __name__, os.path.join('testdata', 'rsa256_key.pem')))) + 'acme', os.path.join('testdata', 'rsa256_key.pem')))) def test_public_key(self): self.assertEqual(self.jwk256, self.private.public_key()) diff --git a/acme/jose/jws_test.py b/acme/jose/jws_test.py index 72b8b7b22..ecfb11be7 100644 --- a/acme/jose/jws_test.py +++ b/acme/jose/jws_test.py @@ -18,10 +18,10 @@ from acme.jose import util CERT = util.ComparableX509(OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'letsencrypt.tests', 'testdata/cert.pem'))) + 'acme', 'testdata/cert.pem'))) RSA512_KEY = serialization.load_pem_private_key( pkg_resources.resource_string( - __name__, os.path.join('testdata', 'rsa512_key.pem')), + 'acme', os.path.join('testdata', 'rsa512_key.pem')), password=None, backend=default_backend()) @@ -210,7 +210,7 @@ class CLITest(unittest.TestCase): def setUp(self): self.key_path = pkg_resources.resource_filename( - __name__, os.path.join('testdata', 'rsa512_key.pem')) + 'acme', os.path.join('testdata', 'rsa512_key.pem')) def test_unverified(self): from acme.jose.jws import CLI diff --git a/acme/jose/util_test.py b/acme/jose/util_test.py index f29b0792f..8d36de09b 100644 --- a/acme/jose/util_test.py +++ b/acme/jose/util_test.py @@ -17,7 +17,7 @@ class ComparableX509Test(unittest.TestCase): def _load(method, filename): # pylint: disable=missing-docstring return ComparableX509(method( OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', filename)))) + 'acme', os.path.join('testdata', filename)))) self.req1 = _load(OpenSSL.crypto.load_certificate_request, 'csr.pem') self.req2 = _load(OpenSSL.crypto.load_certificate_request, 'csr.pem') @@ -61,13 +61,13 @@ class ComparableRSAKeyTest(unittest.TestCase): def load_key(): # pylint: disable=missing-docstring return ComparableRSAKey(serialization.load_pem_private_key( pkg_resources.resource_string( - __name__, os.path.join('testdata', 'rsa256_key.pem')), + 'acme', os.path.join('testdata', 'rsa256_key.pem')), password=None, backend=backend)) self.key = load_key() self.key_same = load_key() self.key2 = ComparableRSAKey(serialization.load_pem_private_key( pkg_resources.resource_string( - __name__, os.path.join('testdata', 'rsa512_key.pem')), + 'acme', os.path.join('testdata', 'rsa512_key.pem')), password=None, backend=backend)) def test_getattr_proxy(self): diff --git a/acme/jws_test.py b/acme/jws_test.py index e65a3bd46..989a6697a 100644 --- a/acme/jws_test.py +++ b/acme/jws_test.py @@ -12,7 +12,7 @@ from acme import jose RSA512_KEY = serialization.load_pem_private_key( pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'rsa512_key.pem')), + 'acme', os.path.join('testdata', 'rsa512_key.pem')), password=None, backend=default_backend()) diff --git a/acme/messages_test.py b/acme/messages_test.py index d028a59c5..71bf25963 100644 --- a/acme/messages_test.py +++ b/acme/messages_test.py @@ -14,17 +14,17 @@ from acme import jose CERT = jose.ComparableX509(OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'cert.der')))) + 'acme', os.path.join('testdata', 'cert.der')))) CSR = jose.ComparableX509(OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'csr.der')))) + 'acme', os.path.join('testdata', 'csr.der')))) KEY = serialization.load_pem_private_key( pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'rsa512_key.pem')), + 'acme', os.path.join('testdata', 'rsa512_key.pem')), password=None, backend=default_backend()) CERT = jose.ComparableX509(OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'cert.der')))) + 'acme', os.path.join('testdata', 'cert.der')))) class ErrorTest(unittest.TestCase): diff --git a/acme/other_test.py b/acme/other_test.py index 64699038e..25b07bcde 100644 --- a/acme/other_test.py +++ b/acme/other_test.py @@ -11,7 +11,7 @@ from acme import jose KEY = serialization.load_pem_private_key( pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'rsa512_key.pem')), + 'acme', os.path.join('testdata', 'rsa512_key.pem')), password=None, backend=default_backend()) diff --git a/acme/jose/testdata/README b/acme/testdata/README similarity index 100% rename from acme/jose/testdata/README rename to acme/testdata/README diff --git a/acme/testdata/cert-san.pem b/acme/testdata/cert-san.pem new file mode 100644 index 000000000..dcb835994 --- /dev/null +++ b/acme/testdata/cert-san.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICFjCCAcCgAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMx +ETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoM +IlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4 +YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIxODIyMzQ0NVowdzELMAkG +A1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3Ix +KzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDAS +BgNVBAMMC2V4YW1wbGUuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR +7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c ++pVE6K+EdE/twuUCAwEAAaM2MDQwCQYDVR0TBAIwADAnBgNVHREEIDAeggtleGFt +cGxlLmNvbYIPd3d3LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA0EASuvNKFTF +nTJsvnSXn52f4BMZJJ2id/kW7+r+FJRm+L20gKQ1aqq8d3e/lzRUrv5SMf1TAOe7 +RDjyGMKy5ZgM2w== +-----END CERTIFICATE----- diff --git a/acme/jose/testdata/cert.der b/acme/testdata/cert.der similarity index 100% rename from acme/jose/testdata/cert.der rename to acme/testdata/cert.der diff --git a/acme/testdata/cert.pem b/acme/testdata/cert.pem new file mode 100644 index 000000000..96c55cbf4 --- /dev/null +++ b/acme/testdata/cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB3jCCAYigAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMx +ETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoM +IlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4 +YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIxODIyMzQ0NVowdzELMAkG +A1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3Ix +KzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDAS +BgNVBAMMC2V4YW1wbGUuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR +7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c ++pVE6K+EdE/twuUCAwEAATANBgkqhkiG9w0BAQsFAANBAC24z0IdwIVKSlntksll +vr6zJepBH5fMndfk3XJp10jT6VE+14KNtjh02a56GoraAvJAT5/H67E8GvJ/ocNn +B/o= +-----END CERTIFICATE----- diff --git a/acme/testdata/csr-san.pem b/acme/testdata/csr-san.pem new file mode 100644 index 000000000..a7128e35c --- /dev/null +++ b/acme/testdata/csr-san.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBbjCCARgCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIw +EAYDVQQHDAlBbm4gQXJib3IxDDAKBgNVBAoMA0VGRjEfMB0GA1UECwwWVW5pdmVy +c2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wXDANBgkqhkiG +9w0BAQEFAANLADBIAkEArHVztFHtH92ucFJD/N/HW9AsdRsUuHUBBBDlHwNlRd3f +p580rv2+6QWE30cWgdmJS86ObRz6lUTor4R0T+3C5QIDAQABoDowOAYJKoZIhvcN +AQkOMSswKTAnBgNVHREEIDAeggtleGFtcGxlLmNvbYIPd3d3LmV4YW1wbGUuY29t +MA0GCSqGSIb3DQEBCwUAA0EAZGBM8J1rRs7onFgtc76mOeoT1c3v0ZsEmxQfb2Wy +tmReY6X1N4cs38D9VSow+VMRu2LWkKvzS7RUFSaTaeQz1A== +-----END CERTIFICATE REQUEST----- diff --git a/acme/jose/testdata/csr.der b/acme/testdata/csr.der similarity index 100% rename from acme/jose/testdata/csr.der rename to acme/testdata/csr.der diff --git a/acme/testdata/csr.pem b/acme/testdata/csr.pem new file mode 100644 index 000000000..b6818e39d --- /dev/null +++ b/acme/testdata/csr.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBXTCCAQcCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIw +EAYDVQQHDAlBbm4gQXJib3IxDDAKBgNVBAoMA0VGRjEfMB0GA1UECwwWVW5pdmVy +c2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wXDANBgkqhkiG +9w0BAQEFAANLADBIAkEArHVztFHtH92ucFJD/N/HW9AsdRsUuHUBBBDlHwNlRd3f +p580rv2+6QWE30cWgdmJS86ObRz6lUTor4R0T+3C5QIDAQABoCkwJwYJKoZIhvcN +AQkOMRowGDAWBgNVHREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAANB +AHJH/O6BtC9aGzEVCMGOZ7z9iIRHWSzr9x/bOzn7hLwsbXPAgO1QxEwL+X+4g20G +n9XBE1N9W6HCIEut2d8wACg= +-----END CERTIFICATE REQUEST----- diff --git a/acme/testdata/dsa512_key.pem b/acme/testdata/dsa512_key.pem new file mode 100644 index 000000000..78e164712 --- /dev/null +++ b/acme/testdata/dsa512_key.pem @@ -0,0 +1,14 @@ +-----BEGIN DSA PARAMETERS----- +MIGdAkEAwebEoGBfokKQeALHHnAZMQwYU35ILEBdV8oUmzv7qpSVUoHihyqfn6GC +OixAKSP8EJYcTilIqPbFbfFyOPlbLwIVANoFHEDiQgknAvKrG78pHzAJdQSPAkEA +qfka5Bnl+CeEMpzVZGrOVqZE/LFdZK9eT6YtWjzqtIkf3hwXUVxJsTnBG4xmrfvl +41pgNJpgu99YOYqPpS0g7A== +-----END DSA PARAMETERS----- +-----BEGIN DSA PRIVATE KEY----- +MIH5AgEAAkEAwebEoGBfokKQeALHHnAZMQwYU35ILEBdV8oUmzv7qpSVUoHihyqf +n6GCOixAKSP8EJYcTilIqPbFbfFyOPlbLwIVANoFHEDiQgknAvKrG78pHzAJdQSP +AkEAqfka5Bnl+CeEMpzVZGrOVqZE/LFdZK9eT6YtWjzqtIkf3hwXUVxJsTnBG4xm +rfvl41pgNJpgu99YOYqPpS0g7AJATQ2LUzjGQSM6UljcPY5I2OD9THkUR9kH2tth +zZd70UoI9btrVaTizgqYShuok94glSQNK0H92JgUk3scJPaAkAIVAMDn61h6vrCE +mNv063So6E+eYaIN +-----END DSA PRIVATE KEY----- diff --git a/acme/jose/testdata/rsa1024_key.pem b/acme/testdata/rsa1024_key.pem similarity index 100% rename from acme/jose/testdata/rsa1024_key.pem rename to acme/testdata/rsa1024_key.pem diff --git a/acme/jose/testdata/rsa256_key.pem b/acme/testdata/rsa256_key.pem similarity index 100% rename from acme/jose/testdata/rsa256_key.pem rename to acme/testdata/rsa256_key.pem diff --git a/acme/jose/testdata/rsa512_key.pem b/acme/testdata/rsa512_key.pem similarity index 100% rename from acme/jose/testdata/rsa512_key.pem rename to acme/testdata/rsa512_key.pem diff --git a/letsencrypt/plugins/common_test.py b/letsencrypt/plugins/common_test.py index 8688c36b1..b68ab8369 100644 --- a/letsencrypt/plugins/common_test.py +++ b/letsencrypt/plugins/common_test.py @@ -1,4 +1,5 @@ """Tests for letsencrypt.plugins.common.""" +import os import pkg_resources import unittest @@ -111,9 +112,9 @@ class DvsniTest(unittest.TestCase): """Tests for letsencrypt.plugins.common.DvsniTest.""" rsa256_file = pkg_resources.resource_filename( - "acme.jose", "testdata/rsa256_key.pem") + "letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem")) rsa256_pem = pkg_resources.resource_string( - "acme.jose", "testdata/rsa256_key.pem") + "letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem")) auth_key = le_util.Key(rsa256_file, rsa256_pem) achalls = [ diff --git a/letsencrypt/plugins/standalone/tests/authenticator_test.py b/letsencrypt/plugins/standalone/tests/authenticator_test.py index 422dc0549..45c485b5d 100644 --- a/letsencrypt/plugins/standalone/tests/authenticator_test.py +++ b/letsencrypt/plugins/standalone/tests/authenticator_test.py @@ -20,9 +20,9 @@ from letsencrypt.tests import acme_util KEY_PATH = pkg_resources.resource_filename( - "acme.jose", os.path.join("testdata", "rsa512_key.pem")) + "letsencrypt.tests", os.path.join("testdata", "rsa512_key.pem")) KEY_DATA = pkg_resources.resource_string( - "acme.jose", os.path.join("testdata", "rsa512_key.pem")) + "letsencrypt.tests", os.path.join("testdata", "rsa512_key.pem")) KEY = jose.JWKRSA(key=jose.ComparableRSAKey(serialization.load_pem_private_key( KEY_DATA, password=None, backend=default_backend()))) PRIVATE_KEY = OpenSSL.crypto.load_privatekey( diff --git a/letsencrypt/tests/account_test.py b/letsencrypt/tests/account_test.py index 93da225af..9a129dbe6 100644 --- a/letsencrypt/tests/account_test.py +++ b/letsencrypt/tests/account_test.py @@ -17,7 +17,7 @@ from letsencrypt import errors KEY = jose.JWKRSA.load(pkg_resources.resource_string( - __name__, os.path.join("testdata", "rsa512_key.pem"))) + "letsencrypt.tests", os.path.join("testdata", "rsa512_key_2.pem"))) class AccountTest(unittest.TestCase): diff --git a/letsencrypt/tests/achallenges_test.py b/letsencrypt/tests/achallenges_test.py index e6c154aae..4faa34d12 100644 --- a/letsencrypt/tests/achallenges_test.py +++ b/letsencrypt/tests/achallenges_test.py @@ -24,7 +24,8 @@ class DVSNITest(unittest.TestCase): key = jose.JWKRSA(key=jose.ComparableRSAKey( serialization.load_pem_private_key( pkg_resources.resource_string( - "acme.jose", os.path.join("testdata", "rsa512_key.pem")), + "letsencrypt.tests", os.path.join( + "testdata", "rsa512_key.pem")), password=None, backend=default_backend()))) from letsencrypt.achallenges import DVSNI diff --git a/letsencrypt/tests/crypto_util_test.py b/letsencrypt/tests/crypto_util_test.py index 06bdc4cd8..2e1e62797 100644 --- a/letsencrypt/tests/crypto_util_test.py +++ b/letsencrypt/tests/crypto_util_test.py @@ -11,9 +11,9 @@ import mock RSA256_KEY = pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'rsa256_key.pem')) + 'letsencrypt.tests', os.path.join('testdata', 'rsa256_key.pem')) RSA512_KEY = pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'rsa512_key.pem')) + 'letsencrypt.tests', os.path.join('testdata', 'rsa512_key.pem')) CERT = pkg_resources.resource_string( 'letsencrypt.tests', os.path.join('testdata', 'cert.pem')) SAN_CERT = pkg_resources.resource_string( diff --git a/letsencrypt/tests/proof_of_possession_test.py b/letsencrypt/tests/proof_of_possession_test.py index d91b8bdb6..ef0ffc21e 100644 --- a/letsencrypt/tests/proof_of_possession_test.py +++ b/letsencrypt/tests/proof_of_possession_test.py @@ -19,7 +19,7 @@ from letsencrypt.display import util as display_util BASE_PACKAGE = "letsencrypt.tests" CERT0_PATH = pkg_resources.resource_filename( - "acme.jose", os.path.join("testdata", "cert.der")) + BASE_PACKAGE, os.path.join("testdata", "cert.der")) CERT2_PATH = pkg_resources.resource_filename( BASE_PACKAGE, os.path.join("testdata", "dsa_cert.pem")) CERT2_KEY_PATH = pkg_resources.resource_filename( @@ -27,7 +27,7 @@ CERT2_KEY_PATH = pkg_resources.resource_filename( CERT3_PATH = pkg_resources.resource_filename( BASE_PACKAGE, os.path.join("testdata", "matching_cert.pem")) CERT3_KEY_PATH = pkg_resources.resource_filename( - BASE_PACKAGE, os.path.join("testdata", "rsa512_key.pem")) + BASE_PACKAGE, os.path.join("testdata", "rsa512_key_2.pem")) with open(CERT3_KEY_PATH) as cert3_file: CERT3_KEY = serialization.load_pem_private_key( cert3_file.read(), password=None, diff --git a/letsencrypt/tests/renewer_test.py b/letsencrypt/tests/renewer_test.py index 3596201b3..4ee7cc0e8 100644 --- a/letsencrypt/tests/renewer_test.py +++ b/letsencrypt/tests/renewer_test.py @@ -296,7 +296,7 @@ class RenewableCertTests(unittest.TestCase): def _test_notafterbefore(self, function, timestamp): test_cert = pkg_resources.resource_string( - "letsencrypt.tests", "testdata/cert.pem") + "letsencrypt.tests", os.path.join("testdata", "cert.pem")) os.symlink(os.path.join("..", "..", "archive", "example.org", "cert12.pem"), self.test_rc.cert) with open(self.test_rc.cert, "w") as f: @@ -320,7 +320,7 @@ class RenewableCertTests(unittest.TestCase): """Test should_autodeploy() and should_autorenew() on the basis of expiry time windows.""" test_cert = pkg_resources.resource_string( - "letsencrypt.tests", "testdata/cert.pem") + "letsencrypt.tests", os.path.join("testdata", "cert.pem")) for kind in ALL_FOUR: where = getattr(self.test_rc, kind) os.symlink(os.path.join("..", "..", "archive", "example.org", @@ -562,7 +562,7 @@ class RenewableCertTests(unittest.TestCase): from letsencrypt import renewer test_cert = pkg_resources.resource_string( - "letsencrypt.tests", "testdata/cert-san.pem") + "letsencrypt.tests", os.path.join("testdata", "cert-san.pem")) for kind in ALL_FOUR: os.symlink(os.path.join("..", "..", "archive", "example.org", kind + "1.pem"), diff --git a/letsencrypt/tests/revoker_test.py b/letsencrypt/tests/revoker_test.py index f90da2168..92eeaf92d 100644 --- a/letsencrypt/tests/revoker_test.py +++ b/letsencrypt/tests/revoker_test.py @@ -99,7 +99,7 @@ class RevokerTest(RevokerBase): mock_display().confirm_revocation.return_value = True key_path = pkg_resources.resource_filename( - "acme.jose", os.path.join("testdata", "rsa256_key.pem")) + "letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem")) wrong_key = le_util.Key(key_path, open(key_path).read()) self.revoker.revoke_from_key(wrong_key) diff --git a/letsencrypt/tests/testdata/cert.der b/letsencrypt/tests/testdata/cert.der new file mode 100644 index 0000000000000000000000000000000000000000..5f1018505d81a50ed3239d829533deac5fcc2085 GIT binary patch literal 377 zcmXqLVk|XiVw7LN%*4pV#L2Ms(6oH-+lDa)ylk9WZ60mkc^MhGSs4t(3`Got*qB3E zn0dHUD-v@Ha#Hn@^K%X4#CZ)(4a|&;3``6RjLoCKTyr=Vr#=)57+D#Zy%`KVm>e0_ zlooFZd@FxGb01z;s66b16iPJW%*ddSVYv$pLpwieafaMs>~58{VWGc zu1@bVkOxUCvq%_-HDFi315zN&!fL?G$oL;EIG7z7c)I@!HO%vwut#mfG=7{>z}O6i?Kd^cJYN9>LqE5%h;CwZnWA40OQJj AMgRZ+ literal 0 HcmV?d00001 diff --git a/letsencrypt/tests/testdata/rsa256_key.pem b/letsencrypt/tests/testdata/rsa256_key.pem new file mode 100644 index 000000000..659274d1d --- /dev/null +++ b/letsencrypt/tests/testdata/rsa256_key.pem @@ -0,0 +1,6 @@ +-----BEGIN RSA PRIVATE KEY----- +MIGrAgEAAiEAm2Fylv+Uz7trgTW8EBHP3FQSMeZs2GNQ6VRo1sIVJEkCAwEAAQIh +AJT0BA/xD01dFCAXzSNyj9nfSZa3NpqzJZZn/eOm7vghAhEAzUVNZn4lLLBD1R6N +E8TKNQIRAMHHyn3O5JeY36lwKwkUlEUCEAliRauN0L0+QZuYjfJ9aJECEGx4dru3 +rTPCyighdqWNlHUCEQCiLjlwSRtWgmMBudCkVjzt +-----END RSA PRIVATE KEY----- diff --git a/letsencrypt/tests/testdata/rsa512_key.pem b/letsencrypt/tests/testdata/rsa512_key.pem index 709b6d8e3..610c8d315 100644 --- a/letsencrypt/tests/testdata/rsa512_key.pem +++ b/letsencrypt/tests/testdata/rsa512_key.pem @@ -1,9 +1,9 @@ -----BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBAPS2EXFRNza/qpXnnBHF/CcFQ543htV+7nLAmrLrmTNHtPXJmLlM -8SJDIzv/ceAFXL110VzxFfi81lpH5E5c0TMCAwEAAQJBALmppYQ/JVARjWBcsEm/ -1/bXBJ127YLv4gQIY5baL4r6IdEE33OXMTTmD9wf+ajuq1eaH0htHkwhOvREu0sz -bskCIQD/Cg+xhEVLcwK3pFp3afPIhj1IPFiL3Uy/nqyMZ6O/RQIhAPWiDBofp7Cp -J4dGZs+hkRySq/IOeeRJlNK1Pq64nToXAiBZ7+te1100YSd5KT051SRB94zO13EG -SZESFduVW8rz3QIgK+tLiqg6TYYRQUi/PUTAM4GuKNuZw828RGiPyqHLywUCIQCd -pkZrNphL/y0D7HSbPIfZzD90M2V8tUjlK0BTqk1bHA== +MIIBOgIBAAJBAKx1c7RR7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79 +vukFhN9HFoHZiUvOjm0c+pVE6K+EdE/twuUCAwEAAQJAMbrEnJCrQe8YqAbw1/Bn +elAzIamndfE3U8bTavf9sgFpS4HL83rhd6PDbvx81ucaJAT/5x048fM/nFl4fzAc +mQIhAOF/a9o3EIsDKEmUl+Z1OaOiUxDF3kqWSmALEsmvDhwXAiEAw8ljV5RO/rUp +Zu2YMDFq3MKpyyMgBIJ8CxmGRc6gCmMCIGRQzkcmhfqBrhOFwkmozrqIBRIKJIjj +8TRm2LXWZZ2DAiAqVO7PztdNpynugUy4jtbGKKjBrTSNBRGA7OHlUgm0dQIhALQq +6oGU29Vxlvt3k0vmiRKU4AVfLyNXIGtcWcNG46h/ -----END RSA PRIVATE KEY----- diff --git a/letsencrypt/tests/testdata/rsa512_key_2.pem b/letsencrypt/tests/testdata/rsa512_key_2.pem new file mode 100644 index 000000000..709b6d8e3 --- /dev/null +++ b/letsencrypt/tests/testdata/rsa512_key_2.pem @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBOwIBAAJBAPS2EXFRNza/qpXnnBHF/CcFQ543htV+7nLAmrLrmTNHtPXJmLlM +8SJDIzv/ceAFXL110VzxFfi81lpH5E5c0TMCAwEAAQJBALmppYQ/JVARjWBcsEm/ +1/bXBJ127YLv4gQIY5baL4r6IdEE33OXMTTmD9wf+ajuq1eaH0htHkwhOvREu0sz +bskCIQD/Cg+xhEVLcwK3pFp3afPIhj1IPFiL3Uy/nqyMZ6O/RQIhAPWiDBofp7Cp +J4dGZs+hkRySq/IOeeRJlNK1Pq64nToXAiBZ7+te1100YSd5KT051SRB94zO13EG +SZESFduVW8rz3QIgK+tLiqg6TYYRQUi/PUTAM4GuKNuZw828RGiPyqHLywUCIQCd +pkZrNphL/y0D7HSbPIfZzD90M2V8tUjlK0BTqk1bHA== +-----END RSA PRIVATE KEY----- diff --git a/letsencrypt_apache/tests/util.py b/letsencrypt_apache/tests/util.py index 0769f6050..b7048035a 100644 --- a/letsencrypt_apache/tests/util.py +++ b/letsencrypt_apache/tests/util.py @@ -29,9 +29,9 @@ class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods self.temp_dir, "debian_apache_2_4/two_vhost_80/apache2") self.rsa256_file = pkg_resources.resource_filename( - "acme.jose", "testdata/rsa256_key.pem") + "letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem")) self.rsa256_pem = pkg_resources.resource_string( - "acme.jose", "testdata/rsa256_key.pem") + "letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem")) def get_apache_configurator( diff --git a/letsencrypt_nginx/tests/util.py b/letsencrypt_nginx/tests/util.py index 414a2f315..a7db398c6 100644 --- a/letsencrypt_nginx/tests/util.py +++ b/letsencrypt_nginx/tests/util.py @@ -26,9 +26,9 @@ class NginxTest(unittest.TestCase): # pylint: disable=too-few-public-methods self.config_path = os.path.join(self.temp_dir, "etc_nginx") self.rsa256_file = pkg_resources.resource_filename( - "acme.jose", "testdata/rsa256_key.pem") + "letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem")) self.rsa256_pem = pkg_resources.resource_string( - "acme.jose", "testdata/rsa256_key.pem") + "letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem")) def get_data_filename(filename): diff --git a/setup.py b/setup.py index 49ac5a6c0..b2bd0e652 100644 --- a/setup.py +++ b/setup.py @@ -38,7 +38,6 @@ acme_install_requires = [ # load_pem_private/public_key (>=0.6) # rsa_recover_prime_factors (>=0.8) 'cryptography>=0.8', - #'letsencrypt' # TODO: uses testdata vectors 'mock<1.1.0', # py26 'pyrfc3339', 'ndg-httpsclient', # urllib3 InsecurePlatformWarning (#304) From 0e474436c4295c9d6697fc7ef735c27db5b862a0 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 12:26:51 +0000 Subject: [PATCH 02/30] Unified vector loading in acme. --- acme/challenges_test.py | 14 ++-------- acme/client_test.py | 12 +++----- acme/jose/json_util_test.py | 13 +++------ acme/jose/jwa_test.py | 26 +++++++----------- acme/jose/jwk_test.py | 34 ++++++++--------------- acme/jose/jws_test.py | 21 ++++---------- acme/jose/util_test.py | 42 ++++++++-------------------- acme/jws_test.py | 13 ++------- acme/messages_test.py | 22 +++------------ acme/other_test.py | 11 ++------ acme/test_util.py | 55 +++++++++++++++++++++++++++++++++++++ acme/testdata/README | 4 +++ 12 files changed, 119 insertions(+), 148 deletions(-) create mode 100644 acme/test_util.py diff --git a/acme/challenges_test.py b/acme/challenges_test.py index 40a2455d5..a1214c2f9 100644 --- a/acme/challenges_test.py +++ b/acme/challenges_test.py @@ -1,10 +1,6 @@ """Tests for acme.challenges.""" -import os -import pkg_resources import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization import mock import OpenSSL import requests @@ -12,15 +8,11 @@ import urlparse from acme import jose from acme import other +from acme import test_util -CERT = jose.ComparableX509(OpenSSL.crypto.load_certificate( - OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'cert.pem')))) -KEY = serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa512_key.pem')), - password=None, backend=default_backend()) +CERT = test_util.load_cert('cert.pem') +KEY = test_util.load_rsa_private_key('rsa512_key.pem') class ChallengeResponseTest(unittest.TestCase): diff --git a/acme/client_test.py b/acme/client_test.py index abd5e7172..3e3380a16 100644 --- a/acme/client_test.py +++ b/acme/client_test.py @@ -2,8 +2,6 @@ import datetime import httplib import json -import os -import pkg_resources import unittest import mock @@ -15,14 +13,12 @@ from acme import jose from acme import jws as acme_jws from acme import messages from acme import messages_test +from acme import test_util -CERT_DER = pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'cert.der')) -KEY = jose.JWKRSA.load(pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa512_key.pem'))) -KEY2 = jose.JWKRSA.load(pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa256_key.pem'))) +CERT_DER = test_util.load_vector('cert.der') +KEY = jose.JWKRSA.load(test_util.load_vector('rsa512_key.pem')) +KEY2 = jose.JWKRSA.load(test_util.load_vector('rsa256_key.pem')) class ClientTest(unittest.TestCase): diff --git a/acme/jose/json_util_test.py b/acme/jose/json_util_test.py index 458d3b87c..9e2a87858 100644 --- a/acme/jose/json_util_test.py +++ b/acme/jose/json_util_test.py @@ -1,23 +1,18 @@ """Tests for acme.jose.json_util.""" import itertools -import os -import pkg_resources import unittest import mock -import OpenSSL + +from acme import test_util from acme.jose import errors from acme.jose import interfaces from acme.jose import util -CERT = util.ComparableX509(OpenSSL.crypto.load_certificate( - OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'cert.pem')))) -CSR = util.ComparableX509(OpenSSL.crypto.load_certificate_request( - OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'csr.pem')))) +CERT = test_util.load_cert('cert.pem') +CSR = test_util.load_csr('csr.pem') class FieldTest(unittest.TestCase): diff --git a/acme/jose/jwa_test.py b/acme/jose/jwa_test.py index 898773716..1a3896f4a 100644 --- a/acme/jose/jwa_test.py +++ b/acme/jose/jwa_test.py @@ -1,19 +1,14 @@ """Tests for acme.jose.jwa.""" -import os -import pkg_resources import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization +from acme import test_util from acme.jose import errors -from acme.jose import jwk_test -RSA1024_KEY = serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa1024_key.pem')), - password=None, backend=default_backend()) +RSA256_KEY = test_util.load_rsa_private_key('rsa256_key.pem') +RSA512_KEY = test_util.load_rsa_private_key('rsa512_key.pem') +RSA1024_KEY = test_util.load_rsa_private_key('rsa1024_key.pem') class JWASignatureTest(unittest.TestCase): @@ -76,13 +71,13 @@ class JWARSTest(unittest.TestCase): def test_sign_no_private_part(self): from acme.jose.jwa import RS256 self.assertRaises( - errors.Error, RS256.sign, jwk_test.RSA512_KEY.public_key(), 'foo') + errors.Error, RS256.sign, RSA512_KEY.public_key(), 'foo') def test_sign_key_too_small(self): from acme.jose.jwa import RS256 from acme.jose.jwa import PS256 - self.assertRaises(errors.Error, RS256.sign, jwk_test.RSA256_KEY, 'foo') - self.assertRaises(errors.Error, PS256.sign, jwk_test.RSA256_KEY, 'foo') + self.assertRaises(errors.Error, RS256.sign, RSA256_KEY, 'foo') + self.assertRaises(errors.Error, PS256.sign, RSA256_KEY, 'foo') def test_rs(self): from acme.jose.jwa import RS256 @@ -92,11 +87,10 @@ class JWARSTest(unittest.TestCase): '\xa4\x99\x1e\x19&\xd8\xc7\x99S\x97\xfc\x85\x0cOV\xe6\x07\x99' '\xd2\xb9.>}\xfd' ) - self.assertEqual(RS256.sign(jwk_test.RSA512_KEY, 'foo'), sig) - self.assertTrue(RS256.verify( - jwk_test.RSA512_KEY.public_key(), 'foo', sig)) + self.assertEqual(RS256.sign(RSA512_KEY, 'foo'), sig) + self.assertTrue(RS256.verify(RSA512_KEY.public_key(), 'foo', sig)) self.assertFalse(RS256.verify( - jwk_test.RSA512_KEY.public_key(), 'foo', sig + '!')) + RSA512_KEY.public_key(), 'foo', sig + '!')) def test_ps(self): from acme.jose.jwa import PS256 diff --git a/acme/jose/jwk_test.py b/acme/jose/jwk_test.py index 2e317d3cc..86674b726 100644 --- a/acme/jose/jwk_test.py +++ b/acme/jose/jwk_test.py @@ -1,25 +1,15 @@ """Tests for acme.jose.jwk.""" -import os -import pkg_resources import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization +from acme import test_util from acme.jose import errors from acme.jose import util -DSA_PEM = pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'dsa512_key.pem')) -RSA256_KEY = serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa256_key.pem')), - password=None, backend=default_backend()) -RSA512_KEY = serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa512_key.pem')), - password=None, backend=default_backend()) +DSA_PEM = test_util.load_vector('dsa512_key.pem') +RSA256_KEY = test_util.load_rsa_private_key('rsa256_key.pem') +RSA512_KEY = test_util.load_rsa_private_key('rsa512_key.pem') class JWKTest(unittest.TestCase): @@ -73,8 +63,8 @@ class JWKRSATest(unittest.TestCase): 'e': 'AQAB', 'n': 'm2Fylv-Uz7trgTW8EBHP3FQSMeZs2GNQ6VRo1sIVJEk', } - self.jwk256_comparable = JWKRSA(key=util.ComparableRSAKey( - RSA256_KEY.public_key())) + # pylint: disable=protected-access + self.jwk256_not_comparable = JWKRSA(key=RSA256_KEY.public_key()._wrapped) self.jwk512 = JWKRSA(key=RSA512_KEY.public_key()) self.jwk512json = { 'kty': 'RSA', @@ -96,9 +86,10 @@ class JWKRSATest(unittest.TestCase): 'qi': 'oi45cEkbVoJjAbnQpFY87Q', }) - def test_init_comparable(self): - self.assertTrue(isinstance(self.jwk256.key, util.ComparableRSAKey)) - self.assertEqual(self.jwk256, self.jwk256_comparable) + def test_init_auto_comparable(self): + self.assertTrue(isinstance( + self.jwk256_not_comparable.key, util.ComparableRSAKey)) + self.assertEqual(self.jwk256, self.jwk256_not_comparable) def test_equals(self): self.assertEqual(self.jwk256, self.jwk256) @@ -110,9 +101,8 @@ class JWKRSATest(unittest.TestCase): def test_load(self): from acme.jose.jwk import JWKRSA - self.assertEqual( - self.private, JWKRSA.load(pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa256_key.pem')))) + self.assertEqual(self.private, JWKRSA.load( + test_util.load_vector('rsa256_key.pem'))) def test_public_key(self): self.assertEqual(self.jwk256, self.private.public_key()) diff --git a/acme/jose/jws_test.py b/acme/jose/jws_test.py index ecfb11be7..7a3e8cb83 100644 --- a/acme/jose/jws_test.py +++ b/acme/jose/jws_test.py @@ -1,28 +1,20 @@ """Tests for acme.jose.jws.""" import base64 -import os -import pkg_resources import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization import mock import OpenSSL +from acme import test_util + from acme.jose import b64 from acme.jose import errors from acme.jose import jwa from acme.jose import jwk -from acme.jose import util -CERT = util.ComparableX509(OpenSSL.crypto.load_certificate( - OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'acme', 'testdata/cert.pem'))) -RSA512_KEY = serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa512_key.pem')), - password=None, backend=default_backend()) +CERT = test_util.load_cert('cert.pem') +KEY = jwk.JWKRSA.load(test_util.load_vector('rsa512_key.pem')) class MediaTypeTest(unittest.TestCase): @@ -112,7 +104,7 @@ class JWSTest(unittest.TestCase): """Tests for acme.jose.jws.JWS.""" def setUp(self): - self.privkey = jwk.JWKRSA(key=RSA512_KEY) + self.privkey = KEY self.pubkey = self.privkey.public_key() from acme.jose.jws import JWS @@ -209,8 +201,7 @@ class JWSTest(unittest.TestCase): class CLITest(unittest.TestCase): def setUp(self): - self.key_path = pkg_resources.resource_filename( - 'acme', os.path.join('testdata', 'rsa512_key.pem')) + self.key_path = test_util.vector_path('rsa512_key.pem') def test_unverified(self): from acme.jose.jws import CLI diff --git a/acme/jose/util_test.py b/acme/jose/util_test.py index 8d36de09b..1bde9ebd9 100644 --- a/acme/jose/util_test.py +++ b/acme/jose/util_test.py @@ -1,31 +1,22 @@ """Tests for acme.jose.util.""" import functools -import os -import pkg_resources import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization -import OpenSSL +from acme import test_util class ComparableX509Test(unittest.TestCase): """Tests for acme.jose.util.ComparableX509.""" def setUp(self): - from acme.jose.util import ComparableX509 - def _load(method, filename): # pylint: disable=missing-docstring - return ComparableX509(method( - OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'acme', os.path.join('testdata', filename)))) + # test_util.load_{csr,cert} return ComparableX509 + self.req1 = test_util.load_csr('csr.pem') + self.req2 = test_util.load_csr('csr.pem') + self.req_other = test_util.load_csr('csr-san.pem') - self.req1 = _load(OpenSSL.crypto.load_certificate_request, 'csr.pem') - self.req2 = _load(OpenSSL.crypto.load_certificate_request, 'csr.pem') - self.req_other = _load(OpenSSL.crypto.load_certificate_request, 'csr-san.pem') - - self.cert1 = _load(OpenSSL.crypto.load_certificate, 'cert.pem') - self.cert2 = _load(OpenSSL.crypto.load_certificate, 'cert.pem') - self.cert_other = _load(OpenSSL.crypto.load_certificate, 'cert-san.pem') + self.cert1 = test_util.load_cert('cert.pem') + self.cert2 = test_util.load_cert('cert.pem') + self.cert_other = test_util.load_cert('cert-san.pem') def test_eq(self): self.assertEqual(self.req1, self.req2) @@ -56,19 +47,10 @@ class ComparableRSAKeyTest(unittest.TestCase): """Tests for acme.jose.util.ComparableRSAKey.""" def setUp(self): - from acme.jose.util import ComparableRSAKey - backend = default_backend() - def load_key(): # pylint: disable=missing-docstring - return ComparableRSAKey(serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa256_key.pem')), - password=None, backend=backend)) - self.key = load_key() - self.key_same = load_key() - self.key2 = ComparableRSAKey(serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa512_key.pem')), - password=None, backend=backend)) + # test_utl.load_rsa_private_key return ComparableRSAKey + self.key = test_util.load_rsa_private_key('rsa256_key.pem') + self.key_same = test_util.load_rsa_private_key('rsa256_key.pem') + self.key2 = test_util.load_rsa_private_key('rsa512_key.pem') def test_getattr_proxy(self): self.assertEqual(256, self.key.key_size) diff --git a/acme/jws_test.py b/acme/jws_test.py index 989a6697a..07361581c 100644 --- a/acme/jws_test.py +++ b/acme/jws_test.py @@ -1,19 +1,12 @@ """Tests for acme.jws.""" -import os -import pkg_resources import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization - from acme import errors from acme import jose +from acme import test_util -RSA512_KEY = serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa512_key.pem')), - password=None, backend=default_backend()) +KEY = jose.JWKRSA.load(test_util.load_vector('rsa512_key.pem')) class HeaderTest(unittest.TestCase): @@ -46,7 +39,7 @@ class JWSTest(unittest.TestCase): """Tests for acme.jws.JWS.""" def setUp(self): - self.privkey = jose.JWKRSA(key=RSA512_KEY) + self.privkey = KEY self.pubkey = self.privkey.public_key() self.nonce = jose.b64encode('Nonce') diff --git a/acme/messages_test.py b/acme/messages_test.py index 71bf25963..2ed0dd669 100644 --- a/acme/messages_test.py +++ b/acme/messages_test.py @@ -1,30 +1,16 @@ """Tests for acme.messages.""" -import os -import pkg_resources import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization import mock -import OpenSSL from acme import challenges from acme import jose +from acme import test_util -CERT = jose.ComparableX509(OpenSSL.crypto.load_certificate( - OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'cert.der')))) -CSR = jose.ComparableX509(OpenSSL.crypto.load_certificate_request( - OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'csr.der')))) -KEY = serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa512_key.pem')), - password=None, backend=default_backend()) -CERT = jose.ComparableX509(OpenSSL.crypto.load_certificate( - OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'cert.der')))) +CERT = test_util.load_cert('cert.der') +CSR = test_util.load_csr('csr.der') +KEY = test_util.load_rsa_private_key('rsa512_key.pem') class ErrorTest(unittest.TestCase): diff --git a/acme/other_test.py b/acme/other_test.py index 25b07bcde..428fca81f 100644 --- a/acme/other_test.py +++ b/acme/other_test.py @@ -1,18 +1,11 @@ """Tests for acme.sig.""" -import os -import pkg_resources import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization - from acme import jose +from acme import test_util -KEY = serialization.load_pem_private_key( - pkg_resources.resource_string( - 'acme', os.path.join('testdata', 'rsa512_key.pem')), - password=None, backend=default_backend()) +KEY = test_util.load_rsa_private_key('rsa512_key.pem') class SignatureTest(unittest.TestCase): diff --git a/acme/test_util.py b/acme/test_util.py new file mode 100644 index 000000000..cec732625 --- /dev/null +++ b/acme/test_util.py @@ -0,0 +1,55 @@ +"""Test utilities. + +.. warning:: This module is not part of the public API. + +""" +import os +import pkg_resources + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +import OpenSSL + +from acme import jose + + +def vector_path(*names): + """Path to a test vector.""" + return pkg_resources.resource_filename( + __name__, os.path.join('testdata', *names)) + +def load_vector(*names): + """Load contents of a test vector.""" + # luckily, resource_string opens file in binary mode + return pkg_resources.resource_string( + __name__, os.path.join('testdata', *names)) + +def _guess_loader(filename, loader_pem, loader_der): + _, ext = os.path.splitext(filename) + if ext.lower() == '.pem': + return loader_pem + elif ext.lower() == '.der': + return loader_der + else: # pragma: no cover + raise ValueError("Loader could not be recognized based on extension") + +def load_cert(*names): + """Load certificate.""" + loader = _guess_loader( + names[-1], OpenSSL.crypto.FILETYPE_PEM, OpenSSL.crypto.FILETYPE_ASN1) + return jose.ComparableX509(OpenSSL.crypto.load_certificate( + loader, load_vector(*names))) + +def load_csr(*names): + """Load certificate request.""" + loader = _guess_loader( + names[-1], OpenSSL.crypto.FILETYPE_PEM, OpenSSL.crypto.FILETYPE_ASN1) + return jose.ComparableX509(OpenSSL.crypto.load_certificate_request( + loader, load_vector(*names))) + +def load_rsa_private_key(*names): + """Load RSA private key.""" + loader = _guess_loader(names[-1], serialization.load_pem_private_key, + serialization.load_der_private_key) + return jose.ComparableRSAKey(loader( + load_vector(*names), password=None, backend=default_backend())) diff --git a/acme/testdata/README b/acme/testdata/README index be3d8b2f7..11bca55e5 100644 --- a/acme/testdata/README +++ b/acme/testdata/README @@ -1,3 +1,7 @@ +In order for acme.test_util._guess_loader to work properly, make sure +to use appropriate extension for vector filenames: .pem for PEM and +.der for DER. + The following command has been used to generate test keys: for x in 256 512 1024; do openssl genrsa -out rsa${k}_key.pem $k; done From b0c72410bacc6c443b34dadbef179bb94fe6946f Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 13:40:51 +0000 Subject: [PATCH 03/30] Unified vector loading in letsencrypt. --- acme/test_util.py | 2 + letsencrypt/tests/account_test.py | 8 +- letsencrypt/tests/achallenges_test.py | 13 +-- letsencrypt/tests/acme_util.py | 12 +-- letsencrypt/tests/client_test.py | 10 +-- letsencrypt/tests/crypto_util_test.py | 79 ++++++++----------- letsencrypt/tests/display/ops_test.py | 6 +- letsencrypt/tests/display/revocation_test.py | 18 ++--- letsencrypt/tests/proof_of_possession_test.py | 26 ++---- letsencrypt/tests/renewer_test.py | 17 ++-- letsencrypt/tests/revoker_test.py | 25 ++---- letsencrypt/tests/test_util.py | 1 + setup.py | 2 +- tox.ini | 8 +- 14 files changed, 88 insertions(+), 139 deletions(-) create mode 120000 letsencrypt/tests/test_util.py diff --git a/acme/test_util.py b/acme/test_util.py index cec732625..85289a978 100644 --- a/acme/test_util.py +++ b/acme/test_util.py @@ -1,3 +1,5 @@ +# Symlinked in letsencrypt/tests/test_util.py, casues duplicate-code +# warning that cannot be disabled locally. """Test utilities. .. warning:: This module is not part of the public API. diff --git a/letsencrypt/tests/account_test.py b/letsencrypt/tests/account_test.py index 9a129dbe6..e19940fe8 100644 --- a/letsencrypt/tests/account_test.py +++ b/letsencrypt/tests/account_test.py @@ -1,7 +1,6 @@ """Tests for letsencrypt.account.""" import datetime import os -import pkg_resources import shutil import stat import tempfile @@ -15,9 +14,10 @@ from acme import messages from letsencrypt import errors +from letsencrypt.tests import test_util -KEY = jose.JWKRSA.load(pkg_resources.resource_string( - "letsencrypt.tests", os.path.join("testdata", "rsa512_key_2.pem"))) + +KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key_2.pem")) class AccountTest(unittest.TestCase): @@ -61,7 +61,7 @@ class ReportNewAccountTest(unittest.TestCase): """Tests for letsencrypt.account.report_new_account.""" def setUp(self): - self.config = mock.MagicMock(config_dir='/etc/letsencrypt') + self.config = mock.MagicMock(config_dir="/etc/letsencrypt") reg = messages.Registration.from_data(email="rhino@jungle.io") reg = reg.update(recovery_token="ECCENTRIC INVISIBILITY RHINOCEROS") self.acc = mock.MagicMock(regr=messages.RegistrationResource( diff --git a/letsencrypt/tests/achallenges_test.py b/letsencrypt/tests/achallenges_test.py index 4faa34d12..253cc20d7 100644 --- a/letsencrypt/tests/achallenges_test.py +++ b/letsencrypt/tests/achallenges_test.py @@ -1,17 +1,15 @@ """Tests for letsencrypt.achallenges.""" -import os -import pkg_resources import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization import OpenSSL from acme import challenges from acme import jose from letsencrypt import crypto_util + from letsencrypt.tests import acme_util +from letsencrypt.tests import test_util class DVSNITest(unittest.TestCase): @@ -21,12 +19,7 @@ class DVSNITest(unittest.TestCase): self.chall = acme_util.chall_to_challb( challenges.DVSNI(r="r_value", nonce="12345ABCDE"), "pending") self.response = challenges.DVSNIResponse() - key = jose.JWKRSA(key=jose.ComparableRSAKey( - serialization.load_pem_private_key( - pkg_resources.resource_string( - "letsencrypt.tests", os.path.join( - "testdata", "rsa512_key.pem")), - password=None, backend=default_backend()))) + key = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem")) from letsencrypt.achallenges import DVSNI self.achall = DVSNI(challb=self.chall, domain="example.com", key=key) diff --git a/letsencrypt/tests/acme_util.py b/letsencrypt/tests/acme_util.py index 8e19a9ca8..0f504fde3 100644 --- a/letsencrypt/tests/acme_util.py +++ b/letsencrypt/tests/acme_util.py @@ -1,21 +1,15 @@ """ACME utilities for testing.""" import datetime import itertools -import os -import pkg_resources - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization from acme import challenges from acme import jose from acme import messages +from letsencrypt.tests import test_util -KEY = serialization.load_pem_private_key( - pkg_resources.resource_string( - __name__, os.path.join('testdata', 'rsa512_key.pem')), - password=None, backend=default_backend()) + +KEY = test_util.load_rsa_private_key('rsa512_key.pem') # Challenges SIMPLE_HTTP = challenges.SimpleHTTP( diff --git a/letsencrypt/tests/client_test.py b/letsencrypt/tests/client_test.py index 2d1f1d2fd..b992089cc 100644 --- a/letsencrypt/tests/client_test.py +++ b/letsencrypt/tests/client_test.py @@ -1,7 +1,5 @@ """Tests for letsencrypt.client.""" -import os import unittest -import pkg_resources import configobj import OpenSSL @@ -14,11 +12,11 @@ from letsencrypt import configuration from letsencrypt import errors from letsencrypt import le_util +from letsencrypt.tests import test_util -KEY = pkg_resources.resource_string( - __name__, os.path.join("testdata", "rsa512_key.pem")) -CSR_SAN = pkg_resources.resource_string( - __name__, os.path.join("testdata", "csr-san.der")) + +KEY = test_util.load_vector("rsa512_key.pem") +CSR_SAN = test_util.load_vector("csr-san.der") class RegisterTest(unittest.TestCase): diff --git a/letsencrypt/tests/crypto_util_test.py b/letsencrypt/tests/crypto_util_test.py index 2e1e62797..fd3b60c60 100644 --- a/letsencrypt/tests/crypto_util_test.py +++ b/letsencrypt/tests/crypto_util_test.py @@ -1,7 +1,5 @@ """Tests for letsencrypt.crypto_util.""" import logging -import os -import pkg_resources import shutil import tempfile import unittest @@ -9,15 +7,13 @@ import unittest import OpenSSL import mock +from letsencrypt.tests import test_util -RSA256_KEY = pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', 'rsa256_key.pem')) -RSA512_KEY = pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', 'rsa512_key.pem')) -CERT = pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', 'cert.pem')) -SAN_CERT = pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', 'cert-san.pem')) + +RSA256_KEY = test_util.load_vector('rsa256_key.pem') +RSA512_KEY = test_util.load_vector('rsa512_key.pem') +CERT = test_util.load_vector('cert.pem') +SAN_CERT = test_util.load_vector('cert-san.pem') class InitSaveKeyTest(unittest.TestCase): @@ -100,21 +96,17 @@ class ValidCSRTest(unittest.TestCase): from letsencrypt.crypto_util import valid_csr return valid_csr(csr) - def _call_testdata(self, name): - return self._call(pkg_resources.resource_string( - __name__, os.path.join('testdata', name))) - def test_valid_pem_true(self): - self.assertTrue(self._call_testdata('csr.pem')) + self.assertTrue(self._call(test_util.load_vector('csr.pem'))) def test_valid_pem_san_true(self): - self.assertTrue(self._call_testdata('csr-san.pem')) + self.assertTrue(self._call(test_util.load_vector('csr-san.pem'))) def test_valid_der_false(self): - self.assertFalse(self._call_testdata('csr.der')) + self.assertFalse(self._call(test_util.load_vector('csr.der'))) def test_valid_der_san_false(self): - self.assertFalse(self._call_testdata('csr-san.der')) + self.assertFalse(self._call(test_util.load_vector('csr-san.der'))) def test_empty_false(self): self.assertFalse(self._call('')) @@ -127,16 +119,17 @@ class CSRMatchesPubkeyTest(unittest.TestCase): """Tests for letsencrypt.crypto_util.csr_matches_pubkey.""" @classmethod - def _call_testdata(cls, name, privkey): + def _call(cls, *args, **kwargs): from letsencrypt.crypto_util import csr_matches_pubkey - return csr_matches_pubkey(pkg_resources.resource_string( - __name__, os.path.join('testdata', name)), privkey) + return csr_matches_pubkey(*args, **kwargs) def test_valid_true(self): - self.assertTrue(self._call_testdata('csr.pem', RSA512_KEY)) + self.assertTrue(self._call( + test_util.load_vector('csr.pem'), RSA512_KEY)) def test_invalid_false(self): - self.assertFalse(self._call_testdata('csr.pem', RSA256_KEY)) + self.assertFalse(self._call( + test_util.load_vector('csr.pem'), RSA256_KEY)) class MakeKeyTest(unittest.TestCase): # pylint: disable=too-few-public-methods @@ -185,50 +178,42 @@ class GetSANsFromCertTest(unittest.TestCase): return get_sans_from_cert(*args, **kwargs) def test_single(self): - self.assertEqual([], self._call(pkg_resources.resource_string( - __name__, os.path.join('testdata', 'cert.pem')))) + self.assertEqual([], self._call(test_util.load_vector('cert.pem'))) def test_san(self): self.assertEqual( ['example.com', 'www.example.com'], - self._call(pkg_resources.resource_string( - __name__, os.path.join('testdata', 'cert-san.pem')))) + self._call(test_util.load_vector('cert-san.pem'))) class GetSANsFromCSRTest(unittest.TestCase): """Tests for letsencrypt.crypto_util.get_sans_from_csr.""" - def test_extract_one_san(self): + + @classmethod + def _call(cls, *args, **kwargs): from letsencrypt.crypto_util import get_sans_from_csr - csr = pkg_resources.resource_string( - __name__, os.path.join('testdata', 'csr.pem')) - self.assertEqual(get_sans_from_csr(csr), ['example.com']) + return get_sans_from_csr(*args, **kwargs) + + def test_extract_one_san(self): + self.assertEqual(['example.com'], self._call( + test_util.load_vector('csr.pem'))) def test_extract_two_sans(self): - from letsencrypt.crypto_util import get_sans_from_csr - csr = pkg_resources.resource_string( - __name__, os.path.join('testdata', 'csr-san.pem')) - self.assertEqual(get_sans_from_csr(csr), ['example.com', - 'www.example.com']) + self.assertEqual(['example.com', 'www.example.com'], self._call( + test_util.load_vector('csr-san.pem'))) def test_extract_six_sans(self): - from letsencrypt.crypto_util import get_sans_from_csr - csr = pkg_resources.resource_string( - __name__, os.path.join('testdata', 'csr-6sans.pem')) - self.assertEqual(get_sans_from_csr(csr), + self.assertEqual(self._call(test_util.load_vector('csr-6sans.pem')), ["example.com", "example.org", "example.net", "example.info", "subdomain.example.com", "other.subdomain.example.com"]) def test_parse_non_csr(self): - from letsencrypt.crypto_util import get_sans_from_csr - self.assertRaises(OpenSSL.crypto.Error, get_sans_from_csr, - "hello there") + self.assertRaises(OpenSSL.crypto.Error, self._call, "hello there") def test_parse_no_sans(self): - from letsencrypt.crypto_util import get_sans_from_csr - csr = pkg_resources.resource_string( - __name__, os.path.join('testdata', 'csr-nosans.pem')) - self.assertEqual([], get_sans_from_csr(csr)) + self.assertEqual( + [], self._call(test_util.load_vector('csr-nosans.pem'))) if __name__ == '__main__': diff --git a/letsencrypt/tests/display/ops_test.py b/letsencrypt/tests/display/ops_test.py index 59b8d9b5c..3a0c627ce 100644 --- a/letsencrypt/tests/display/ops_test.py +++ b/letsencrypt/tests/display/ops_test.py @@ -1,6 +1,5 @@ """Test letsencrypt.display.ops.""" import os -import pkg_resources import sys import tempfile import unittest @@ -16,9 +15,10 @@ from letsencrypt import interfaces from letsencrypt.display import util as display_util +from letsencrypt.tests import test_util -KEY = jose.JWKRSA.load(pkg_resources.resource_string( - "letsencrypt.tests", os.path.join("testdata", "rsa512_key.pem"))) + +KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem")) class ChoosePluginTest(unittest.TestCase): diff --git a/letsencrypt/tests/display/revocation_test.py b/letsencrypt/tests/display/revocation_test.py index cb877499a..6e9763006 100644 --- a/letsencrypt/tests/display/revocation_test.py +++ b/letsencrypt/tests/display/revocation_test.py @@ -1,6 +1,4 @@ """Test :mod:`letsencrypt.display.revocation`.""" -import os -import pkg_resources import sys import unittest @@ -9,15 +7,14 @@ import zope.component from letsencrypt.display import util as display_util +from letsencrypt.tests import test_util + class DisplayCertsTest(unittest.TestCase): def setUp(self): from letsencrypt.revoker import Cert - base_package = "letsencrypt.tests" - self.cert0 = Cert(pkg_resources.resource_filename( - base_package, os.path.join("testdata", "cert.pem"))) - self.cert1 = Cert(pkg_resources.resource_filename( - base_package, os.path.join("testdata", "cert-san.pem"))) + self.cert0 = Cert(test_util.vector_path("cert.pem")) + self.cert1 = Cert(test_util.vector_path("cert-san.pem")) self.certs = [self.cert0, self.cert1] @@ -62,9 +59,7 @@ class MoreInfoCertTest(unittest.TestCase): class SuccessRevocationTest(unittest.TestCase): def setUp(self): from letsencrypt.revoker import Cert - base_package = "letsencrypt.tests" - self.cert = Cert(pkg_resources.resource_filename( - base_package, os.path.join("testdata", "cert.pem"))) + self.cert = Cert(test_util.vector_path("cert.pem")) @classmethod def _call(cls, cert): @@ -82,8 +77,7 @@ class SuccessRevocationTest(unittest.TestCase): class ConfirmRevocationTest(unittest.TestCase): def setUp(self): from letsencrypt.revoker import Cert - self.cert = Cert(pkg_resources.resource_filename( - "letsencrypt.tests", os.path.join("testdata", "cert.pem"))) + self.cert = Cert(test_util.vector_path("cert.pem")) @classmethod def _call(cls, cert): diff --git a/letsencrypt/tests/proof_of_possession_test.py b/letsencrypt/tests/proof_of_possession_test.py index ef0ffc21e..bfe3478d1 100644 --- a/letsencrypt/tests/proof_of_possession_test.py +++ b/letsencrypt/tests/proof_of_possession_test.py @@ -1,11 +1,8 @@ """Tests for letsencrypt.proof_of_possession.""" import os -import pkg_resources import tempfile import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization import mock from acme import challenges @@ -16,22 +13,15 @@ from letsencrypt import achallenges from letsencrypt import proof_of_possession from letsencrypt.display import util as display_util +from letsencrypt.tests import test_util -BASE_PACKAGE = "letsencrypt.tests" -CERT0_PATH = pkg_resources.resource_filename( - BASE_PACKAGE, os.path.join("testdata", "cert.der")) -CERT2_PATH = pkg_resources.resource_filename( - BASE_PACKAGE, os.path.join("testdata", "dsa_cert.pem")) -CERT2_KEY_PATH = pkg_resources.resource_filename( - BASE_PACKAGE, os.path.join("testdata", "dsa512_key.pem")) -CERT3_PATH = pkg_resources.resource_filename( - BASE_PACKAGE, os.path.join("testdata", "matching_cert.pem")) -CERT3_KEY_PATH = pkg_resources.resource_filename( - BASE_PACKAGE, os.path.join("testdata", "rsa512_key_2.pem")) -with open(CERT3_KEY_PATH) as cert3_file: - CERT3_KEY = serialization.load_pem_private_key( - cert3_file.read(), password=None, - backend=default_backend()).public_key() + +CERT0_PATH = test_util.vector_path("cert.der") +CERT2_PATH = test_util.vector_path("dsa_cert.pem") +CERT2_KEY_PATH = test_util.vector_path("dsa512_key.pem") +CERT3_PATH = test_util.vector_path("matching_cert.pem") +CERT3_KEY_PATH = test_util.vector_path("rsa512_key_2.pem") +CERT3_KEY = test_util.load_rsa_private_key("rsa512_key_2.pem").public_key() class ProofOfPossessionTest(unittest.TestCase): diff --git a/letsencrypt/tests/renewer_test.py b/letsencrypt/tests/renewer_test.py index 4ee7cc0e8..65bfce314 100644 --- a/letsencrypt/tests/renewer_test.py +++ b/letsencrypt/tests/renewer_test.py @@ -2,22 +2,20 @@ import datetime import os import tempfile -import pkg_resources import shutil import unittest import configobj import mock -import OpenSSL import pytz from letsencrypt import configuration from letsencrypt.storage import ALL_FOUR +from letsencrypt.tests import test_util -CERT = OpenSSL.crypto.load_certificate( - OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - 'letsencrypt.tests', os.path.join('testdata', 'cert.pem'))) + +CERT = test_util.load_cert('cert.pem') def unlink_all(rc_object): @@ -295,8 +293,7 @@ class RenewableCertTests(unittest.TestCase): self.assertFalse(self.test_rc.has_pending_deployment()) def _test_notafterbefore(self, function, timestamp): - test_cert = pkg_resources.resource_string( - "letsencrypt.tests", os.path.join("testdata", "cert.pem")) + test_cert = test_util.load_vector("cert.pem") os.symlink(os.path.join("..", "..", "archive", "example.org", "cert12.pem"), self.test_rc.cert) with open(self.test_rc.cert, "w") as f: @@ -319,8 +316,7 @@ class RenewableCertTests(unittest.TestCase): def test_time_interval_judgments(self, mock_datetime): """Test should_autodeploy() and should_autorenew() on the basis of expiry time windows.""" - test_cert = pkg_resources.resource_string( - "letsencrypt.tests", os.path.join("testdata", "cert.pem")) + test_cert = test_util.load_vector("cert.pem") for kind in ALL_FOUR: where = getattr(self.test_rc, kind) os.symlink(os.path.join("..", "..", "archive", "example.org", @@ -561,8 +557,7 @@ class RenewableCertTests(unittest.TestCase): def test_renew(self, mock_c, mock_acc_storage, mock_pd): from letsencrypt import renewer - test_cert = pkg_resources.resource_string( - "letsencrypt.tests", os.path.join("testdata", "cert-san.pem")) + test_cert = test_util.load_vector("cert-san.pem") for kind in ALL_FOUR: os.symlink(os.path.join("..", "..", "archive", "example.org", kind + "1.pem"), diff --git a/letsencrypt/tests/revoker_test.py b/letsencrypt/tests/revoker_test.py index 92eeaf92d..87dab4eb8 100644 --- a/letsencrypt/tests/revoker_test.py +++ b/letsencrypt/tests/revoker_test.py @@ -1,7 +1,6 @@ """Test letsencrypt.revoker.""" import csv import os -import pkg_resources import shutil import tempfile import unittest @@ -13,10 +12,11 @@ from letsencrypt import errors from letsencrypt import le_util from letsencrypt.display import util as display_util +from letsencrypt.tests import test_util + KEY = OpenSSL.crypto.load_privatekey( - OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string( - __name__, os.path.join("testdata", "rsa512_key.pem"))) + OpenSSL.crypto.FILETYPE_PEM, test_util.load_vector("rsa512_key.pem")) class RevokerBase(unittest.TestCase): # pylint: disable=too-few-public-methods @@ -98,8 +98,7 @@ class RevokerTest(RevokerBase): def test_revoke_by_wrong_key(self, mock_display, mock_acme): mock_display().confirm_revocation.return_value = True - key_path = pkg_resources.resource_filename( - "letsencrypt.tests", os.path.join("testdata", "rsa256_key.pem")) + key_path = test_util.vector_path("rsa256_key.pem") wrong_key = le_util.Key(key_path, open(key_path).read()) self.revoker.revoke_from_key(wrong_key) @@ -395,22 +394,14 @@ class CertTest(unittest.TestCase): def create_revoker_certs(): """Create a few revoker.Cert objects.""" + cert0_path = test_util.vector_path("cert.pem") + cert1_path = test_util.vector_path("cert-san.pem") + key_path = test_util.vector_path("rsa512_key.pem") + from letsencrypt.revoker import Cert - - base_package = "letsencrypt.tests" - - cert0_path = pkg_resources.resource_filename( - base_package, os.path.join("testdata", "cert.pem")) - - cert1_path = pkg_resources.resource_filename( - base_package, os.path.join("testdata", "cert-san.pem")) - cert0 = Cert(cert0_path) cert1 = Cert(cert1_path) - key_path = pkg_resources.resource_filename( - base_package, os.path.join("testdata", "rsa512_key.pem")) - return [cert0_path, cert1_path], [cert0, cert1], key_path diff --git a/letsencrypt/tests/test_util.py b/letsencrypt/tests/test_util.py new file mode 120000 index 000000000..d46ad3bd4 --- /dev/null +++ b/letsencrypt/tests/test_util.py @@ -0,0 +1 @@ +../../acme/test_util.py \ No newline at end of file diff --git a/setup.py b/setup.py index b2bd0e652..0c74b296c 100644 --- a/setup.py +++ b/setup.py @@ -187,6 +187,6 @@ setup( ], }, - zip_safe=False, + zip_safe=False, # letsencrypt/tests/test_util.py is a symlink! include_package_data=True, ) diff --git a/tox.ini b/tox.ini index aed60f454..2f20e5799 100644 --- a/tox.ini +++ b/tox.ini @@ -28,6 +28,12 @@ commands = [testenv:lint] # recent versions of pylint do not support Python 2.6 (#97, #187) basepython = python2.7 +# separating into multiple invocations disables cross package +# duplicate code checking; if one of the commands fails, others will +# continue, but tox return code will reflect previous error commands = pip install -r requirements.txt -e .[dev] - pylint --rcfile=.pylintrc letsencrypt acme letsencrypt_apache letsencrypt_nginx + pylint --rcfile=.pylintrc letsencrypt + pylint --rcfile=.pylintrc acme + pylint --rcfile=.pylintrc letsencrypt_apache + pylint --rcfile=.pylintrc letsencrypt_nginx From 2f9cd6880769d345c1c5afff800e6ea794e33e45 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 14:14:52 +0000 Subject: [PATCH 04/30] Move acme and plugins to respective subdirectories. for x in acme letsencrypt_nginx letsencrypt_apache; do git mv $x _$x; mkdir $x; git mv _$x $x/$x; done --- acme/{ => acme}/__init__.py | 0 acme/{ => acme}/challenges.py | 0 acme/{ => acme}/challenges_test.py | 0 acme/{ => acme}/client.py | 0 acme/{ => acme}/client_test.py | 0 acme/{ => acme}/errors.py | 0 acme/{ => acme}/errors_test.py | 0 acme/{ => acme}/fields.py | 0 acme/{ => acme}/fields_test.py | 0 acme/{ => acme}/interfaces.py | 0 acme/{ => acme}/jose/__init__.py | 0 acme/{ => acme}/jose/b64.py | 0 acme/{ => acme}/jose/b64_test.py | 0 acme/{ => acme}/jose/errors.py | 0 acme/{ => acme}/jose/errors_test.py | 0 acme/{ => acme}/jose/interfaces.py | 0 acme/{ => acme}/jose/interfaces_test.py | 0 acme/{ => acme}/jose/json_util.py | 0 acme/{ => acme}/jose/json_util_test.py | 0 acme/{ => acme}/jose/jwa.py | 0 acme/{ => acme}/jose/jwa_test.py | 0 acme/{ => acme}/jose/jwk.py | 0 acme/{ => acme}/jose/jwk_test.py | 0 acme/{ => acme}/jose/jws.py | 0 acme/{ => acme}/jose/jws_test.py | 0 acme/{ => acme}/jose/util.py | 0 acme/{ => acme}/jose/util_test.py | 0 acme/{ => acme}/jws.py | 0 acme/{ => acme}/jws_test.py | 0 acme/{ => acme}/messages.py | 0 acme/{ => acme}/messages_test.py | 0 acme/{ => acme}/other.py | 0 acme/{ => acme}/other_test.py | 0 acme/{ => acme}/test_util.py | 0 acme/{ => acme}/testdata/README | 0 acme/{ => acme}/testdata/cert-san.pem | 0 acme/{ => acme}/testdata/cert.der | Bin acme/{ => acme}/testdata/cert.pem | 0 acme/{ => acme}/testdata/csr-san.pem | 0 acme/{ => acme}/testdata/csr.der | Bin acme/{ => acme}/testdata/csr.pem | 0 acme/{ => acme}/testdata/dsa512_key.pem | 0 acme/{ => acme}/testdata/rsa1024_key.pem | 0 acme/{ => acme}/testdata/rsa256_key.pem | 0 acme/{ => acme}/testdata/rsa512_key.pem | 0 .../{ => letsencrypt_apache}/__init__.py | 0 .../{ => letsencrypt_apache}/augeas_configurator.py | 0 .../{ => letsencrypt_apache}/configurator.py | 0 .../{ => letsencrypt_apache}/constants.py | 0 .../{ => letsencrypt_apache}/display_ops.py | 0 .../{ => letsencrypt_apache}/dvsni.py | 0 letsencrypt_apache/{ => letsencrypt_apache}/obj.py | 0 .../options-ssl-apache.conf | 0 .../{ => letsencrypt_apache}/parser.py | 0 .../{ => letsencrypt_apache}/tests/__init__.py | 0 .../tests/configurator_test.py | 0 .../tests/display_ops_test.py | 0 .../{ => letsencrypt_apache}/tests/dvsni_test.py | 0 .../{ => letsencrypt_apache}/tests/obj_test.py | 0 .../{ => letsencrypt_apache}/tests/parser_test.py | 0 .../default_vhost/apache2/apache2.conf | 0 .../conf-available/other-vhosts-access-log.conf | 0 .../apache2/conf-available/security.conf | 0 .../apache2/conf-available/serve-cgi-bin.conf | 0 .../conf-enabled/other-vhosts-access-log.conf | 0 .../apache2/conf-enabled/security.conf | 0 .../apache2/conf-enabled/serve-cgi-bin.conf | 0 .../debian_apache_2_4/default_vhost/apache2/envvars | 0 .../default_vhost/apache2/mods-available/ssl.conf | 0 .../default_vhost/apache2/mods-available/ssl.load | 0 .../default_vhost/apache2/ports.conf | 0 .../apache2/sites-available/000-default.conf | 0 .../apache2/sites-available/default-ssl.conf | 0 .../apache2/sites-enabled/000-default.conf | 0 .../testdata/debian_apache_2_4/default_vhost/sites | 0 .../two_vhost_80/apache2/apache2.conf | 0 .../conf-available/other-vhosts-access-log.conf | 0 .../apache2/conf-available/security.conf | 0 .../apache2/conf-available/serve-cgi-bin.conf | 0 .../conf-enabled/other-vhosts-access-log.conf | 0 .../two_vhost_80/apache2/conf-enabled/security.conf | 0 .../apache2/conf-enabled/serve-cgi-bin.conf | 0 .../debian_apache_2_4/two_vhost_80/apache2/envvars | 0 .../two_vhost_80/apache2/mods-available/ssl.conf | 0 .../two_vhost_80/apache2/mods-available/ssl.load | 0 .../two_vhost_80/apache2/ports.conf | 0 .../apache2/sites-available/000-default.conf | 0 .../apache2/sites-available/default-ssl.conf | 0 .../apache2/sites-available/encryption-example.conf | 0 .../apache2/sites-available/letsencrypt.conf | 0 .../apache2/sites-enabled/000-default.conf | 0 .../apache2/sites-enabled/encryption-example.conf | 0 .../apache2/sites-enabled/letsencrypt.conf | 0 .../testdata/debian_apache_2_4/two_vhost_80/sites | 0 .../{ => letsencrypt_apache}/tests/util.py | 0 .../{ => letsencrypt_nginx}/__init__.py | 0 .../{ => letsencrypt_nginx}/configurator.py | 0 .../{ => letsencrypt_nginx}/constants.py | 0 letsencrypt_nginx/{ => letsencrypt_nginx}/dvsni.py | 0 .../{ => letsencrypt_nginx}/nginxparser.py | 0 letsencrypt_nginx/{ => letsencrypt_nginx}/obj.py | 0 .../{ => letsencrypt_nginx}/options-ssl-nginx.conf | 0 letsencrypt_nginx/{ => letsencrypt_nginx}/parser.py | 0 .../{ => letsencrypt_nginx}/tests/__init__.py | 0 .../tests/configurator_test.py | 0 .../{ => letsencrypt_nginx}/tests/dvsni_test.py | 0 .../tests/nginxparser_test.py | 0 .../{ => letsencrypt_nginx}/tests/obj_test.py | 0 .../{ => letsencrypt_nginx}/tests/parser_test.py | 0 .../tests/testdata/etc_nginx/edge_cases.conf | 0 .../tests/testdata/etc_nginx/foo.conf | 0 .../tests/testdata/etc_nginx/mime.types | 0 .../tests/testdata/etc_nginx/nginx.conf | 0 .../tests/testdata/etc_nginx/nginx.new.conf | 0 .../tests/testdata/etc_nginx/server.conf | 0 .../tests/testdata/etc_nginx/sites-enabled/default | 0 .../testdata/etc_nginx/sites-enabled/example.com | 0 .../default_vhost/nginx/fastcgi_params | 0 .../ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf | 0 .../ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win | 0 .../default_vhost/nginx/mime.types | 0 .../default_vhost/nginx/naxsi-ui.conf.1.4.1 | 0 .../default_vhost/nginx/naxsi.rules | 0 .../default_vhost/nginx/naxsi_core.rules | 0 .../default_vhost/nginx/nginx.conf | 0 .../default_vhost/nginx/proxy_params | 0 .../default_vhost/nginx/scgi_params | 0 .../default_vhost/nginx/sites-available/default | 0 .../default_vhost/nginx/sites-enabled/default | 0 .../default_vhost/nginx/uwsgi_params | 0 .../ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf | 0 .../{ => letsencrypt_nginx}/tests/util.py | 0 132 files changed, 0 insertions(+), 0 deletions(-) rename acme/{ => acme}/__init__.py (100%) rename acme/{ => acme}/challenges.py (100%) rename acme/{ => acme}/challenges_test.py (100%) rename acme/{ => acme}/client.py (100%) rename acme/{ => acme}/client_test.py (100%) rename acme/{ => acme}/errors.py (100%) rename acme/{ => acme}/errors_test.py (100%) rename acme/{ => acme}/fields.py (100%) rename acme/{ => acme}/fields_test.py (100%) rename acme/{ => acme}/interfaces.py (100%) rename acme/{ => acme}/jose/__init__.py (100%) rename acme/{ => acme}/jose/b64.py (100%) rename acme/{ => acme}/jose/b64_test.py (100%) rename acme/{ => acme}/jose/errors.py (100%) rename acme/{ => acme}/jose/errors_test.py (100%) rename acme/{ => acme}/jose/interfaces.py (100%) rename acme/{ => acme}/jose/interfaces_test.py (100%) rename acme/{ => acme}/jose/json_util.py (100%) rename acme/{ => acme}/jose/json_util_test.py (100%) rename acme/{ => acme}/jose/jwa.py (100%) rename acme/{ => acme}/jose/jwa_test.py (100%) rename acme/{ => acme}/jose/jwk.py (100%) rename acme/{ => acme}/jose/jwk_test.py (100%) rename acme/{ => acme}/jose/jws.py (100%) rename acme/{ => acme}/jose/jws_test.py (100%) rename acme/{ => acme}/jose/util.py (100%) rename acme/{ => acme}/jose/util_test.py (100%) rename acme/{ => acme}/jws.py (100%) rename acme/{ => acme}/jws_test.py (100%) rename acme/{ => acme}/messages.py (100%) rename acme/{ => acme}/messages_test.py (100%) rename acme/{ => acme}/other.py (100%) rename acme/{ => acme}/other_test.py (100%) rename acme/{ => acme}/test_util.py (100%) rename acme/{ => acme}/testdata/README (100%) rename acme/{ => acme}/testdata/cert-san.pem (100%) rename acme/{ => acme}/testdata/cert.der (100%) rename acme/{ => acme}/testdata/cert.pem (100%) rename acme/{ => acme}/testdata/csr-san.pem (100%) rename acme/{ => acme}/testdata/csr.der (100%) rename acme/{ => acme}/testdata/csr.pem (100%) rename acme/{ => acme}/testdata/dsa512_key.pem (100%) rename acme/{ => acme}/testdata/rsa1024_key.pem (100%) rename acme/{ => acme}/testdata/rsa256_key.pem (100%) rename acme/{ => acme}/testdata/rsa512_key.pem (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/__init__.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/augeas_configurator.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/configurator.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/constants.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/display_ops.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/dvsni.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/obj.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/options-ssl-apache.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/parser.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/__init__.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/configurator_test.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/display_ops_test.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/dvsni_test.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/obj_test.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/parser_test.py (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/default_vhost/sites (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/testdata/debian_apache_2_4/two_vhost_80/sites (100%) rename letsencrypt_apache/{ => letsencrypt_apache}/tests/util.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/__init__.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/configurator.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/constants.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/dvsni.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/nginxparser.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/obj.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/options-ssl-nginx.conf (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/parser.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/__init__.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/configurator_test.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/dvsni_test.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/nginxparser_test.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/obj_test.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/parser_test.py (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/edge_cases.conf (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/foo.conf (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/mime.types (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/nginx.conf (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/nginx.new.conf (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/server.conf (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/sites-enabled/default (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/sites-enabled/example.com (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf (100%) rename letsencrypt_nginx/{ => letsencrypt_nginx}/tests/util.py (100%) diff --git a/acme/__init__.py b/acme/acme/__init__.py similarity index 100% rename from acme/__init__.py rename to acme/acme/__init__.py diff --git a/acme/challenges.py b/acme/acme/challenges.py similarity index 100% rename from acme/challenges.py rename to acme/acme/challenges.py diff --git a/acme/challenges_test.py b/acme/acme/challenges_test.py similarity index 100% rename from acme/challenges_test.py rename to acme/acme/challenges_test.py diff --git a/acme/client.py b/acme/acme/client.py similarity index 100% rename from acme/client.py rename to acme/acme/client.py diff --git a/acme/client_test.py b/acme/acme/client_test.py similarity index 100% rename from acme/client_test.py rename to acme/acme/client_test.py diff --git a/acme/errors.py b/acme/acme/errors.py similarity index 100% rename from acme/errors.py rename to acme/acme/errors.py diff --git a/acme/errors_test.py b/acme/acme/errors_test.py similarity index 100% rename from acme/errors_test.py rename to acme/acme/errors_test.py diff --git a/acme/fields.py b/acme/acme/fields.py similarity index 100% rename from acme/fields.py rename to acme/acme/fields.py diff --git a/acme/fields_test.py b/acme/acme/fields_test.py similarity index 100% rename from acme/fields_test.py rename to acme/acme/fields_test.py diff --git a/acme/interfaces.py b/acme/acme/interfaces.py similarity index 100% rename from acme/interfaces.py rename to acme/acme/interfaces.py diff --git a/acme/jose/__init__.py b/acme/acme/jose/__init__.py similarity index 100% rename from acme/jose/__init__.py rename to acme/acme/jose/__init__.py diff --git a/acme/jose/b64.py b/acme/acme/jose/b64.py similarity index 100% rename from acme/jose/b64.py rename to acme/acme/jose/b64.py diff --git a/acme/jose/b64_test.py b/acme/acme/jose/b64_test.py similarity index 100% rename from acme/jose/b64_test.py rename to acme/acme/jose/b64_test.py diff --git a/acme/jose/errors.py b/acme/acme/jose/errors.py similarity index 100% rename from acme/jose/errors.py rename to acme/acme/jose/errors.py diff --git a/acme/jose/errors_test.py b/acme/acme/jose/errors_test.py similarity index 100% rename from acme/jose/errors_test.py rename to acme/acme/jose/errors_test.py diff --git a/acme/jose/interfaces.py b/acme/acme/jose/interfaces.py similarity index 100% rename from acme/jose/interfaces.py rename to acme/acme/jose/interfaces.py diff --git a/acme/jose/interfaces_test.py b/acme/acme/jose/interfaces_test.py similarity index 100% rename from acme/jose/interfaces_test.py rename to acme/acme/jose/interfaces_test.py diff --git a/acme/jose/json_util.py b/acme/acme/jose/json_util.py similarity index 100% rename from acme/jose/json_util.py rename to acme/acme/jose/json_util.py diff --git a/acme/jose/json_util_test.py b/acme/acme/jose/json_util_test.py similarity index 100% rename from acme/jose/json_util_test.py rename to acme/acme/jose/json_util_test.py diff --git a/acme/jose/jwa.py b/acme/acme/jose/jwa.py similarity index 100% rename from acme/jose/jwa.py rename to acme/acme/jose/jwa.py diff --git a/acme/jose/jwa_test.py b/acme/acme/jose/jwa_test.py similarity index 100% rename from acme/jose/jwa_test.py rename to acme/acme/jose/jwa_test.py diff --git a/acme/jose/jwk.py b/acme/acme/jose/jwk.py similarity index 100% rename from acme/jose/jwk.py rename to acme/acme/jose/jwk.py diff --git a/acme/jose/jwk_test.py b/acme/acme/jose/jwk_test.py similarity index 100% rename from acme/jose/jwk_test.py rename to acme/acme/jose/jwk_test.py diff --git a/acme/jose/jws.py b/acme/acme/jose/jws.py similarity index 100% rename from acme/jose/jws.py rename to acme/acme/jose/jws.py diff --git a/acme/jose/jws_test.py b/acme/acme/jose/jws_test.py similarity index 100% rename from acme/jose/jws_test.py rename to acme/acme/jose/jws_test.py diff --git a/acme/jose/util.py b/acme/acme/jose/util.py similarity index 100% rename from acme/jose/util.py rename to acme/acme/jose/util.py diff --git a/acme/jose/util_test.py b/acme/acme/jose/util_test.py similarity index 100% rename from acme/jose/util_test.py rename to acme/acme/jose/util_test.py diff --git a/acme/jws.py b/acme/acme/jws.py similarity index 100% rename from acme/jws.py rename to acme/acme/jws.py diff --git a/acme/jws_test.py b/acme/acme/jws_test.py similarity index 100% rename from acme/jws_test.py rename to acme/acme/jws_test.py diff --git a/acme/messages.py b/acme/acme/messages.py similarity index 100% rename from acme/messages.py rename to acme/acme/messages.py diff --git a/acme/messages_test.py b/acme/acme/messages_test.py similarity index 100% rename from acme/messages_test.py rename to acme/acme/messages_test.py diff --git a/acme/other.py b/acme/acme/other.py similarity index 100% rename from acme/other.py rename to acme/acme/other.py diff --git a/acme/other_test.py b/acme/acme/other_test.py similarity index 100% rename from acme/other_test.py rename to acme/acme/other_test.py diff --git a/acme/test_util.py b/acme/acme/test_util.py similarity index 100% rename from acme/test_util.py rename to acme/acme/test_util.py diff --git a/acme/testdata/README b/acme/acme/testdata/README similarity index 100% rename from acme/testdata/README rename to acme/acme/testdata/README diff --git a/acme/testdata/cert-san.pem b/acme/acme/testdata/cert-san.pem similarity index 100% rename from acme/testdata/cert-san.pem rename to acme/acme/testdata/cert-san.pem diff --git a/acme/testdata/cert.der b/acme/acme/testdata/cert.der similarity index 100% rename from acme/testdata/cert.der rename to acme/acme/testdata/cert.der diff --git a/acme/testdata/cert.pem b/acme/acme/testdata/cert.pem similarity index 100% rename from acme/testdata/cert.pem rename to acme/acme/testdata/cert.pem diff --git a/acme/testdata/csr-san.pem b/acme/acme/testdata/csr-san.pem similarity index 100% rename from acme/testdata/csr-san.pem rename to acme/acme/testdata/csr-san.pem diff --git a/acme/testdata/csr.der b/acme/acme/testdata/csr.der similarity index 100% rename from acme/testdata/csr.der rename to acme/acme/testdata/csr.der diff --git a/acme/testdata/csr.pem b/acme/acme/testdata/csr.pem similarity index 100% rename from acme/testdata/csr.pem rename to acme/acme/testdata/csr.pem diff --git a/acme/testdata/dsa512_key.pem b/acme/acme/testdata/dsa512_key.pem similarity index 100% rename from acme/testdata/dsa512_key.pem rename to acme/acme/testdata/dsa512_key.pem diff --git a/acme/testdata/rsa1024_key.pem b/acme/acme/testdata/rsa1024_key.pem similarity index 100% rename from acme/testdata/rsa1024_key.pem rename to acme/acme/testdata/rsa1024_key.pem diff --git a/acme/testdata/rsa256_key.pem b/acme/acme/testdata/rsa256_key.pem similarity index 100% rename from acme/testdata/rsa256_key.pem rename to acme/acme/testdata/rsa256_key.pem diff --git a/acme/testdata/rsa512_key.pem b/acme/acme/testdata/rsa512_key.pem similarity index 100% rename from acme/testdata/rsa512_key.pem rename to acme/acme/testdata/rsa512_key.pem diff --git a/letsencrypt_apache/__init__.py b/letsencrypt_apache/letsencrypt_apache/__init__.py similarity index 100% rename from letsencrypt_apache/__init__.py rename to letsencrypt_apache/letsencrypt_apache/__init__.py diff --git a/letsencrypt_apache/augeas_configurator.py b/letsencrypt_apache/letsencrypt_apache/augeas_configurator.py similarity index 100% rename from letsencrypt_apache/augeas_configurator.py rename to letsencrypt_apache/letsencrypt_apache/augeas_configurator.py diff --git a/letsencrypt_apache/configurator.py b/letsencrypt_apache/letsencrypt_apache/configurator.py similarity index 100% rename from letsencrypt_apache/configurator.py rename to letsencrypt_apache/letsencrypt_apache/configurator.py diff --git a/letsencrypt_apache/constants.py b/letsencrypt_apache/letsencrypt_apache/constants.py similarity index 100% rename from letsencrypt_apache/constants.py rename to letsencrypt_apache/letsencrypt_apache/constants.py diff --git a/letsencrypt_apache/display_ops.py b/letsencrypt_apache/letsencrypt_apache/display_ops.py similarity index 100% rename from letsencrypt_apache/display_ops.py rename to letsencrypt_apache/letsencrypt_apache/display_ops.py diff --git a/letsencrypt_apache/dvsni.py b/letsencrypt_apache/letsencrypt_apache/dvsni.py similarity index 100% rename from letsencrypt_apache/dvsni.py rename to letsencrypt_apache/letsencrypt_apache/dvsni.py diff --git a/letsencrypt_apache/obj.py b/letsencrypt_apache/letsencrypt_apache/obj.py similarity index 100% rename from letsencrypt_apache/obj.py rename to letsencrypt_apache/letsencrypt_apache/obj.py diff --git a/letsencrypt_apache/options-ssl-apache.conf b/letsencrypt_apache/letsencrypt_apache/options-ssl-apache.conf similarity index 100% rename from letsencrypt_apache/options-ssl-apache.conf rename to letsencrypt_apache/letsencrypt_apache/options-ssl-apache.conf diff --git a/letsencrypt_apache/parser.py b/letsencrypt_apache/letsencrypt_apache/parser.py similarity index 100% rename from letsencrypt_apache/parser.py rename to letsencrypt_apache/letsencrypt_apache/parser.py diff --git a/letsencrypt_apache/tests/__init__.py b/letsencrypt_apache/letsencrypt_apache/tests/__init__.py similarity index 100% rename from letsencrypt_apache/tests/__init__.py rename to letsencrypt_apache/letsencrypt_apache/tests/__init__.py diff --git a/letsencrypt_apache/tests/configurator_test.py b/letsencrypt_apache/letsencrypt_apache/tests/configurator_test.py similarity index 100% rename from letsencrypt_apache/tests/configurator_test.py rename to letsencrypt_apache/letsencrypt_apache/tests/configurator_test.py diff --git a/letsencrypt_apache/tests/display_ops_test.py b/letsencrypt_apache/letsencrypt_apache/tests/display_ops_test.py similarity index 100% rename from letsencrypt_apache/tests/display_ops_test.py rename to letsencrypt_apache/letsencrypt_apache/tests/display_ops_test.py diff --git a/letsencrypt_apache/tests/dvsni_test.py b/letsencrypt_apache/letsencrypt_apache/tests/dvsni_test.py similarity index 100% rename from letsencrypt_apache/tests/dvsni_test.py rename to letsencrypt_apache/letsencrypt_apache/tests/dvsni_test.py diff --git a/letsencrypt_apache/tests/obj_test.py b/letsencrypt_apache/letsencrypt_apache/tests/obj_test.py similarity index 100% rename from letsencrypt_apache/tests/obj_test.py rename to letsencrypt_apache/letsencrypt_apache/tests/obj_test.py diff --git a/letsencrypt_apache/tests/parser_test.py b/letsencrypt_apache/letsencrypt_apache/tests/parser_test.py similarity index 100% rename from letsencrypt_apache/tests/parser_test.py rename to letsencrypt_apache/letsencrypt_apache/tests/parser_test.py diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/sites b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/sites similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/sites rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/sites diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf diff --git a/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/sites b/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/sites similarity index 100% rename from letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/sites rename to letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/sites diff --git a/letsencrypt_apache/tests/util.py b/letsencrypt_apache/letsencrypt_apache/tests/util.py similarity index 100% rename from letsencrypt_apache/tests/util.py rename to letsencrypt_apache/letsencrypt_apache/tests/util.py diff --git a/letsencrypt_nginx/__init__.py b/letsencrypt_nginx/letsencrypt_nginx/__init__.py similarity index 100% rename from letsencrypt_nginx/__init__.py rename to letsencrypt_nginx/letsencrypt_nginx/__init__.py diff --git a/letsencrypt_nginx/configurator.py b/letsencrypt_nginx/letsencrypt_nginx/configurator.py similarity index 100% rename from letsencrypt_nginx/configurator.py rename to letsencrypt_nginx/letsencrypt_nginx/configurator.py diff --git a/letsencrypt_nginx/constants.py b/letsencrypt_nginx/letsencrypt_nginx/constants.py similarity index 100% rename from letsencrypt_nginx/constants.py rename to letsencrypt_nginx/letsencrypt_nginx/constants.py diff --git a/letsencrypt_nginx/dvsni.py b/letsencrypt_nginx/letsencrypt_nginx/dvsni.py similarity index 100% rename from letsencrypt_nginx/dvsni.py rename to letsencrypt_nginx/letsencrypt_nginx/dvsni.py diff --git a/letsencrypt_nginx/nginxparser.py b/letsencrypt_nginx/letsencrypt_nginx/nginxparser.py similarity index 100% rename from letsencrypt_nginx/nginxparser.py rename to letsencrypt_nginx/letsencrypt_nginx/nginxparser.py diff --git a/letsencrypt_nginx/obj.py b/letsencrypt_nginx/letsencrypt_nginx/obj.py similarity index 100% rename from letsencrypt_nginx/obj.py rename to letsencrypt_nginx/letsencrypt_nginx/obj.py diff --git a/letsencrypt_nginx/options-ssl-nginx.conf b/letsencrypt_nginx/letsencrypt_nginx/options-ssl-nginx.conf similarity index 100% rename from letsencrypt_nginx/options-ssl-nginx.conf rename to letsencrypt_nginx/letsencrypt_nginx/options-ssl-nginx.conf diff --git a/letsencrypt_nginx/parser.py b/letsencrypt_nginx/letsencrypt_nginx/parser.py similarity index 100% rename from letsencrypt_nginx/parser.py rename to letsencrypt_nginx/letsencrypt_nginx/parser.py diff --git a/letsencrypt_nginx/tests/__init__.py b/letsencrypt_nginx/letsencrypt_nginx/tests/__init__.py similarity index 100% rename from letsencrypt_nginx/tests/__init__.py rename to letsencrypt_nginx/letsencrypt_nginx/tests/__init__.py diff --git a/letsencrypt_nginx/tests/configurator_test.py b/letsencrypt_nginx/letsencrypt_nginx/tests/configurator_test.py similarity index 100% rename from letsencrypt_nginx/tests/configurator_test.py rename to letsencrypt_nginx/letsencrypt_nginx/tests/configurator_test.py diff --git a/letsencrypt_nginx/tests/dvsni_test.py b/letsencrypt_nginx/letsencrypt_nginx/tests/dvsni_test.py similarity index 100% rename from letsencrypt_nginx/tests/dvsni_test.py rename to letsencrypt_nginx/letsencrypt_nginx/tests/dvsni_test.py diff --git a/letsencrypt_nginx/tests/nginxparser_test.py b/letsencrypt_nginx/letsencrypt_nginx/tests/nginxparser_test.py similarity index 100% rename from letsencrypt_nginx/tests/nginxparser_test.py rename to letsencrypt_nginx/letsencrypt_nginx/tests/nginxparser_test.py diff --git a/letsencrypt_nginx/tests/obj_test.py b/letsencrypt_nginx/letsencrypt_nginx/tests/obj_test.py similarity index 100% rename from letsencrypt_nginx/tests/obj_test.py rename to letsencrypt_nginx/letsencrypt_nginx/tests/obj_test.py diff --git a/letsencrypt_nginx/tests/parser_test.py b/letsencrypt_nginx/letsencrypt_nginx/tests/parser_test.py similarity index 100% rename from letsencrypt_nginx/tests/parser_test.py rename to letsencrypt_nginx/letsencrypt_nginx/tests/parser_test.py diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/mime.types b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/mime.types similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/mime.types rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/mime.types diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/server.conf b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/server.conf similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/server.conf rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/server.conf diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/default b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/default similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/default rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/default diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/example.com b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/example.com similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/example.com rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/example.com diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params diff --git a/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf b/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf similarity index 100% rename from letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf rename to letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf diff --git a/letsencrypt_nginx/tests/util.py b/letsencrypt_nginx/letsencrypt_nginx/tests/util.py similarity index 100% rename from letsencrypt_nginx/tests/util.py rename to letsencrypt_nginx/letsencrypt_nginx/tests/util.py From b9df69af9f1f883daa03bc715200f6e866fd7cd5 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 16:34:08 +0000 Subject: [PATCH 05/30] Basic dev/test setup for separate package subdirectories. --- Dockerfile | 6 ++- MANIFEST.in | 9 ----- Vagrantfile | 2 +- acme/MANIFEST.in | 1 + acme/setup.py | 29 ++++++++++++++ docs/contributing.rst | 2 +- docs/using.rst | 2 +- letsencrypt/plugins/disco.py | 6 ++- letsencrypt/tests/test_util.py | 2 +- letsencrypt_apache/MANIFEST.in | 2 + letsencrypt_apache/setup.py | 23 +++++++++++ letsencrypt_nginx/MANIFEST.in | 2 + letsencrypt_nginx/setup.py | 22 ++++++++++ setup.py | 73 +--------------------------------- tox.ini | 15 ++++--- 15 files changed, 104 insertions(+), 92 deletions(-) create mode 100644 acme/MANIFEST.in create mode 100644 acme/setup.py create mode 100644 letsencrypt_apache/MANIFEST.in create mode 100644 letsencrypt_apache/setup.py create mode 100644 letsencrypt_nginx/MANIFEST.in create mode 100644 letsencrypt_nginx/setup.py diff --git a/Dockerfile b/Dockerfile index 479aa4e85..a045cf2ce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,11 @@ COPY letsencrypt_nginx /opt/letsencrypt/src/letsencrypt_nginx/ # requirements.txt not installed! RUN virtualenv --no-site-packages -p python2 /opt/letsencrypt/venv && \ - /opt/letsencrypt/venv/bin/pip install -e /opt/letsencrypt/src + /opt/letsencrypt/venv/bin/pip install \ + -e /opt/letsencrypt/src/acme \ + -e /opt/letsencrypt/src \ + -e /opt/letsencrypt/src/letsencrypt_apache \ + -e /opt/letsencrypt/src/letsencrypt_nginx # install in editable mode (-e) to save space: it's not possible to # "rm -rf /opt/letsencrypt/src" (it's stays in the underlaying image); diff --git a/MANIFEST.in b/MANIFEST.in index 900a7ab80..08b67ef7a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,12 +4,3 @@ include CONTRIBUTING.md include linter_plugin.py include letsencrypt/EULA recursive-include letsencrypt/tests/testdata * - -recursive-include acme/schemata *.json -recursive-include acme/testdata * - -recursive-include letsencrypt_apache/tests/testdata * -include letsencrypt_apache/options-ssl-apache.conf - -recursive-include letsencrypt_nginx/tests/testdata * -include letsencrypt_nginx/options-ssl-nginx.conf diff --git a/Vagrantfile b/Vagrantfile index 1d3b48f06..0659e1ee2 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -10,7 +10,7 @@ cd /vagrant sudo ./bootstrap/ubuntu.sh if [ ! -d "venv" ]; then virtualenv --no-site-packages -p python2 venv - ./venv/bin/pip install -r requirements.txt -e .[dev,docs,testing] + ./venv/bin/pip install -r requirements.txt -e acme -e .[dev,docs,testing] -e letsencrypt_apache -e letsencrypt_nginx fi SETUP_SCRIPT diff --git a/acme/MANIFEST.in b/acme/MANIFEST.in new file mode 100644 index 000000000..f3444f746 --- /dev/null +++ b/acme/MANIFEST.in @@ -0,0 +1 @@ +recursive-include acme/testdata * diff --git a/acme/setup.py b/acme/setup.py new file mode 100644 index 000000000..d83131d2a --- /dev/null +++ b/acme/setup.py @@ -0,0 +1,29 @@ +from setuptools import setup +from setuptools import find_packages + + +install_requires = [ + 'argparse', + # load_pem_private/public_key (>=0.6) + # rsa_recover_prime_factors (>=0.8) + 'cryptography>=0.8', + 'mock<1.1.0', # py26 + 'pyrfc3339', + 'ndg-httpsclient', # urllib3 InsecurePlatformWarning (#304) + 'pyasn1', # urllib3 InsecurePlatformWarning (#304) + 'PyOpenSSL', + 'pytz', + 'requests', + 'werkzeug', +] + +setup( + name='acme', + packages=find_packages(), + install_requires=install_requires, + entry_points={ + 'console_scripts': [ + 'jws = acme.jose.jws:CLI.run', + ], + }, +) diff --git a/docs/contributing.rst b/docs/contributing.rst index b415390cf..c2120f1e1 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -26,7 +26,7 @@ Install the development packages: .. code-block:: shell - pip install -r requirements.txt -e .[dev,docs,testing] + pip install -r requirements.txt -e acme -e .[dev,docs,testing] -e letsencrypt_apache -e letsencrypt_nginx .. note:: `-e` (short for `--editable`) turns on *editable mode* in which any source code changes in the current working diff --git a/docs/using.rst b/docs/using.rst index 026c34aa2..0d9ffcc73 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -108,7 +108,7 @@ Installation .. code-block:: shell virtualenv --no-site-packages -p python2 venv - ./venv/bin/pip install -r requirements.txt . + ./venv/bin/pip install -r requirements.txt acme . letsencrypt_apache letsencrypt_nginx .. warning:: Please do **not** use ``python setup.py install``. Please do **not** attempt the installation commands as diff --git a/letsencrypt/plugins/disco.py b/letsencrypt/plugins/disco.py index e2e2d4c54..51d251126 100644 --- a/letsencrypt/plugins/disco.py +++ b/letsencrypt/plugins/disco.py @@ -16,7 +16,11 @@ logger = logging.getLogger(__name__) class PluginEntryPoint(object): """Plugin entry point.""" - PREFIX_FREE_DISTRIBUTIONS = ["letsencrypt"] + PREFIX_FREE_DISTRIBUTIONS = [ + "letsencrypt", + "letsencrypt-apache", + "letsencrypt-nginx", + ] """Distributions for which prefix will be omitted.""" # this object is mutable, don't allow it to be hashed! diff --git a/letsencrypt/tests/test_util.py b/letsencrypt/tests/test_util.py index d46ad3bd4..80d26cbe8 120000 --- a/letsencrypt/tests/test_util.py +++ b/letsencrypt/tests/test_util.py @@ -1 +1 @@ -../../acme/test_util.py \ No newline at end of file +../../acme/acme/test_util.py \ No newline at end of file diff --git a/letsencrypt_apache/MANIFEST.in b/letsencrypt_apache/MANIFEST.in new file mode 100644 index 000000000..aac2bfb36 --- /dev/null +++ b/letsencrypt_apache/MANIFEST.in @@ -0,0 +1,2 @@ +recursive-include letsencrypt_apache/tests/testdata * +include letsencrypt_apache/options-ssl-apache.conf diff --git a/letsencrypt_apache/setup.py b/letsencrypt_apache/setup.py new file mode 100644 index 000000000..fac5b6b88 --- /dev/null +++ b/letsencrypt_apache/setup.py @@ -0,0 +1,23 @@ +from setuptools import setup +from setuptools import find_packages + + +install_requires = [ + 'acme', + 'letsencrypt', + 'mock<1.1.0', # py26 + 'python-augeas', + 'zope.component', + 'zope.interface', +] + +setup( + name='letsencrypt-apache', + packages=find_packages(), + install_requires=install_requires, + entry_points={ + 'letsencrypt.plugins': [ + 'apache = letsencrypt_apache.configurator:ApacheConfigurator', + ], + }, +) diff --git a/letsencrypt_nginx/MANIFEST.in b/letsencrypt_nginx/MANIFEST.in new file mode 100644 index 000000000..94f85e40f --- /dev/null +++ b/letsencrypt_nginx/MANIFEST.in @@ -0,0 +1,2 @@ +recursive-include letsencrypt_nginx/tests/testdata * +include letsencrypt_nginx/options-ssl-nginx.conf diff --git a/letsencrypt_nginx/setup.py b/letsencrypt_nginx/setup.py new file mode 100644 index 000000000..bd8e8976d --- /dev/null +++ b/letsencrypt_nginx/setup.py @@ -0,0 +1,22 @@ +from setuptools import setup +from setuptools import find_packages + + +install_requires = [ + 'acme', + 'letsencrypt', + 'pyparsing>=1.5.5', # Python3 support; perhaps unnecessary? + 'mock<1.1.0', # py26 + 'zope.interface', +] + +setup( + name='letsencrypt-nginx', + packages=find_packages(), + install_requires=install_requires, + entry_points={ + 'letsencrypt.plugins': [ + 'nginx = letsencrypt_nginx.configurator:NginxConfigurator', + ], + }, +) diff --git a/setup.py b/setup.py index 0c74b296c..1e0d58a70 100644 --- a/setup.py +++ b/setup.py @@ -28,88 +28,24 @@ meta = dict(re.findall(r"""__([a-z]+)__ = "([^"]+)""", read_file(init_fn))) readme = read_file(os.path.join(here, 'README.rst')) changes = read_file(os.path.join(here, 'CHANGES.rst')) -# #358: acme, letsencrypt, letsencrypt_apache, letsencrypt_nginx, etc. -# shall be distributed separately. Please make sure to keep the -# dependecy lists up to date: this is being somewhat checked below -# using an assert statement! Separate lists are helpful for OS package -# maintainers. and will make the future migration a lot easier. -acme_install_requires = [ - 'argparse', - # load_pem_private/public_key (>=0.6) - # rsa_recover_prime_factors (>=0.8) - 'cryptography>=0.8', - 'mock<1.1.0', # py26 - 'pyrfc3339', - 'ndg-httpsclient', # urllib3 InsecurePlatformWarning (#304) - 'pyasn1', # urllib3 InsecurePlatformWarning (#304) - #'PyOpenSSL', # version pin would cause mismatch - 'pytz', - 'requests', - 'werkzeug', -] -letsencrypt_install_requires = [ - #'acme', - 'argparse', - 'ConfigArgParse', - 'configobj', - #'cryptography>=0.7', # load_pem_x509_certificate, version pin mismatch - 'mock<1.1.0', # py26 - 'parsedatetime', - 'psutil>=2.1.0', # net_connections introduced in 2.1.0 - # https://pyopenssl.readthedocs.org/en/latest/api/crypto.html#OpenSSL.crypto.X509Req.get_extensions - 'PyOpenSSL>=0.15', - 'pyrfc3339', - 'python2-pythondialog>=3.2.2rc1', # Debian squeeze support, cf. #280 - 'pytz', - 'zope.component', - 'zope.interface', -] -letsencrypt_apache_install_requires = [ - #'acme', - #'letsencrypt', - 'mock<1.1.0', # py26 - 'python-augeas', - 'zope.component', - 'zope.interface', -] -letsencrypt_nginx_install_requires = [ - #'acme', - #'letsencrypt', - 'pyparsing>=1.5.5', # Python3 support; perhaps unnecessary? - 'mock<1.1.0', # py26 - 'zope.interface', -] - install_requires = [ + 'acme', 'argparse', - 'cryptography>=0.8', 'ConfigArgParse', 'configobj', + 'cryptography>=0.7', # load_pem_x509_certificate 'mock<1.1.0', # py26 - 'ndg-httpsclient', # urllib3 InsecurePlatformWarning (#304) 'parsedatetime', 'psutil>=2.1.0', # net_connections introduced in 2.1.0 - 'pyasn1', # urllib3 InsecurePlatformWarning (#304) # https://pyopenssl.readthedocs.org/en/latest/api/crypto.html#OpenSSL.crypto.X509Req.get_extensions 'PyOpenSSL>=0.15', - 'pyparsing>=1.5.5', # Python3 support; perhaps unnecessary? 'pyrfc3339', - 'python-augeas', 'python2-pythondialog>=3.2.2rc1', # Debian squeeze support, cf. #280 'pytz', - 'requests', - 'werkzeug', 'zope.component', 'zope.interface', ] -assert set(install_requires) == set.union(*(set(ireq) for ireq in ( - acme_install_requires, - letsencrypt_install_requires, - letsencrypt_apache_install_requires, - letsencrypt_nginx_install_requires -))), "*install_requires don't match up!" - dev_extras = [ # Pin astroid==1.3.5, pylint==1.4.2 as a workaround for #289 'astroid==1.3.5', @@ -172,7 +108,6 @@ setup( 'console_scripts': [ 'letsencrypt = letsencrypt.cli:main', 'letsencrypt-renewer = letsencrypt.renewer:main', - 'jws = letsencrypt.acme.jose.jws:CLI.run', ], 'letsencrypt.plugins': [ 'manual = letsencrypt.plugins.manual:ManualAuthenticator', @@ -180,10 +115,6 @@ setup( 'null = letsencrypt.plugins.null:Installer', 'standalone = letsencrypt.plugins.standalone.authenticator' ':StandaloneAuthenticator', - - # to be moved to separate pypi packages - 'apache = letsencrypt_apache.configurator:ApacheConfigurator', - 'nginx = letsencrypt_nginx.configurator:NginxConfigurator', ], }, diff --git a/tox.ini b/tox.ini index 2f20e5799..71eb950d1 100644 --- a/tox.ini +++ b/tox.ini @@ -3,11 +3,14 @@ # "tox" from this directory. [tox] +# acme and letsencrypt are not yet on pypi, so when Tox invokes +# "install *.zip", it will not find deps +skipsdist = true envlist = py26,py27,cover,lint [testenv] commands = - pip install -r requirements.txt -e .[testing] + pip install -r requirements.txt -e acme -e .[testing] -e letsencrypt_apache -e letsencrypt_nginx # -q does not suppress errors python setup.py test -q python setup.py test -q -s acme @@ -22,7 +25,7 @@ setenv = [testenv:cover] basepython = python2.7 commands = - pip install -r requirements.txt -e .[testing] + pip install -r requirements.txt -e acme -e .[testing] -e letsencrypt_apache -e letsencrypt_nginx ./tox.cover.sh [testenv:lint] @@ -32,8 +35,8 @@ basepython = python2.7 # duplicate code checking; if one of the commands fails, others will # continue, but tox return code will reflect previous error commands = - pip install -r requirements.txt -e .[dev] + pip install -r requirements.txt -e acme -e .[dev] -e letsencrypt_apache -e letsencrypt_nginx pylint --rcfile=.pylintrc letsencrypt - pylint --rcfile=.pylintrc acme - pylint --rcfile=.pylintrc letsencrypt_apache - pylint --rcfile=.pylintrc letsencrypt_nginx + pylint --rcfile=.pylintrc acme/acme + pylint --rcfile=.pylintrc letsencrypt_apache/letsencrypt_apache + pylint --rcfile=.pylintrc letsencrypt_nginx/letsencrypt_nginx From 2e9cf9a5d5c567c07f0f0510474b513976d6e4ad Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 16:39:05 +0000 Subject: [PATCH 06/30] Include requirements.txt in sdist --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/MANIFEST.in b/MANIFEST.in index 08b67ef7a..530044212 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,4 @@ +include requirements.txt include README.rst include CHANGES.rst include CONTRIBUTING.md From db1e078c0602f0b691379d7c8bb31076e11b77b2 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 16:39:19 +0000 Subject: [PATCH 07/30] Shared tox envdir --- .dockerignore | 2 +- .gitignore | 2 +- tox.ini | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 2ce8a8209..203d8000f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,6 @@ # test docker on their git working directories. .git -.tox +tox.cover venv docs diff --git a/.gitignore b/.gitignore index 54670e6da..2441f1a74 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ build/ dist/ /venv/ -/.tox/ +/tox.venv/ letsencrypt.log # coverage diff --git a/tox.ini b/tox.ini index 71eb950d1..031f3af4f 100644 --- a/tox.ini +++ b/tox.ini @@ -9,6 +9,10 @@ skipsdist = true envlist = py26,py27,cover,lint [testenv] +# share one venv across testenvs, instead of multiple +# .tox/{py26,py27,cover,lint}; but do NOT set envdir to +# {toxinidir}/venv as it will destroy existing dev venv +envdir = {toxinidir}/tox.venv commands = pip install -r requirements.txt -e acme -e .[testing] -e letsencrypt_apache -e letsencrypt_nginx # -q does not suppress errors From 2ae6ac2bfdcf628efcbb9a6d14143c2d1b6b253e Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 17:13:25 +0000 Subject: [PATCH 08/30] Travis: tox-venv activation path adjustment --- .dockerignore | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 203d8000f..0bdb9e62d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,5 @@ # this file uses slightly different syntax than .gitignore, -# e.g. ".tox/" will not ignore .tox directory +# e.g. "tox.cover/" will not ignore tox.cover directory # well, official docker build should be done on clean git checkout # anyway, so .tox should be empty... But I'm sure people will try to diff --git a/.travis.yml b/.travis.yml index a7b03d20a..a9769ed78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ env: install: "travis_retry pip install tox coveralls" before_script: '[ "${TOXENV:0:2}" != "py" ] || ./tests/boulder-start.sh' # TODO: eliminate substring slice bashism -script: 'travis_retry tox && ([ "${TOXENV:0:2}" != "py" ] || (source .tox/$TOXENV/bin/activate && ./tests/boulder-integration.sh))' +script: 'travis_retry tox && ([ "${TOXENV:0:2}" != "py" ] || (source tox.venv/$TOXENV/bin/activate && ./tests/boulder-integration.sh))' after_success: '[ "$TOXENV" == "cover" ] && coveralls' From ff8925d92fc5a4146cd1704f9563653789df11c1 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 17:22:52 +0000 Subject: [PATCH 09/30] Update sys.path in docs/conf.py for Sphinx to find subdir packages. --- docs/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index c285c19e5..62e846a33 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -36,6 +36,8 @@ with codecs.open(init_fn, encoding='utf8') as fd: # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath(os.path.join(here, '..'))) +for pkg in 'acme', 'letsencrypt_apache', 'letsencrypt_nginx': + sys.path.insert(0, os.path.abspath(os.path.join(here, '..', pkg))) # -- General configuration ------------------------------------------------ From 0b4a85c145326037f2bd7da60b35eb5d97badd17 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 10 Jul 2015 17:29:28 +0000 Subject: [PATCH 10/30] Once again fix travis/tox venv path. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a9769ed78..31348f066 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ env: install: "travis_retry pip install tox coveralls" before_script: '[ "${TOXENV:0:2}" != "py" ] || ./tests/boulder-start.sh' # TODO: eliminate substring slice bashism -script: 'travis_retry tox && ([ "${TOXENV:0:2}" != "py" ] || (source tox.venv/$TOXENV/bin/activate && ./tests/boulder-integration.sh))' +script: 'travis_retry tox && ([ "${TOXENV:0:2}" != "py" ] || (source tox.venv/bin/activate && ./tests/boulder-integration.sh))' after_success: '[ "$TOXENV" == "cover" ] && coveralls' From 120a94f84f3b9e33f5095b20cfe8b7925815a969 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sat, 11 Jul 2015 04:31:18 +0000 Subject: [PATCH 11/30] mv letsencrypt_* letsencrypt-*. --- {letsencrypt_apache => letsencrypt-apache}/MANIFEST.in | 0 .../letsencrypt_apache/__init__.py | 0 .../letsencrypt_apache/augeas_configurator.py | 0 .../letsencrypt_apache/configurator.py | 0 .../letsencrypt_apache/constants.py | 0 .../letsencrypt_apache/display_ops.py | 0 .../letsencrypt_apache/dvsni.py | 0 .../letsencrypt_apache/obj.py | 0 .../letsencrypt_apache/options-ssl-apache.conf | 0 .../letsencrypt_apache/parser.py | 0 .../letsencrypt_apache/tests/__init__.py | 0 .../letsencrypt_apache/tests/configurator_test.py | 0 .../letsencrypt_apache/tests/display_ops_test.py | 0 .../letsencrypt_apache/tests/dvsni_test.py | 0 .../letsencrypt_apache/tests/obj_test.py | 0 .../letsencrypt_apache/tests/parser_test.py | 0 .../testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf | 0 .../apache2/conf-available/other-vhosts-access-log.conf | 0 .../default_vhost/apache2/conf-available/security.conf | 0 .../default_vhost/apache2/conf-available/serve-cgi-bin.conf | 0 .../apache2/conf-enabled/other-vhosts-access-log.conf | 0 .../default_vhost/apache2/conf-enabled/security.conf | 0 .../default_vhost/apache2/conf-enabled/serve-cgi-bin.conf | 0 .../testdata/debian_apache_2_4/default_vhost/apache2/envvars | 0 .../default_vhost/apache2/mods-available/ssl.conf | 0 .../default_vhost/apache2/mods-available/ssl.load | 0 .../testdata/debian_apache_2_4/default_vhost/apache2/ports.conf | 0 .../default_vhost/apache2/sites-available/000-default.conf | 0 .../default_vhost/apache2/sites-available/default-ssl.conf | 0 .../default_vhost/apache2/sites-enabled/000-default.conf | 0 .../tests/testdata/debian_apache_2_4/default_vhost/sites | 0 .../testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf | 0 .../apache2/conf-available/other-vhosts-access-log.conf | 0 .../two_vhost_80/apache2/conf-available/security.conf | 0 .../two_vhost_80/apache2/conf-available/serve-cgi-bin.conf | 0 .../apache2/conf-enabled/other-vhosts-access-log.conf | 0 .../two_vhost_80/apache2/conf-enabled/security.conf | 0 .../two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf | 0 .../tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars | 0 .../two_vhost_80/apache2/mods-available/ssl.conf | 0 .../two_vhost_80/apache2/mods-available/ssl.load | 0 .../testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf | 0 .../two_vhost_80/apache2/sites-available/000-default.conf | 0 .../two_vhost_80/apache2/sites-available/default-ssl.conf | 0 .../two_vhost_80/apache2/sites-available/encryption-example.conf | 0 .../two_vhost_80/apache2/sites-available/letsencrypt.conf | 0 .../two_vhost_80/apache2/sites-enabled/000-default.conf | 0 .../two_vhost_80/apache2/sites-enabled/encryption-example.conf | 0 .../two_vhost_80/apache2/sites-enabled/letsencrypt.conf | 0 .../tests/testdata/debian_apache_2_4/two_vhost_80/sites | 0 .../letsencrypt_apache/tests/util.py | 0 {letsencrypt_apache => letsencrypt-apache}/setup.py | 0 {letsencrypt_nginx => letsencrypt-nginx}/MANIFEST.in | 0 .../letsencrypt_nginx/__init__.py | 0 .../letsencrypt_nginx/configurator.py | 0 .../letsencrypt_nginx/constants.py | 0 .../letsencrypt_nginx/dvsni.py | 0 .../letsencrypt_nginx/nginxparser.py | 0 {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/obj.py | 0 .../letsencrypt_nginx/options-ssl-nginx.conf | 0 .../letsencrypt_nginx/parser.py | 0 .../letsencrypt_nginx/tests/__init__.py | 0 .../letsencrypt_nginx/tests/configurator_test.py | 0 .../letsencrypt_nginx/tests/dvsni_test.py | 0 .../letsencrypt_nginx/tests/nginxparser_test.py | 0 .../letsencrypt_nginx/tests/obj_test.py | 0 .../letsencrypt_nginx/tests/parser_test.py | 0 .../letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf | 0 .../letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf | 0 .../letsencrypt_nginx/tests/testdata/etc_nginx/mime.types | 0 .../letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf | 0 .../letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf | 0 .../letsencrypt_nginx/tests/testdata/etc_nginx/server.conf | 0 .../tests/testdata/etc_nginx/sites-enabled/default | 0 .../tests/testdata/etc_nginx/sites-enabled/example.com | 0 .../ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params | 0 .../etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf | 0 .../etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win | 0 .../etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types | 0 .../ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 | 0 .../etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules | 0 .../ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules | 0 .../etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf | 0 .../etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params | 0 .../etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params | 0 .../default_vhost/nginx/sites-available/default | 0 .../ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default | 0 .../etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params | 0 .../etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf | 0 .../letsencrypt_nginx/tests/util.py | 0 {letsencrypt_nginx => letsencrypt-nginx}/setup.py | 0 91 files changed, 0 insertions(+), 0 deletions(-) rename {letsencrypt_apache => letsencrypt-apache}/MANIFEST.in (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/__init__.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/augeas_configurator.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/configurator.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/constants.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/display_ops.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/dvsni.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/obj.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/options-ssl-apache.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/parser.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/__init__.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/configurator_test.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/display_ops_test.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/dvsni_test.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/obj_test.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/parser_test.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/sites (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/sites (100%) rename {letsencrypt_apache => letsencrypt-apache}/letsencrypt_apache/tests/util.py (100%) rename {letsencrypt_apache => letsencrypt-apache}/setup.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/MANIFEST.in (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/__init__.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/configurator.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/constants.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/dvsni.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/nginxparser.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/obj.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/options-ssl-nginx.conf (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/parser.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/__init__.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/configurator_test.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/dvsni_test.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/nginxparser_test.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/obj_test.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/parser_test.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/mime.types (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/server.conf (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/default (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/example.com (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/letsencrypt_nginx/tests/util.py (100%) rename {letsencrypt_nginx => letsencrypt-nginx}/setup.py (100%) diff --git a/letsencrypt_apache/MANIFEST.in b/letsencrypt-apache/MANIFEST.in similarity index 100% rename from letsencrypt_apache/MANIFEST.in rename to letsencrypt-apache/MANIFEST.in diff --git a/letsencrypt_apache/letsencrypt_apache/__init__.py b/letsencrypt-apache/letsencrypt_apache/__init__.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/__init__.py rename to letsencrypt-apache/letsencrypt_apache/__init__.py diff --git a/letsencrypt_apache/letsencrypt_apache/augeas_configurator.py b/letsencrypt-apache/letsencrypt_apache/augeas_configurator.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/augeas_configurator.py rename to letsencrypt-apache/letsencrypt_apache/augeas_configurator.py diff --git a/letsencrypt_apache/letsencrypt_apache/configurator.py b/letsencrypt-apache/letsencrypt_apache/configurator.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/configurator.py rename to letsencrypt-apache/letsencrypt_apache/configurator.py diff --git a/letsencrypt_apache/letsencrypt_apache/constants.py b/letsencrypt-apache/letsencrypt_apache/constants.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/constants.py rename to letsencrypt-apache/letsencrypt_apache/constants.py diff --git a/letsencrypt_apache/letsencrypt_apache/display_ops.py b/letsencrypt-apache/letsencrypt_apache/display_ops.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/display_ops.py rename to letsencrypt-apache/letsencrypt_apache/display_ops.py diff --git a/letsencrypt_apache/letsencrypt_apache/dvsni.py b/letsencrypt-apache/letsencrypt_apache/dvsni.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/dvsni.py rename to letsencrypt-apache/letsencrypt_apache/dvsni.py diff --git a/letsencrypt_apache/letsencrypt_apache/obj.py b/letsencrypt-apache/letsencrypt_apache/obj.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/obj.py rename to letsencrypt-apache/letsencrypt_apache/obj.py diff --git a/letsencrypt_apache/letsencrypt_apache/options-ssl-apache.conf b/letsencrypt-apache/letsencrypt_apache/options-ssl-apache.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/options-ssl-apache.conf rename to letsencrypt-apache/letsencrypt_apache/options-ssl-apache.conf diff --git a/letsencrypt_apache/letsencrypt_apache/parser.py b/letsencrypt-apache/letsencrypt_apache/parser.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/parser.py rename to letsencrypt-apache/letsencrypt_apache/parser.py diff --git a/letsencrypt_apache/letsencrypt_apache/tests/__init__.py b/letsencrypt-apache/letsencrypt_apache/tests/__init__.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/__init__.py rename to letsencrypt-apache/letsencrypt_apache/tests/__init__.py diff --git a/letsencrypt_apache/letsencrypt_apache/tests/configurator_test.py b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/configurator_test.py rename to letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py diff --git a/letsencrypt_apache/letsencrypt_apache/tests/display_ops_test.py b/letsencrypt-apache/letsencrypt_apache/tests/display_ops_test.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/display_ops_test.py rename to letsencrypt-apache/letsencrypt_apache/tests/display_ops_test.py diff --git a/letsencrypt_apache/letsencrypt_apache/tests/dvsni_test.py b/letsencrypt-apache/letsencrypt_apache/tests/dvsni_test.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/dvsni_test.py rename to letsencrypt-apache/letsencrypt_apache/tests/dvsni_test.py diff --git a/letsencrypt_apache/letsencrypt_apache/tests/obj_test.py b/letsencrypt-apache/letsencrypt_apache/tests/obj_test.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/obj_test.py rename to letsencrypt-apache/letsencrypt_apache/tests/obj_test.py diff --git a/letsencrypt_apache/letsencrypt_apache/tests/parser_test.py b/letsencrypt-apache/letsencrypt_apache/tests/parser_test.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/parser_test.py rename to letsencrypt-apache/letsencrypt_apache/tests/parser_test.py diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/other-vhosts-access-log.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/security.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-available/serve-cgi-bin.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/other-vhosts-access-log.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/serve-cgi-bin.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/mods-available/ssl.load diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/000-default.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-available/default-ssl.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/apache2/sites-enabled/000-default.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/sites b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/sites similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/sites rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/default_vhost/sites diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/other-vhosts-access-log.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/security.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-available/serve-cgi-bin.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/other-vhosts-access-log.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/serve-cgi-bin.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.load diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/000-default.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/default-ssl.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/encryption-example.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-available/letsencrypt.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/000-default.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/encryption-example.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/sites-enabled/letsencrypt.conf diff --git a/letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/sites b/letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/sites similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/sites rename to letsencrypt-apache/letsencrypt_apache/tests/testdata/debian_apache_2_4/two_vhost_80/sites diff --git a/letsencrypt_apache/letsencrypt_apache/tests/util.py b/letsencrypt-apache/letsencrypt_apache/tests/util.py similarity index 100% rename from letsencrypt_apache/letsencrypt_apache/tests/util.py rename to letsencrypt-apache/letsencrypt_apache/tests/util.py diff --git a/letsencrypt_apache/setup.py b/letsencrypt-apache/setup.py similarity index 100% rename from letsencrypt_apache/setup.py rename to letsencrypt-apache/setup.py diff --git a/letsencrypt_nginx/MANIFEST.in b/letsencrypt-nginx/MANIFEST.in similarity index 100% rename from letsencrypt_nginx/MANIFEST.in rename to letsencrypt-nginx/MANIFEST.in diff --git a/letsencrypt_nginx/letsencrypt_nginx/__init__.py b/letsencrypt-nginx/letsencrypt_nginx/__init__.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/__init__.py rename to letsencrypt-nginx/letsencrypt_nginx/__init__.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/configurator.py b/letsencrypt-nginx/letsencrypt_nginx/configurator.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/configurator.py rename to letsencrypt-nginx/letsencrypt_nginx/configurator.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/constants.py b/letsencrypt-nginx/letsencrypt_nginx/constants.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/constants.py rename to letsencrypt-nginx/letsencrypt_nginx/constants.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/dvsni.py b/letsencrypt-nginx/letsencrypt_nginx/dvsni.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/dvsni.py rename to letsencrypt-nginx/letsencrypt_nginx/dvsni.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/nginxparser.py b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/nginxparser.py rename to letsencrypt-nginx/letsencrypt_nginx/nginxparser.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/obj.py b/letsencrypt-nginx/letsencrypt_nginx/obj.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/obj.py rename to letsencrypt-nginx/letsencrypt_nginx/obj.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/options-ssl-nginx.conf b/letsencrypt-nginx/letsencrypt_nginx/options-ssl-nginx.conf similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/options-ssl-nginx.conf rename to letsencrypt-nginx/letsencrypt_nginx/options-ssl-nginx.conf diff --git a/letsencrypt_nginx/letsencrypt_nginx/parser.py b/letsencrypt-nginx/letsencrypt_nginx/parser.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/parser.py rename to letsencrypt-nginx/letsencrypt_nginx/parser.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/__init__.py b/letsencrypt-nginx/letsencrypt_nginx/tests/__init__.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/__init__.py rename to letsencrypt-nginx/letsencrypt_nginx/tests/__init__.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/configurator_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/configurator_test.py rename to letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/dvsni_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/dvsni_test.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/dvsni_test.py rename to letsencrypt-nginx/letsencrypt_nginx/tests/dvsni_test.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/nginxparser_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/nginxparser_test.py rename to letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/obj_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/obj_test.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/obj_test.py rename to letsencrypt-nginx/letsencrypt_nginx/tests/obj_test.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/parser_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/parser_test.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/parser_test.py rename to letsencrypt-nginx/letsencrypt_nginx/tests/parser_test.py diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/edge_cases.conf diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/foo.conf diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/mime.types b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/mime.types similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/mime.types rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/mime.types diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.conf diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/server.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/server.conf similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/server.conf rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/server.conf diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/default b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/default similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/default rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/default diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/example.com b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/example.com similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/example.com rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/sites-enabled/example.com diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/fastcgi_params diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-utf diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/koi-win diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/mime.types diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi-ui.conf.1.4.1 diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi.rules diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/naxsi_core.rules diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/nginx.conf diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/proxy_params diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/scgi_params diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-available/default diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/sites-enabled/default diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/uwsgi_params diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf rename to letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/ubuntu_nginx_1_4_6/default_vhost/nginx/win-utf diff --git a/letsencrypt_nginx/letsencrypt_nginx/tests/util.py b/letsencrypt-nginx/letsencrypt_nginx/tests/util.py similarity index 100% rename from letsencrypt_nginx/letsencrypt_nginx/tests/util.py rename to letsencrypt-nginx/letsencrypt_nginx/tests/util.py diff --git a/letsencrypt_nginx/setup.py b/letsencrypt-nginx/setup.py similarity index 100% rename from letsencrypt_nginx/setup.py rename to letsencrypt-nginx/setup.py From a462e38cab02f2c732b776017f1fe78c1997e3ab Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sat, 11 Jul 2015 04:33:07 +0000 Subject: [PATCH 12/30] Update package references after subdirs rename. --- Vagrantfile | 2 +- docs/contributing.rst | 2 +- docs/using.rst | 2 +- tox.ini | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index 0659e1ee2..d54e4ea23 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -10,7 +10,7 @@ cd /vagrant sudo ./bootstrap/ubuntu.sh if [ ! -d "venv" ]; then virtualenv --no-site-packages -p python2 venv - ./venv/bin/pip install -r requirements.txt -e acme -e .[dev,docs,testing] -e letsencrypt_apache -e letsencrypt_nginx + ./venv/bin/pip install -r requirements.txt -e acme -e .[dev,docs,testing] -e letsencrypt-apache -e letsencrypt-nginx fi SETUP_SCRIPT diff --git a/docs/contributing.rst b/docs/contributing.rst index c2120f1e1..20a588674 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -26,7 +26,7 @@ Install the development packages: .. code-block:: shell - pip install -r requirements.txt -e acme -e .[dev,docs,testing] -e letsencrypt_apache -e letsencrypt_nginx + pip install -r requirements.txt -e acme -e .[dev,docs,testing] -e letsencrypt-apache -e letsencrypt-nginx .. note:: `-e` (short for `--editable`) turns on *editable mode* in which any source code changes in the current working diff --git a/docs/using.rst b/docs/using.rst index 0d9ffcc73..0812b86e7 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -108,7 +108,7 @@ Installation .. code-block:: shell virtualenv --no-site-packages -p python2 venv - ./venv/bin/pip install -r requirements.txt acme . letsencrypt_apache letsencrypt_nginx + ./venv/bin/pip install -r requirements.txt acme . letsencrypt-apache letsencrypt-nginx .. warning:: Please do **not** use ``python setup.py install``. Please do **not** attempt the installation commands as diff --git a/tox.ini b/tox.ini index 031f3af4f..dc6fb567a 100644 --- a/tox.ini +++ b/tox.ini @@ -14,7 +14,7 @@ envlist = py26,py27,cover,lint # {toxinidir}/venv as it will destroy existing dev venv envdir = {toxinidir}/tox.venv commands = - pip install -r requirements.txt -e acme -e .[testing] -e letsencrypt_apache -e letsencrypt_nginx + pip install -r requirements.txt -e acme -e .[testing] -e letsencrypt-apache -e letsencrypt-nginx # -q does not suppress errors python setup.py test -q python setup.py test -q -s acme @@ -29,7 +29,7 @@ setenv = [testenv:cover] basepython = python2.7 commands = - pip install -r requirements.txt -e acme -e .[testing] -e letsencrypt_apache -e letsencrypt_nginx + pip install -r requirements.txt -e acme -e .[testing] -e letsencrypt-apache -e letsencrypt-nginx ./tox.cover.sh [testenv:lint] @@ -39,8 +39,8 @@ basepython = python2.7 # duplicate code checking; if one of the commands fails, others will # continue, but tox return code will reflect previous error commands = - pip install -r requirements.txt -e acme -e .[dev] -e letsencrypt_apache -e letsencrypt_nginx + pip install -r requirements.txt -e acme -e .[dev] -e letsencrypt-apache -e letsencrypt-nginx pylint --rcfile=.pylintrc letsencrypt pylint --rcfile=.pylintrc acme/acme - pylint --rcfile=.pylintrc letsencrypt_apache/letsencrypt_apache - pylint --rcfile=.pylintrc letsencrypt_nginx/letsencrypt_nginx + pylint --rcfile=.pylintrc letsencrypt-apache/letsencrypt_apache + pylint --rcfile=.pylintrc letsencrypt-nginx/letsencrypt_nginx From c85fa02495394c5fdbfbfe655568e7a91f1c2cd2 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sat, 11 Jul 2015 05:08:43 +0000 Subject: [PATCH 13/30] Leave letsencrypt_ symlinks for Boulder integration testing. --- letsencrypt_apache | 1 + letsencrypt_nginx | 1 + 2 files changed, 2 insertions(+) create mode 120000 letsencrypt_apache create mode 120000 letsencrypt_nginx diff --git a/letsencrypt_apache b/letsencrypt_apache new file mode 120000 index 000000000..f50a82d01 --- /dev/null +++ b/letsencrypt_apache @@ -0,0 +1 @@ +letsencrypt-apache \ No newline at end of file diff --git a/letsencrypt_nginx b/letsencrypt_nginx new file mode 120000 index 000000000..c2f40bb9d --- /dev/null +++ b/letsencrypt_nginx @@ -0,0 +1 @@ +letsencrypt-nginx/ \ No newline at end of file From 04c12a5e3807a8d75754250de29acf4136b263ff Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sat, 11 Jul 2015 05:15:10 +0000 Subject: [PATCH 14/30] Update package references after subdirs rename for Vagrant and Docker. --- Dockerfile | 8 ++++---- docs/conf.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index a045cf2ce..789e26af9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,8 +44,8 @@ COPY setup.py README.rst CHANGES.rst MANIFEST.in /opt/letsencrypt/src/ COPY letsencrypt /opt/letsencrypt/src/letsencrypt/ COPY acme /opt/letsencrypt/src/acme/ -COPY letsencrypt_apache /opt/letsencrypt/src/letsencrypt_apache/ -COPY letsencrypt_nginx /opt/letsencrypt/src/letsencrypt_nginx/ +COPY letsencrypt-apache /opt/letsencrypt/src/letsencrypt-apache/ +COPY letsencrypt-nginx /opt/letsencrypt/src/letsencrypt-nginx/ # requirements.txt not installed! @@ -53,8 +53,8 @@ RUN virtualenv --no-site-packages -p python2 /opt/letsencrypt/venv && \ /opt/letsencrypt/venv/bin/pip install \ -e /opt/letsencrypt/src/acme \ -e /opt/letsencrypt/src \ - -e /opt/letsencrypt/src/letsencrypt_apache \ - -e /opt/letsencrypt/src/letsencrypt_nginx + -e /opt/letsencrypt/src/letsencrypt-apache \ + -e /opt/letsencrypt/src/letsencrypt-nginx # install in editable mode (-e) to save space: it's not possible to # "rm -rf /opt/letsencrypt/src" (it's stays in the underlaying image); diff --git a/docs/conf.py b/docs/conf.py index 62e846a33..50359ba4e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -36,7 +36,7 @@ with codecs.open(init_fn, encoding='utf8') as fd: # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath(os.path.join(here, '..'))) -for pkg in 'acme', 'letsencrypt_apache', 'letsencrypt_nginx': +for pkg in 'acme', 'letsencrypt-apache', 'letsencrypt-nginx': sys.path.insert(0, os.path.abspath(os.path.join(here, '..', pkg))) # -- General configuration ------------------------------------------------ From 10e993331c9946df01023606f2b8f78066a14765 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sat, 11 Jul 2015 06:09:52 +0000 Subject: [PATCH 15/30] Update installation instructions for pkgs subdirs (include trailing slash). --- docs/using.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index 0812b86e7..fa0f7b8a9 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -105,10 +105,13 @@ Centos 7 Installation ============ +.. "pip install acme" doesn't search for "acme" in cwd, just like "pip + install -e acme" does + .. code-block:: shell virtualenv --no-site-packages -p python2 venv - ./venv/bin/pip install -r requirements.txt acme . letsencrypt-apache letsencrypt-nginx + ./venv/bin/pip install -r requirements.txt acme/ . letsencrypt-apache/ letsencrypt-nginx/ .. warning:: Please do **not** use ``python setup.py install``. Please do **not** attempt the installation commands as From 802b9d4a4306954c255273d1a3b7b83d86aaaba8 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sat, 11 Jul 2015 15:50:49 +0000 Subject: [PATCH 16/30] Support for py3.3+ in acme.jose. --- acme/acme/jose/__init__.py | 2 + acme/acme/jose/b64.py | 26 ++++---- acme/acme/jose/b64_test.py | 36 ++++++----- acme/acme/jose/interfaces.py | 18 ++++-- acme/acme/jose/json_util.py | 83 +++++++++++++++++++------ acme/acme/jose/json_util_test.py | 101 +++++++++++++++++++------------ acme/acme/jose/jwa.py | 6 +- acme/acme/jose/jwa_test.py | 37 +++++------ acme/acme/jose/jwk.py | 31 +++++++--- acme/acme/jose/jwk_test.py | 16 +++-- acme/acme/jose/jws.py | 79 +++++++++++++++--------- acme/acme/jose/jws_test.py | 28 +++++---- acme/acme/jose/util.py | 15 +++-- acme/acme/jose/util_test.py | 6 +- acme/setup.py | 1 + 15 files changed, 315 insertions(+), 170 deletions(-) diff --git a/acme/acme/jose/__init__.py b/acme/acme/jose/__init__.py index 793b342b0..76969139b 100644 --- a/acme/acme/jose/__init__.py +++ b/acme/acme/jose/__init__.py @@ -44,8 +44,10 @@ from acme.jose.json_util import ( decode_cert, decode_csr, decode_hex16, + encode_b64jose, encode_cert, encode_csr, + encode_hex16, ) from acme.jose.jwa import ( diff --git a/acme/acme/jose/b64.py b/acme/acme/jose/b64.py index 8f2d284ce..5fccdce2e 100644 --- a/acme/acme/jose/b64.py +++ b/acme/acme/jose/b64.py @@ -9,28 +9,31 @@ .. _`JOSE Base64`: https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-37#appendix-C -.. warning:: Do NOT try to call this module "base64", - as it will "shadow" the standard library. +.. Do NOT try to call this module "base64", as it will "shadow" the + standard library. """ import base64 +import six + def b64encode(data): """JOSE Base64 encode. :param data: Data to be encoded. - :type data: str or bytearray + :type data: `bytes` or `bytearray` :returns: JOSE Base64 string. - :rtype: str + :rtype: bytes :raises TypeError: if `data` is of incorrect type """ - if not isinstance(data, str): - raise TypeError('argument should be str or bytearray') - return base64.urlsafe_b64encode(data).rstrip('=') + if not isinstance(data, (six.binary_type, bytearray)): + raise TypeError('argument should be {0} or bytearray'.format( + six.binary_type)) + return base64.urlsafe_b64encode(data).rstrip(b'=') def b64decode(data): @@ -38,21 +41,22 @@ def b64decode(data): :param data: Base64 string to be decoded. If it's unicode, then only ASCII characters are allowed. - :type data: str or unicode + :type data: `bytes` or `unicode` :returns: Decoded data. + :rtype: bytes :raises TypeError: if input is of incorrect type :raises ValueError: if input is unicode with non-ASCII characters """ - if isinstance(data, unicode): + if isinstance(data, six.string_types): try: data = data.encode('ascii') except UnicodeEncodeError: raise ValueError( 'unicode argument should contain only ASCII characters') - elif not isinstance(data, str): + elif not isinstance(data, six.binary_type): raise TypeError('argument should be a str or unicode') - return base64.urlsafe_b64decode(data + '=' * (4 - (len(data) % 4))) + return base64.urlsafe_b64decode(data + b'=' * (4 - (len(data) % 4))) diff --git a/acme/acme/jose/b64_test.py b/acme/acme/jose/b64_test.py index 0c243cb2a..989f8e7fe 100644 --- a/acme/acme/jose/b64_test.py +++ b/acme/acme/jose/b64_test.py @@ -1,20 +1,22 @@ """Tests for acme.jose.b64.""" import unittest +import six + # https://en.wikipedia.org/wiki/Base64#Examples B64_PADDING_EXAMPLES = { - 'any carnal pleasure.': ('YW55IGNhcm5hbCBwbGVhc3VyZS4', '='), - 'any carnal pleasure': ('YW55IGNhcm5hbCBwbGVhc3VyZQ', '=='), - 'any carnal pleasur': ('YW55IGNhcm5hbCBwbGVhc3Vy', ''), - 'any carnal pleasu': ('YW55IGNhcm5hbCBwbGVhc3U', '='), - 'any carnal pleas': ('YW55IGNhcm5hbCBwbGVhcw', '=='), + b'any carnal pleasure.': (b'YW55IGNhcm5hbCBwbGVhc3VyZS4', b'='), + b'any carnal pleasure': (b'YW55IGNhcm5hbCBwbGVhc3VyZQ', b'=='), + b'any carnal pleasur': (b'YW55IGNhcm5hbCBwbGVhc3Vy', b''), + b'any carnal pleasu': (b'YW55IGNhcm5hbCBwbGVhc3U', b'='), + b'any carnal pleas': (b'YW55IGNhcm5hbCBwbGVhcw', b'=='), } B64_URL_UNSAFE_EXAMPLES = { - chr(251) + chr(239): '--8', - chr(255) * 2: '__8', + six.int2byte(251) + six.int2byte(239): b'--8', + six.int2byte(255) * 2: b'__8', } @@ -26,14 +28,20 @@ class B64EncodeTest(unittest.TestCase): from acme.jose.b64 import b64encode return b64encode(data) + def test_empty(self): + self.assertEqual(self._call(b''), b'') + def test_unsafe_url(self): - for text, b64 in B64_URL_UNSAFE_EXAMPLES.iteritems(): + for text, b64 in six.iteritems(B64_URL_UNSAFE_EXAMPLES): self.assertEqual(self._call(text), b64) def test_different_paddings(self): - for text, (b64, _) in B64_PADDING_EXAMPLES.iteritems(): + for text, (b64, _) in six.iteritems(B64_PADDING_EXAMPLES): self.assertEqual(self._call(text), b64) + def test_bytearray_ok(self): + self.assertEqual(self._call(bytearray(b'foo')), b'Zm9v') + def test_unicode_fails_with_type_error(self): self.assertRaises(TypeError, self._call, u'some unicode') @@ -47,24 +55,24 @@ class B64DecodeTest(unittest.TestCase): return b64decode(data) def test_unsafe_url(self): - for text, b64 in B64_URL_UNSAFE_EXAMPLES.iteritems(): + for text, b64 in six.iteritems(B64_URL_UNSAFE_EXAMPLES): self.assertEqual(self._call(b64), text) def test_input_without_padding(self): - for text, (b64, _) in B64_PADDING_EXAMPLES.iteritems(): + for text, (b64, _) in six.iteritems(B64_PADDING_EXAMPLES): self.assertEqual(self._call(b64), text) def test_input_with_padding(self): - for text, (b64, pad) in B64_PADDING_EXAMPLES.iteritems(): + for text, (b64, pad) in six.iteritems(B64_PADDING_EXAMPLES): self.assertEqual(self._call(b64 + pad), text) def test_unicode_with_ascii(self): - self.assertEqual(self._call(u'YQ'), 'a') + self.assertEqual(self._call(u'YQ'), b'a') def test_non_ascii_unicode_fails(self): self.assertRaises(ValueError, self._call, u'\u0105') - def test_type_error_no_unicode_or_str(self): + def test_type_error_no_unicode_or_bytes(self): self.assertRaises(TypeError, self._call, object()) diff --git a/acme/acme/jose/interfaces.py b/acme/acme/jose/interfaces.py index 27dcf863f..96dae6bae 100644 --- a/acme/acme/jose/interfaces.py +++ b/acme/acme/jose/interfaces.py @@ -3,12 +3,15 @@ import abc import collections import json +import six + from acme.jose import util # pylint: disable=no-self-argument,no-method-argument,no-init,inherit-non-class # pylint: disable=too-few-public-methods +@six.add_metaclass(abc.ABCMeta) class JSONDeSerializable(object): # pylint: disable=too-few-public-methods """Interface for (de)serializable JSON objects. @@ -96,7 +99,6 @@ class JSONDeSerializable(object): return Bar() """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def to_partial_json(self): # pragma: no cover @@ -133,7 +135,7 @@ class JSONDeSerializable(object): def _serialize(obj): if isinstance(obj, JSONDeSerializable): return _serialize(obj.to_partial_json()) - if isinstance(obj, basestring): # strings are sequence + if isinstance(obj, six.string_types): # strings are Sequence return obj elif isinstance(obj, list): return [_serialize(subobj) for subobj in obj] @@ -143,14 +145,14 @@ class JSONDeSerializable(object): return tuple(_serialize(subobj) for subobj in obj) elif isinstance(obj, collections.Mapping): return dict((_serialize(key), _serialize(value)) - for key, value in obj.iteritems()) + for key, value in six.iteritems(obj)) else: return obj return _serialize(self) @util.abstractclassmethod - def from_json(cls, unused_jobj): + def from_json(cls, jobj): # pylint: disable=unused-argument """Deserialize a decoded JSON document. :param jobj: Python object, composed of only other basic data @@ -182,7 +184,11 @@ class JSONDeSerializable(object): return json.dumps(self, default=self.json_dump_default, **kwargs) def json_dumps_pretty(self): - """Dump the object to pretty JSON document string.""" + """Dump the object to pretty JSON document string. + + :rtype: str + + """ return self.json_dumps(sort_keys=True, indent=4, separators=(',', ': ')) @classmethod @@ -190,7 +196,7 @@ class JSONDeSerializable(object): """Serialize Python object. This function is meant to be passed as ``default`` to - :func:`json.load` or :func:`json.loads`. They call + :func:`json.dump` or :func:`json.dumps`. They call ``default(python_object)`` only for non-basic Python types, so this function necessarily raises :class:`TypeError` if ``python_object`` is not an instance of diff --git a/acme/acme/jose/json_util.py b/acme/acme/jose/json_util.py index fe3831296..c531efd9d 100644 --- a/acme/acme/jose/json_util.py +++ b/acme/acme/jose/json_util.py @@ -11,6 +11,7 @@ import binascii import logging import OpenSSL +import six from acme.jose import b64 from acme.jose import errors @@ -109,7 +110,7 @@ class Field(object): elif isinstance(value, dict): return util.frozendict( dict((cls.default_decoder(key), cls.default_decoder(value)) - for key, value in value.iteritems())) + for key, value in six.iteritems(value))) else: # integer or string return value @@ -167,17 +168,20 @@ class JSONObjectWithFieldsMeta(abc.ABCMeta): for base in bases: fields.update(getattr(base, '_fields', {})) # Do not reorder, this class might override fields from base classes! - for key, value in dikt.items(): # not iterkeys() (in-place edit!) + for key, value in tuple(six.iteritems(dikt)): + # not six.iterkeys() (in-place edit!) if isinstance(value, Field): fields[key] = dikt.pop(key) dikt['_orig_slots'] = dikt.get('__slots__', ()) - dikt['__slots__'] = tuple(list(dikt['_orig_slots']) + fields.keys()) + dikt['__slots__'] = tuple( + list(dikt['_orig_slots']) + list(six.iterkeys(fields))) dikt['_fields'] = fields return abc.ABCMeta.__new__(mcs, name, bases, dikt) +@six.add_metaclass(JSONObjectWithFieldsMeta) class JSONObjectWithFields(util.ImmutableMap, interfaces.JSONDeSerializable): # pylint: disable=too-few-public-methods """JSON object with fields. @@ -205,13 +209,12 @@ class JSONObjectWithFields(util.ImmutableMap, interfaces.JSONDeSerializable): assert Foo(bar='baz').bar == 'baz' """ - __metaclass__ = JSONObjectWithFieldsMeta @classmethod def _defaults(cls): """Get default fields values.""" return dict([(slot, field.default) for slot, field - in cls._fields.iteritems() if field.omitempty]) + in six.iteritems(cls._fields) if field.omitempty]) def __init__(self, **kwargs): # pylint: disable=star-args @@ -222,7 +225,7 @@ class JSONObjectWithFields(util.ImmutableMap, interfaces.JSONDeSerializable): """Serialize fields to JSON.""" jobj = {} omitted = set() - for slot, field in self._fields.iteritems(): + for slot, field in six.iteritems(self._fields): value = getattr(self, slot) if field.omit(value): @@ -246,7 +249,7 @@ class JSONObjectWithFields(util.ImmutableMap, interfaces.JSONDeSerializable): @classmethod def _check_required(cls, jobj): missing = set() - for _, field in cls._fields.iteritems(): + for _, field in six.iteritems(cls._fields): if not field.omitempty and field.json_name not in jobj: missing.add(field.json_name) @@ -260,7 +263,7 @@ class JSONObjectWithFields(util.ImmutableMap, interfaces.JSONDeSerializable): """Deserialize fields from JSON.""" cls._check_required(jobj) fields = {} - for slot, field in cls._fields.iteritems(): + for slot, field in six.iteritems(cls._fields): if field.json_name not in jobj and field.omitempty: fields[slot] = field.default else: @@ -278,17 +281,31 @@ class JSONObjectWithFields(util.ImmutableMap, interfaces.JSONDeSerializable): return cls(**cls.fields_from_json(jobj)) +def encode_b64jose(data): + """Encode JOSE Base-64 field. + + :param bytes data: + :rtype: `unicode` + + """ + # b64encode produces ASCII characters only + return b64.b64encode(data).decode('ascii') + def decode_b64jose(data, size=None, minimum=False): """Decode JOSE Base-64 field. + :param unicode data: :param int size: Required length (after decoding). :param bool minimum: If ``True``, then `size` will be treated as minimum required length, as opposed to exact equality. + :rtype: bytes + """ + error_cls = TypeError if six.PY2 else binascii.Error try: - decoded = b64.b64decode(data) - except TypeError as error: + decoded = b64.b64decode(data.encode()) + except error_cls as error: raise errors.DeserializationError(error) if size is not None and ((not minimum and len(decoded) != size) @@ -297,35 +314,53 @@ def decode_b64jose(data, size=None, minimum=False): return decoded +def encode_hex16(value): + """Hexlify. + + :param bytes value: + :rtype: unicode + + """ + return binascii.hexlify(value).decode() def decode_hex16(value, size=None, minimum=False): """Decode hexlified field. + :param unicode value: :param int size: Required length (after decoding). :param bool minimum: If ``True``, then `size` will be treated as minimum required length, as opposed to exact equality. + :rtype: bytes + """ + value = value.encode() if size is not None and ((not minimum and len(value) != size * 2) or (minimum and len(value) < size * 2)): raise errors.DeserializationError() + error_cls = TypeError if six.PY2 else binascii.Error try: return binascii.unhexlify(value) - except TypeError as error: + except error_cls as error: raise errors.DeserializationError(error) def encode_cert(cert): """Encode certificate as JOSE Base-64 DER. - :param cert: Certificate. - :type cert: :class:`acme.jose.util.ComparableX509` + :type cert: `OpenSSL.crypto.X509` wrapped in `.ComparableX509` + :rtype: unicode """ - return b64.b64encode(OpenSSL.crypto.dump_certificate( + return encode_b64jose(OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_ASN1, cert)) def decode_cert(b64der): - """Decode JOSE Base-64 DER-encoded certificate.""" + """Decode JOSE Base-64 DER-encoded certificate. + + :param unicode b64der: + :rtype: `OpenSSL.crypto.X509` wrapped in `.ComparableX509` + + """ try: return util.ComparableX509(OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_ASN1, decode_b64jose(b64der))) @@ -333,12 +368,22 @@ def decode_cert(b64der): raise errors.DeserializationError(error) def encode_csr(csr): - """Encode CSR as JOSE Base-64 DER.""" - return b64.b64encode(OpenSSL.crypto.dump_certificate_request( + """Encode CSR as JOSE Base-64 DER. + + :type csr: `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509` + :rtype: unicode + + """ + return encode_b64jose(OpenSSL.crypto.dump_certificate_request( OpenSSL.crypto.FILETYPE_ASN1, csr)) def decode_csr(b64der): - """Decode JOSE Base-64 DER-encoded CSR.""" + """Decode JOSE Base-64 DER-encoded CSR. + + :param unicode b64der: + :rtype: `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509` + + """ try: return util.ComparableX509(OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_ASN1, decode_b64jose(b64der))) @@ -372,7 +417,7 @@ class TypedJSONObjectWithFields(JSONObjectWithFields): @classmethod def get_type_cls(cls, jobj): """Get the registered class for ``jobj``.""" - if cls in cls.TYPES.itervalues(): + if cls in six.itervalues(cls.TYPES): assert jobj[cls.type_field_name] # cls is already registered type_cls, force to use it # so that, e.g Revocation.from_json(jobj) fails if diff --git a/acme/acme/jose/json_util_test.py b/acme/acme/jose/json_util_test.py index 9e2a87858..2225267ee 100644 --- a/acme/acme/jose/json_util_test.py +++ b/acme/acme/jose/json_util_test.py @@ -3,6 +3,7 @@ import itertools import unittest import mock +import six from acme import test_util @@ -92,8 +93,8 @@ class JSONObjectWithFieldsMetaTest(unittest.TestCase): self.field2 = Field('Baz2') # pylint: disable=invalid-name,missing-docstring,too-few-public-methods # pylint: disable=blacklisted-name + @six.add_metaclass(JSONObjectWithFieldsMeta) class A(object): - __metaclass__ = JSONObjectWithFieldsMeta __slots__ = ('bar',) baz = self.field class B(A): @@ -207,62 +208,82 @@ class JSONObjectWithFieldsTest(unittest.TestCase): class DeEncodersTest(unittest.TestCase): def setUp(self): self.b64_cert = ( - 'MIIB3jCCAYigAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhM' - 'CVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKz' - 'ApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxF' - 'DASBgNVBAMMC2V4YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIx' - 'ODIyMzQ0NVowdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRI' - 'wEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTW' - 'ljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4YW1wbGUuY29tMFwwD' - 'QYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR7R_drnBSQ_zfx1vQLHUbFLh1' - 'AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c-pVE6K-EdE_twuUCAwE' - 'AATANBgkqhkiG9w0BAQsFAANBAC24z0IdwIVKSlntksllvr6zJepBH5fMnd' - 'fk3XJp10jT6VE-14KNtjh02a56GoraAvJAT5_H67E8GvJ_ocNnB_o' + u'MIIB3jCCAYigAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhM' + u'CVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKz' + u'ApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxF' + u'DASBgNVBAMMC2V4YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIx' + u'ODIyMzQ0NVowdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRI' + u'wEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTW' + u'ljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4YW1wbGUuY29tMFwwD' + u'QYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR7R_drnBSQ_zfx1vQLHUbFLh1' + u'AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c-pVE6K-EdE_twuUCAwE' + u'AATANBgkqhkiG9w0BAQsFAANBAC24z0IdwIVKSlntksllvr6zJepBH5fMnd' + u'fk3XJp10jT6VE-14KNtjh02a56GoraAvJAT5_H67E8GvJ_ocNnB_o' ) self.b64_csr = ( - 'MIIBXTCCAQcCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2F' - 'uMRIwEAYDVQQHDAlBbm4gQXJib3IxDDAKBgNVBAoMA0VGRjEfMB0GA1UECw' - 'wWVW5pdmVyc2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAwwLZXhhbXBsZS5jb' - '20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEArHVztFHtH92ucFJD_N_HW9As' - 'dRsUuHUBBBDlHwNlRd3fp580rv2-6QWE30cWgdmJS86ObRz6lUTor4R0T-3' - 'C5QIDAQABoCkwJwYJKoZIhvcNAQkOMRowGDAWBgNVHREEDzANggtleGFtcG' - 'xlLmNvbTANBgkqhkiG9w0BAQsFAANBAHJH_O6BtC9aGzEVCMGOZ7z9iIRHW' - 'Szr9x_bOzn7hLwsbXPAgO1QxEwL-X-4g20Gn9XBE1N9W6HCIEut2d8wACg' + u'MIIBXTCCAQcCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2F' + u'uMRIwEAYDVQQHDAlBbm4gQXJib3IxDDAKBgNVBAoMA0VGRjEfMB0GA1UECw' + u'wWVW5pdmVyc2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAwwLZXhhbXBsZS5jb' + u'20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEArHVztFHtH92ucFJD_N_HW9As' + u'dRsUuHUBBBDlHwNlRd3fp580rv2-6QWE30cWgdmJS86ObRz6lUTor4R0T-3' + u'C5QIDAQABoCkwJwYJKoZIhvcNAQkOMRowGDAWBgNVHREEDzANggtleGFtcG' + u'xlLmNvbTANBgkqhkiG9w0BAQsFAANBAHJH_O6BtC9aGzEVCMGOZ7z9iIRHW' + u'Szr9x_bOzn7hLwsbXPAgO1QxEwL-X-4g20Gn9XBE1N9W6HCIEut2d8wACg' ) - def test_decode_b64_jose_padding_error(self): - from acme.jose.json_util import decode_b64jose - self.assertRaises(errors.DeserializationError, decode_b64jose, 'x') + def test_encode_b64jose(self): + from acme.jose.json_util import encode_b64jose + encoded = encode_b64jose(b'x') + self.assertTrue(isinstance(encoded, six.string_types)) + self.assertEqual(u'eA', encoded) - def test_decode_b64_jose_size(self): + def test_decode_b64jose(self): from acme.jose.json_util import decode_b64jose - self.assertEqual('foo', decode_b64jose('Zm9v', size=3)) - self.assertRaises( - errors.DeserializationError, decode_b64jose, 'Zm9v', size=2) - self.assertRaises( - errors.DeserializationError, decode_b64jose, 'Zm9v', size=4) + decoded = decode_b64jose(u'eA') + self.assertTrue(isinstance(decoded, six.binary_type)) + self.assertEqual(b'x', decoded) - def test_decode_b64_jose_minimum_size(self): + def test_decode_b64jose_padding_error(self): from acme.jose.json_util import decode_b64jose - self.assertEqual('foo', decode_b64jose('Zm9v', size=3, minimum=True)) - self.assertEqual('foo', decode_b64jose('Zm9v', size=2, minimum=True)) + self.assertRaises(errors.DeserializationError, decode_b64jose, u'x') + + def test_decode_b64jose_size(self): + from acme.jose.json_util import decode_b64jose + self.assertEqual(b'foo', decode_b64jose(u'Zm9v', size=3)) + self.assertRaises( + errors.DeserializationError, decode_b64jose, u'Zm9v', size=2) + self.assertRaises( + errors.DeserializationError, decode_b64jose, u'Zm9v', size=4) + + def test_decode_b64jose_minimum_size(self): + from acme.jose.json_util import decode_b64jose + self.assertEqual(b'foo', decode_b64jose(u'Zm9v', size=3, minimum=True)) + self.assertEqual(b'foo', decode_b64jose(u'Zm9v', size=2, minimum=True)) self.assertRaises(errors.DeserializationError, decode_b64jose, - 'Zm9v', size=4, minimum=True) + u'Zm9v', size=4, minimum=True) + + def test_encode_hex16(self): + from acme.jose.json_util import encode_hex16 + encoded = encode_hex16(b'foo') + self.assertEqual(u'666f6f', encoded) + self.assertTrue(isinstance(encoded, six.string_types)) def test_decode_hex16(self): from acme.jose.json_util import decode_hex16 - self.assertEqual('foo', decode_hex16('666f6f')) + decoded = decode_hex16(u'666f6f') + self.assertEqual(b'foo', decoded) + self.assertTrue(isinstance(decoded, six.binary_type)) def test_decode_hex16_minimum_size(self): from acme.jose.json_util import decode_hex16 - self.assertEqual('foo', decode_hex16('666f6f', size=3, minimum=True)) - self.assertEqual('foo', decode_hex16('666f6f', size=2, minimum=True)) + self.assertEqual(b'foo', decode_hex16(u'666f6f', size=3, minimum=True)) + self.assertEqual(b'foo', decode_hex16(u'666f6f', size=2, minimum=True)) self.assertRaises(errors.DeserializationError, decode_hex16, - '666f6f', size=4, minimum=True) + u'666f6f', size=4, minimum=True) def test_decode_hex16_odd_length(self): from acme.jose.json_util import decode_hex16 - self.assertRaises(errors.DeserializationError, decode_hex16, 'x') + self.assertRaises(errors.DeserializationError, decode_hex16, u'x') def test_encode_cert(self): from acme.jose.json_util import encode_cert @@ -273,7 +294,7 @@ class DeEncodersTest(unittest.TestCase): cert = decode_cert(self.b64_cert) self.assertTrue(isinstance(cert, util.ComparableX509)) self.assertEqual(cert, CERT) - self.assertRaises(errors.DeserializationError, decode_cert, '') + self.assertRaises(errors.DeserializationError, decode_cert, u'') def test_encode_csr(self): from acme.jose.json_util import encode_csr @@ -284,7 +305,7 @@ class DeEncodersTest(unittest.TestCase): csr = decode_csr(self.b64_csr) self.assertTrue(isinstance(csr, util.ComparableX509)) self.assertEqual(csr, CSR) - self.assertRaises(errors.DeserializationError, decode_csr, '') + self.assertRaises(errors.DeserializationError, decode_csr, u'') class TypedJSONObjectWithFieldsTest(unittest.TestCase): diff --git a/acme/acme/jose/jwa.py b/acme/acme/jose/jwa.py index f081aa169..0c84905df 100644 --- a/acme/acme/jose/jwa.py +++ b/acme/acme/jose/jwa.py @@ -4,6 +4,7 @@ https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 """ import abc +import collections import logging import cryptography.exceptions @@ -27,7 +28,7 @@ class JWA(interfaces.JSONDeSerializable): # pylint: disable=abstract-method """JSON Web Algorithm.""" -class JWASignature(JWA): +class JWASignature(JWA, collections.Hashable): """JSON Web Signature Algorithm.""" SIGNATURES = {} @@ -39,6 +40,9 @@ class JWASignature(JWA): return NotImplemented return self.name == other.name + def __hash__(self): + return hash((self.__class__, self.name)) + def __ne__(self, other): return not self == other diff --git a/acme/acme/jose/jwa_test.py b/acme/acme/jose/jwa_test.py index 1a3896f4a..3328d083a 100644 --- a/acme/acme/jose/jwa_test.py +++ b/acme/acme/jose/jwa_test.py @@ -58,12 +58,12 @@ class JWAHSTest(unittest.TestCase): # pylint: disable=too-few-public-methods def test_it(self): from acme.jose.jwa import HS256 sig = ( - "\xceR\xea\xcd\x94\xab\xcf\xfb\xe0\xacA.:\x1a'\x08i\xe2\xc4" - "\r\x85+\x0e\x85\xaeUZ\xd4\xb3\x97zO" + b"\xceR\xea\xcd\x94\xab\xcf\xfb\xe0\xacA.:\x1a'\x08i\xe2\xc4" + b"\r\x85+\x0e\x85\xaeUZ\xd4\xb3\x97zO" ) - self.assertEqual(HS256.sign('some key', 'foo'), sig) - self.assertTrue(HS256.verify('some key', 'foo', sig) is True) - self.assertTrue(HS256.verify('some key', 'foo', sig + '!') is False) + self.assertEqual(HS256.sign(b'some key', b'foo'), sig) + self.assertTrue(HS256.verify(b'some key', b'foo', sig) is True) + self.assertTrue(HS256.verify(b'some key', b'foo', sig + b'!') is False) class JWARSTest(unittest.TestCase): @@ -71,32 +71,33 @@ class JWARSTest(unittest.TestCase): def test_sign_no_private_part(self): from acme.jose.jwa import RS256 self.assertRaises( - errors.Error, RS256.sign, RSA512_KEY.public_key(), 'foo') + errors.Error, RS256.sign, RSA512_KEY.public_key(), b'foo') def test_sign_key_too_small(self): from acme.jose.jwa import RS256 from acme.jose.jwa import PS256 - self.assertRaises(errors.Error, RS256.sign, RSA256_KEY, 'foo') - self.assertRaises(errors.Error, PS256.sign, RSA256_KEY, 'foo') + self.assertRaises(errors.Error, RS256.sign, RSA256_KEY, b'foo') + self.assertRaises(errors.Error, PS256.sign, RSA256_KEY, b'foo') def test_rs(self): from acme.jose.jwa import RS256 sig = ( - '|\xc6\xb2\xa4\xab(\x87\x99\xfa*:\xea\xf8\xa0N&}\x9f\x0f\xc0O' - '\xc6t\xa3\xe6\xfa\xbb"\x15Y\x80Y\xe0\x81\xb8\x88)\xba\x0c\x9c' - '\xa4\x99\x1e\x19&\xd8\xc7\x99S\x97\xfc\x85\x0cOV\xe6\x07\x99' - '\xd2\xb9.>}\xfd' + b'|\xc6\xb2\xa4\xab(\x87\x99\xfa*:\xea\xf8\xa0N&}\x9f\x0f\xc0O' + b'\xc6t\xa3\xe6\xfa\xbb"\x15Y\x80Y\xe0\x81\xb8\x88)\xba\x0c\x9c' + b'\xa4\x99\x1e\x19&\xd8\xc7\x99S\x97\xfc\x85\x0cOV\xe6\x07\x99' + b'\xd2\xb9.>}\xfd' ) - self.assertEqual(RS256.sign(RSA512_KEY, 'foo'), sig) - self.assertTrue(RS256.verify(RSA512_KEY.public_key(), 'foo', sig)) + self.assertEqual(RS256.sign(RSA512_KEY, b'foo'), sig) + self.assertTrue(RS256.verify(RSA512_KEY.public_key(), b'foo', sig)) self.assertFalse(RS256.verify( - RSA512_KEY.public_key(), 'foo', sig + '!')) + RSA512_KEY.public_key(), b'foo', sig + b'!')) def test_ps(self): from acme.jose.jwa import PS256 - sig = PS256.sign(RSA1024_KEY, 'foo') - self.assertTrue(PS256.verify(RSA1024_KEY.public_key(), 'foo', sig)) - self.assertFalse(PS256.verify(RSA1024_KEY.public_key(), 'foo', sig + '!')) + sig = PS256.sign(RSA1024_KEY, b'foo') + self.assertTrue(PS256.verify(RSA1024_KEY.public_key(), b'foo', sig)) + self.assertFalse(PS256.verify( + RSA1024_KEY.public_key(), b'foo', sig + b'!')) if __name__ == '__main__': diff --git a/acme/acme/jose/jwk.py b/acme/acme/jose/jwk.py index 2b48d56e6..d9b903eb0 100644 --- a/acme/acme/jose/jwk.py +++ b/acme/acme/jose/jwk.py @@ -9,7 +9,8 @@ from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric import rsa -from acme.jose import b64 +import six + from acme.jose import errors from acme.jose import json_util from acme.jose import util @@ -87,7 +88,7 @@ class JWK(json_util.TypedJSONObjectWithFields): key, cls.cryptography_key_types): raise errors.Error("Unable to deserialize {0} into {1}".format( key.__class__, cls.__class__)) - for jwk_cls in cls.TYPES.itervalues(): + for jwk_cls in six.itervalues(cls.TYPES): if isinstance(key, jwk_cls.cryptography_key_types): return jwk_cls(key=key) raise errors.Error("Unsupported algorithm: {0}".format(key.__class__)) @@ -127,11 +128,11 @@ class JWKOct(JWK): # algorithm intended to be used with the key, unless the # application uses another means or convention to determine # the algorithm used. - return {'k': self.key} + return {'k': json_util.encode_b64jose(self.key)} @classmethod def fields_from_json(cls, jobj): - return cls(key=jobj['k']) + return cls(key=json_util.decode_b64jose(jobj['k'])) def public_key(self): return self @@ -158,18 +159,25 @@ class JWKRSA(JWK): @classmethod def _encode_param(cls, data): + """Encode Base64urlUInt. + + :type data: long + :rtype: unicode + + """ def _leading_zeros(arg): if len(arg) % 2: return '0' + arg return arg - return b64.b64encode(binascii.unhexlify( + return json_util.encode_b64jose(binascii.unhexlify( _leading_zeros(hex(data)[2:].rstrip('L')))) @classmethod def _decode_param(cls, data): + """Decode Base64urlUInt.""" try: - return long(binascii.hexlify(json_util.decode_b64jose(data)), 16) + return int(binascii.hexlify(json_util.decode_b64jose(data)), 16) except ValueError: # invalid literal for long() with base 16 raise errors.DeserializationError() @@ -198,17 +206,20 @@ class JWKRSA(JWK): raise errors.Error( "Some private parameters are missing: {0}".format( all_params)) - p, q, dp, dq, qi = tuple(cls._decode_param(x) for x in all_params) + p, q, dp, dq, qi = tuple( + cls._decode_param(x) for x in all_params) # TODO: check for oth else: - p, q = rsa.rsa_recover_prime_factors(n, e, d) # cryptography>=0.8 + # cryptography>=0.8 + p, q = rsa.rsa_recover_prime_factors(n, e, d) dp = rsa.rsa_crt_dmp1(d, p) dq = rsa.rsa_crt_dmq1(d, q) qi = rsa.rsa_crt_iqmp(p, q) key = rsa.RSAPrivateNumbers( - p, q, d, dp, dq, qi, public_numbers).private_key(default_backend()) + p, q, d, dp, dq, qi, public_numbers).private_key( + default_backend()) return cls(key=key) @@ -234,4 +245,4 @@ class JWKRSA(JWK): 'qi': private.iqmp, } return dict((key, self._encode_param(value)) - for key, value in params.iteritems()) + for key, value in six.iteritems(params)) diff --git a/acme/acme/jose/jwk_test.py b/acme/acme/jose/jwk_test.py index 86674b726..5462af6b0 100644 --- a/acme/acme/jose/jwk_test.py +++ b/acme/acme/jose/jwk_test.py @@ -4,6 +4,7 @@ import unittest from acme import test_util from acme.jose import errors +from acme.jose import json_util from acme.jose import util @@ -29,8 +30,8 @@ class JWKOctTest(unittest.TestCase): def setUp(self): from acme.jose.jwk import JWKOct - self.jwk = JWKOct(key='foo') - self.jobj = {'kty': 'oct', 'k': 'foo'} + self.jwk = JWKOct(key=b'foo') + self.jobj = {'kty': 'oct', 'k': json_util.encode_b64jose(b'foo')} def test_to_partial_json(self): self.assertEqual(self.jwk.to_partial_json(), self.jobj) @@ -45,7 +46,7 @@ class JWKOctTest(unittest.TestCase): def test_load(self): from acme.jose.jwk import JWKOct - self.assertEqual(self.jwk, JWKOct.load('foo')) + self.assertEqual(self.jwk, JWKOct.load(b'foo')) def test_public_key(self): self.assertTrue(self.jwk.public_key() is self.jwk) @@ -64,7 +65,8 @@ class JWKRSATest(unittest.TestCase): 'n': 'm2Fylv-Uz7trgTW8EBHP3FQSMeZs2GNQ6VRo1sIVJEk', } # pylint: disable=protected-access - self.jwk256_not_comparable = JWKRSA(key=RSA256_KEY.public_key()._wrapped) + self.jwk256_not_comparable = JWKRSA( + key=RSA256_KEY.public_key()._wrapped) self.jwk512 = JWKRSA(key=RSA512_KEY.public_key()) self.jwk512json = { 'kty': 'RSA', @@ -91,6 +93,12 @@ class JWKRSATest(unittest.TestCase): self.jwk256_not_comparable.key, util.ComparableRSAKey)) self.assertEqual(self.jwk256, self.jwk256_not_comparable) + def test_encode_param_zero(self): + from acme.jose.jwk import JWKRSA + # pylint: disable=protected-access + # TODO: move encode/decode _param to separate class + self.assertEqual('AA', JWKRSA._encode_param(0)) + def test_equals(self): self.assertEqual(self.jwk256, self.jwk256) self.assertEqual(self.jwk512, self.jwk512) diff --git a/acme/acme/jose/jws.py b/acme/acme/jose/jws.py index 6d1a5db2b..7ecc87bf2 100644 --- a/acme/acme/jose/jws.py +++ b/acme/acme/jose/jws.py @@ -4,6 +4,7 @@ import base64 import sys import OpenSSL +import six from acme.jose import b64 from acme.jose import errors @@ -80,7 +81,7 @@ class Header(json_util.JSONObjectWithFields): def not_omitted(self): """Fields that would not be omitted in the JSON object.""" return dict((name, getattr(self, name)) - for name, field in self._fields.iteritems() + for name, field in six.iteritems(self._fields) if not field.omit(getattr(self, name))) def __add__(self, other): @@ -148,15 +149,22 @@ class Signature(json_util.JSONObjectWithFields): header_cls = Header __slots__ = ('combined',) - protected = json_util.Field( - 'protected', omitempty=True, default='', - decoder=json_util.decode_b64jose, encoder=b64.b64encode) # TODO: utf-8? + protected = json_util.Field('protected', omitempty=True, default='') header = json_util.Field( 'header', omitempty=True, default=header_cls(), decoder=header_cls.from_json) signature = json_util.Field( 'signature', decoder=json_util.decode_b64jose, - encoder=b64.b64encode) + encoder=json_util.encode_b64jose) + + @protected.encoder + def protected(value): # pylint: disable=missing-docstring,no-self-argument + # wrong type guess (Signature, not bytes) | pylint: disable=no-member + return json_util.encode_b64jose(value.encode('utf-8')) + + @protected.decoder + def protected(value): # pylint: disable=missing-docstring,no-self-argument + return json_util.decode_b64jose(value).decode('utf-8') def __init__(self, **kwargs): if 'combined' not in kwargs: @@ -178,6 +186,11 @@ class Signature(json_util.JSONObjectWithFields): kwargs['combined'] = combined return kwargs + @classmethod + def _msg(cls, protected, payload): + return (b64.b64encode(protected.encode('utf-8')) + b'.' + + b64.b64encode(payload)) + def verify(self, payload, key=None): """Verify. @@ -188,8 +201,7 @@ class Signature(json_util.JSONObjectWithFields): key = self.combined.find_key() if key is None else key return self.combined.alg.verify( key=key.key, sig=self.signature, - msg=(b64.b64encode(self.protected) + '.' + - b64.b64encode(payload))) + msg=self._msg(self.protected, payload)) @classmethod def sign(cls, payload, key, alg, include_jwk=True, @@ -220,8 +232,7 @@ class Signature(json_util.JSONObjectWithFields): protected = '' header = cls.header_cls(**header_params) # pylint: disable=star-args - signature = alg.sign(key.key, b64.b64encode(protected) - + '.' + b64.b64encode(payload)) + signature = alg.sign(key.key, cls._msg(protected, payload)) return cls(protected=protected, header=header, signature=signature) @@ -244,7 +255,7 @@ class JWS(json_util.JSONObjectWithFields): """JSON Web Signature. :ivar str payload: JWS Payload. - :ivar str signaturea: JWS Signatures. + :ivar str signature: JWS Signatures. """ __slots__ = ('payload', 'signatures') @@ -272,33 +283,45 @@ class JWS(json_util.JSONObjectWithFields): return self.signatures[0] def to_compact(self): - """Compact serialization.""" + """Compact serialization. + + :rtype: bytes + + """ assert len(self.signatures) == 1 assert 'alg' not in self.signature.header.not_omitted() # ... it must be in protected - return '{0}.{1}.{2}'.format( - b64.b64encode(self.signature.protected), - b64.b64encode(self.payload), + return ( + b64.b64encode(self.signature.protected.encode('utf-8')) + + b'.' + + b64.b64encode(self.payload) + + b'.' + b64.b64encode(self.signature.signature)) @classmethod def from_compact(cls, compact): - """Compact deserialization.""" + """Compact deserialization. + + :param bytes compact: + + """ try: - protected, payload, signature = compact.split('.') + protected, payload, signature = compact.split(b'.') except ValueError: raise errors.DeserializationError( 'Compact JWS serialization should comprise of exactly' ' 3 dot-separated components') - sig = cls.signature_cls(protected=json_util.decode_b64jose(protected), - signature=json_util.decode_b64jose(signature)) - return cls(payload=json_util.decode_b64jose(payload), signatures=(sig,)) + + sig = cls.signature_cls( + protected=b64.b64decode(protected).decode('utf-8'), + signature=b64.b64decode(signature)) + return cls(payload=b64.b64decode(payload), signatures=(sig,)) def to_partial_json(self, flat=True): # pylint: disable=arguments-differ assert self.signatures - payload = b64.b64encode(self.payload) + payload = json_util.encode_b64jose(self.payload) if flat and len(self.signatures) == 1: ret = self.signatures[0].to_partial_json() @@ -329,34 +352,36 @@ class CLI(object): def sign(cls, args): """Sign.""" key = args.alg.kty.load(args.key.read()) + args.key.close() if args.protect is None: args.protect = [] if args.compact: args.protect.append('alg') - sig = JWS.sign(payload=sys.stdin.read(), key=key, alg=args.alg, + sig = JWS.sign(payload=sys.stdin.read().encode(), key=key, alg=args.alg, protect=set(args.protect)) if args.compact: - print sig.to_compact() + six.print_(sig.to_compact().decode('utf-8')) else: # JSON - print sig.json_dumps_pretty() + six.print_(sig.json_dumps_pretty()) @classmethod def verify(cls, args): """Verify.""" if args.compact: - sig = JWS.from_compact(sys.stdin.read()) + sig = JWS.from_compact(sys.stdin.read().encode()) else: # JSON try: sig = JWS.json_loads(sys.stdin.read()) except errors.Error as error: - print error + six.print_(error) return -1 if args.key is not None: assert args.kty is not None key = args.kty.load(args.key.read()).public_key() + args.key.close() else: key = None @@ -387,7 +412,7 @@ class CLI(object): parser_sign = subparsers.add_parser('sign') parser_sign.set_defaults(func=cls.sign) parser_sign.add_argument( - '-k', '--key', type=argparse.FileType(), required=True) + '-k', '--key', type=argparse.FileType('rb'), required=True) parser_sign.add_argument( '-a', '--alg', type=cls._alg_type, default=jwa.RS256) parser_sign.add_argument( @@ -396,7 +421,7 @@ class CLI(object): parser_verify = subparsers.add_parser('verify') parser_verify.set_defaults(func=cls.verify) parser_verify.add_argument( - '-k', '--key', type=argparse.FileType(), required=False) + '-k', '--key', type=argparse.FileType('rb'), required=False) parser_verify.add_argument( '--kty', type=cls._kty_type, required=False) diff --git a/acme/acme/jose/jws_test.py b/acme/acme/jose/jws_test.py index 7a3e8cb83..69341f228 100644 --- a/acme/acme/jose/jws_test.py +++ b/acme/acme/jose/jws_test.py @@ -7,8 +7,8 @@ import OpenSSL from acme import test_util -from acme.jose import b64 from acme.jose import errors +from acme.jose import json_util from acme.jose import jwa from acme.jose import jwk @@ -73,7 +73,7 @@ class HeaderTest(unittest.TestCase): self.assertEqual(jobj, {'x5c': [cert_b64, cert_b64]}) self.assertEqual(header, Header.from_json(jobj)) jobj['x5c'][0] = base64.b64encode( - 'xxx' + OpenSSL.crypto.dump_certificate( + b'xxx' + OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_ASN1, CERT)) self.assertRaises(errors.DeserializationError, Header.from_json, jobj) @@ -90,7 +90,7 @@ class SignatureTest(unittest.TestCase): from acme.jose.jws import Header from acme.jose.jws import Signature self.assertEqual( - Signature(signature='foo', header=Header(alg=jwa.RS256)), + Signature(signature=b'foo', header=Header(alg=jwa.RS256)), Signature.from_json( {'signature': 'Zm9v', 'header': {'alg': 'RS256'}})) @@ -109,12 +109,12 @@ class JWSTest(unittest.TestCase): from acme.jose.jws import JWS self.unprotected = JWS.sign( - payload='foo', key=self.privkey, alg=jwa.RS256) + payload=b'foo', key=self.privkey, alg=jwa.RS256) self.protected = JWS.sign( - payload='foo', key=self.privkey, alg=jwa.RS256, + payload=b'foo', key=self.privkey, alg=jwa.RS256, protect=frozenset(['jwk', 'alg'])) self.mixed = JWS.sign( - payload='foo', key=self.privkey, alg=jwa.RS256, + payload=b'foo', key=self.privkey, alg=jwa.RS256, protect=frozenset(['alg'])) def test_pubkey_jwk(self): @@ -134,8 +134,8 @@ class JWSTest(unittest.TestCase): def test_compact_lost_unprotected(self): compact = self.mixed.to_compact() self.assertEqual( - 'eyJhbGciOiAiUlMyNTYifQ.Zm9v.OHdxFVj73l5LpxbFp1AmYX4yJM0Pyb' - '_893n1zQjpim_eLS5J1F61lkvrCrCDErTEJnBGOGesJ72M7b6Ve1cAJA', + b'eyJhbGciOiAiUlMyNTYifQ.Zm9v.OHdxFVj73l5LpxbFp1AmYX4yJM0Pyb' + b'_893n1zQjpim_eLS5J1F61lkvrCrCDErTEJnBGOGesJ72M7b6Ve1cAJA', compact) from acme.jose.jws import JWS @@ -147,7 +147,7 @@ class JWSTest(unittest.TestCase): def test_from_compact_missing_components(self): from acme.jose.jws import JWS - self.assertRaises(errors.DeserializationError, JWS.from_compact, '.') + self.assertRaises(errors.DeserializationError, JWS.from_compact, b'.') def test_json_omitempty(self): protected_jobj = self.protected.to_partial_json(flat=True) @@ -164,10 +164,12 @@ class JWSTest(unittest.TestCase): def test_json_flat(self): jobj_to = { - 'signature': b64.b64encode(self.mixed.signature.signature), - 'payload': b64.b64encode('foo'), + 'signature': json_util.encode_b64jose( + self.mixed.signature.signature), + 'payload': json_util.encode_b64jose(b'foo'), 'header': self.mixed.signature.header, - 'protected': b64.b64encode(self.mixed.signature.protected), + 'protected': json_util.encode_b64jose( + self.mixed.signature.protected.encode('utf-8')), } jobj_from = jobj_to.copy() jobj_from['header'] = jobj_from['header'].to_json() @@ -179,7 +181,7 @@ class JWSTest(unittest.TestCase): def test_json_not_flat(self): jobj_to = { 'signatures': (self.mixed.signature,), - 'payload': b64.b64encode('foo'), + 'payload': json_util.encode_b64jose(b'foo'), } jobj_from = jobj_to.copy() jobj_from['signatures'] = [jobj_to['signatures'][0].to_json()] diff --git a/acme/acme/jose/util.py b/acme/acme/jose/util.py index eebbe7468..fd58a9e97 100644 --- a/acme/acme/jose/util.py +++ b/acme/acme/jose/util.py @@ -3,6 +3,7 @@ import collections from cryptography.hazmat.primitives.asymmetric import rsa import OpenSSL +import six class abstractclassmethod(classmethod): @@ -156,7 +157,8 @@ class ImmutableMap(collections.Mapping, collections.Hashable): def __repr__(self): return '{0}({1})'.format(self.__class__.__name__, ', '.join( - '{0}={1!r}'.format(key, value) for key, value in self.iteritems())) + '{0}={1!r}'.format(key, value) + for key, value in six.iteritems(self))) class frozendict(collections.Mapping, collections.Hashable): @@ -174,7 +176,7 @@ class frozendict(collections.Mapping, collections.Hashable): # TODO: support generators/iterators object.__setattr__(self, '_items', items) - object.__setattr__(self, '_keys', tuple(sorted(items.iterkeys()))) + object.__setattr__(self, '_keys', tuple(sorted(six.iterkeys(items)))) def __getitem__(self, key): return self._items[key] @@ -185,8 +187,11 @@ class frozendict(collections.Mapping, collections.Hashable): def __len__(self): return len(self._items) + def _sorted_items(self): + return tuple((key, self[key]) for key in self._keys) + def __hash__(self): - return hash(tuple((key, value) for key, value in self.items())) + return hash(self._sorted_items()) def __getattr__(self, name): try: @@ -198,5 +203,5 @@ class frozendict(collections.Mapping, collections.Hashable): raise AttributeError("can't set attribute") def __repr__(self): - return 'frozendict({0})'.format(', '.join( - '{0}={1!r}'.format(key, value) for key, value in self.iteritems())) + return 'frozendict({0})'.format(', '.join('{0}={1!r}'.format( + key, value) for key, value in self._sorted_items())) diff --git a/acme/acme/jose/util_test.py b/acme/acme/jose/util_test.py index 1bde9ebd9..4cdd9127f 100644 --- a/acme/acme/jose/util_test.py +++ b/acme/acme/jose/util_test.py @@ -2,6 +2,8 @@ import functools import unittest +import six + from acme import test_util @@ -168,13 +170,13 @@ class frozendictTest(unittest.TestCase): # pylint: disable=invalid-name def test_init_other_raises_type_error(self): from acme.jose.util import frozendict # specifically fail for generators... - self.assertRaises(TypeError, frozendict, {'a': 'b'}.iteritems()) + self.assertRaises(TypeError, frozendict, six.iteritems({'a': 'b'})) def test_len(self): self.assertEqual(2, len(self.fdict)) def test_hash(self): - self.assertEqual(1278944519403861804, hash(self.fdict)) + self.assertTrue(isinstance(hash(self.fdict), int)) def test_getattr_proxy(self): self.assertEqual(1, self.fdict.x) diff --git a/acme/setup.py b/acme/setup.py index d83131d2a..481a35eb6 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -14,6 +14,7 @@ install_requires = [ 'PyOpenSSL', 'pytz', 'requests', + 'six', 'werkzeug', ] From a876a664df358c04d1ae5d7eb67b5c55af53c5bc Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sat, 11 Jul 2015 16:11:09 +0000 Subject: [PATCH 17/30] Add py3 tox tests for acme.jose --- .dockerignore | 4 +++- .gitignore | 2 ++ acme/setup.py | 10 ++++++++++ tox.ini | 8 +++++++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 0bdb9e62d..5ee05ea89 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,8 @@ # test docker on their git working directories. .git -tox.cover +tox.venv +tox.venv3 venv +venv3 docs diff --git a/.gitignore b/.gitignore index 2441f1a74..990564fca 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ build/ dist/ /venv/ +/venv3/ +/tox.venv/ /tox.venv/ letsencrypt.log diff --git a/acme/setup.py b/acme/setup.py index 481a35eb6..8ce3399cc 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -18,13 +18,23 @@ install_requires = [ 'werkzeug', ] +testing_extras = [ + 'nose', + 'tox', +] + + setup( name='acme', packages=find_packages(), install_requires=install_requires, + extras_require={ + 'testing': testing_extras, + }, entry_points={ 'console_scripts': [ 'jws = acme.jose.jws:CLI.run', ], }, + test_suite='acme', ) diff --git a/tox.ini b/tox.ini index dc6fb567a..d1b9253ed 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ # acme and letsencrypt are not yet on pypi, so when Tox invokes # "install *.zip", it will not find deps skipsdist = true -envlist = py26,py27,cover,lint +envlist = py26,py27,py34,cover,lint [testenv] # share one venv across testenvs, instead of multiple @@ -26,6 +26,12 @@ setenv = PYTHONHASHSEED = 0 # https://testrun.org/tox/latest/example/basic.html#special-handling-of-pythonhas +[testenv:py34] +envdir = {toxinidir}/tox.venv3 +commands = + pip install -e acme[testing] + nosetests acme/acme/jose + [testenv:cover] basepython = python2.7 commands = From c0ba26776a34893ce6e115a330a13fcc1ab1bad5 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 11:26:05 +0000 Subject: [PATCH 18/30] Support for py3.3+ in acme --- .pylintrc | 4 +- acme/acme/challenges.py | 91 ++++++++++++++++++++++++------------ acme/acme/challenges_test.py | 46 +++++++++--------- acme/acme/client.py | 28 ++++++----- acme/acme/client_test.py | 39 ++++++++-------- acme/acme/interfaces.py | 2 +- acme/acme/jws.py | 25 ++-------- acme/acme/jws_test.py | 24 +++++----- acme/acme/messages.py | 44 +++++++++++------ acme/acme/other.py | 27 +++++------ acme/acme/other_test.py | 14 +++--- 11 files changed, 191 insertions(+), 153 deletions(-) diff --git a/.pylintrc b/.pylintrc index 88cb563fa..d954b2658 100644 --- a/.pylintrc +++ b/.pylintrc @@ -240,7 +240,9 @@ ignore-mixin-members=yes # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis -ignored-modules=pkg_resources,confargparse,argparse +ignored-modules=pkg_resources,confargparse,argparse,six.moves,six.moves.urllib +# import errors ignored only in 1.4.4 +# https://bitbucket.org/logilab/pylint/commits/cd000904c9e2 # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 8024728fa..a37095532 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -35,12 +35,7 @@ class DVChallenge(Challenge): # pylint: disable=abstract-method class ChallengeResponse(interfaces.ClientRequestableResource, jose.TypedJSONObjectWithFields): # _fields_to_partial_json | pylint: disable=abstract-method - """ACME challenge response. - - :ivar str mitm_resource: ACME resource identifier used in client - HTTPS requests in order to protect against MITM. - - """ + """ACME challenge response.""" TYPES = {} resource_type = 'challenge' @@ -56,14 +51,23 @@ class ChallengeResponse(interfaces.ClientRequestableResource, @Challenge.register class SimpleHTTP(DVChallenge): - """ACME "simpleHttp" challenge.""" + """ACME "simpleHttp" challenge. + + :ivar unicode token: + + """ typ = "simpleHttp" token = jose.Field("token") @ChallengeResponse.register class SimpleHTTPResponse(ChallengeResponse): - """ACME "simpleHttp" challenge response.""" + """ACME "simpleHttp" challenge response. + + :ivar unicode path: + :ivar unicode tls: + + """ typ = "simpleHttp" path = jose.Field("path") tls = jose.Field("tls", default=True, omitempty=True) @@ -107,7 +111,7 @@ class SimpleHTTPResponse(ChallengeResponse): Forms an URI to the HTTPS server provisioned resource (containing :attr:`~SimpleHTTP.token`). - :param str domain: Domain name being verified. + :param unicode domain: Domain name being verified. """ return self._URI_TEMPLATE.format( @@ -121,7 +125,7 @@ class SimpleHTTPResponse(ChallengeResponse): ``requests.get`` is called with ``verify=False``. :param .SimpleHTTP chall: Corresponding challenge. - :param str domain: Domain name being verified. + :param unicode domain: Domain name being verified. :param int port: Port used in the validation. :returns: ``True`` iff validation is successful, ``False`` @@ -163,13 +167,13 @@ class SimpleHTTPResponse(ChallengeResponse): class DVSNI(DVChallenge): """ACME "dvsni" challenge. - :ivar str r: Random data, **not** base64-encoded. - :ivar str nonce: Random data, **not** hex-encoded. + :ivar bytes r: Random data, **not** base64-encoded. + :ivar bytes nonce: Random data, **not** hex-encoded. """ typ = "dvsni" - DOMAIN_SUFFIX = ".acme.invalid" + DOMAIN_SUFFIX = b".acme.invalid" """Domain name suffix.""" R_SIZE = 32 @@ -181,15 +185,19 @@ class DVSNI(DVChallenge): PORT = 443 """Port to perform DVSNI challenge.""" - r = jose.Field("r", encoder=jose.b64encode, # pylint: disable=invalid-name + r = jose.Field("r", encoder=jose.encode_b64jose, # pylint: disable=invalid-name decoder=functools.partial(jose.decode_b64jose, size=R_SIZE)) - nonce = jose.Field("nonce", encoder=binascii.hexlify, + nonce = jose.Field("nonce", encoder=jose.encode_hex16, decoder=functools.partial(functools.partial( jose.decode_hex16, size=NONCE_SIZE))) @property def nonce_domain(self): - """Domain name used in SNI.""" + """Domain name used in SNI. + + :rtype: bytes + + """ return binascii.hexlify(self.nonce) + self.DOMAIN_SUFFIX @@ -197,7 +205,7 @@ class DVSNI(DVChallenge): class DVSNIResponse(ChallengeResponse): """ACME "dvsni" challenge response. - :param str s: Random data, **not** base64-encoded. + :param bytes s: Random data, **not** base64-encoded. """ typ = "dvsni" @@ -208,7 +216,7 @@ class DVSNIResponse(ChallengeResponse): S_SIZE = 32 """Required size of the :attr:`s` in bytes.""" - s = jose.Field("s", encoder=jose.b64encode, # pylint: disable=invalid-name + s = jose.Field("s", encoder=jose.encode_b64jose, # pylint: disable=invalid-name decoder=functools.partial(jose.decode_b64jose, size=S_SIZE)) def __init__(self, s=None, *args, **kwargs): @@ -221,11 +229,13 @@ class DVSNIResponse(ChallengeResponse): :param challenge: Corresponding challenge. :type challenge: :class:`DVSNI` + :rtype: bytes + """ z = hashlib.new("sha256") # pylint: disable=invalid-name z.update(chall.r) z.update(self.s) - return z.hexdigest() + return z.hexdigest().encode() def z_domain(self, chall): """Domain name for certificate subjectAltName.""" @@ -233,7 +243,13 @@ class DVSNIResponse(ChallengeResponse): @Challenge.register class RecoveryContact(ContinuityChallenge): - """ACME "recoveryContact" challenge.""" + """ACME "recoveryContact" challenge. + + :ivar unicode activation_url: + :ivar unicode success_url: + :ivar unicode contact: + + """ typ = "recoveryContact" activation_url = jose.Field("activationURL", omitempty=True) @@ -243,7 +259,11 @@ class RecoveryContact(ContinuityChallenge): @ChallengeResponse.register class RecoveryContactResponse(ChallengeResponse): - """ACME "recoveryContact" challenge response.""" + """ACME "recoveryContact" challenge response. + + :ivar unicode token: + + """ typ = "recoveryContact" token = jose.Field("token", omitempty=True) @@ -256,7 +276,11 @@ class RecoveryToken(ContinuityChallenge): @ChallengeResponse.register class RecoveryTokenResponse(ChallengeResponse): - """ACME "recoveryToken" challenge response.""" + """ACME "recoveryToken" challenge response. + + :ivar unicode token: + + """ typ = "recoveryToken" token = jose.Field("token", omitempty=True) @@ -265,7 +289,8 @@ class RecoveryTokenResponse(ChallengeResponse): class ProofOfPossession(ContinuityChallenge): """ACME "proofOfPossession" challenge. - :ivar str nonce: Random data, **not** base64-encoded. + :ivar .JWAAlgorithm alg: + :ivar bytes nonce: Random data, **not** base64-encoded. :ivar hints: Various clues for the client (:class:`Hints`). """ @@ -277,8 +302,12 @@ class ProofOfPossession(ContinuityChallenge): """Hints for "proofOfPossession" challenge. :ivar jwk: JSON Web Key (:class:`acme.jose.JWK`) - :ivar list certs: List of :class:`acme.jose.ComparableX509` + :ivar tuple cert_fingerprints: `tuple` of `unicode` + :ivar tuple certs: Sequence of :class:`acme.jose.ComparableX509` certificates. + :ivar tuple subject_key_identifiers: `tuple` of `unicode` + :ivar tuple issuers: `tuple` of `unicode` + :ivar tuple authorized_for: `tuple` of `unicode` """ jwk = jose.Field("jwk", decoder=jose.JWK.from_json) @@ -301,7 +330,7 @@ class ProofOfPossession(ContinuityChallenge): alg = jose.Field("alg", decoder=jose.JWASignature.from_json) nonce = jose.Field( - "nonce", encoder=jose.b64encode, decoder=functools.partial( + "nonce", encoder=jose.encode_b64jose, decoder=functools.partial( jose.decode_b64jose, size=NONCE_SIZE)) hints = jose.Field("hints", decoder=Hints.from_json) @@ -310,8 +339,8 @@ class ProofOfPossession(ContinuityChallenge): class ProofOfPossessionResponse(ChallengeResponse): """ACME "proofOfPossession" challenge response. - :ivar str nonce: Random data, **not** base64-encoded. - :ivar signature: :class:`~acme.other.Signature` of this message. + :ivar bytes nonce: Random data, **not** base64-encoded. + :ivar acme.other.Signature signature: Sugnature of this message. """ typ = "proofOfPossession" @@ -319,7 +348,7 @@ class ProofOfPossessionResponse(ChallengeResponse): NONCE_SIZE = ProofOfPossession.NONCE_SIZE nonce = jose.Field( - "nonce", encoder=jose.b64encode, decoder=functools.partial( + "nonce", encoder=jose.encode_b64jose, decoder=functools.partial( jose.decode_b64jose, size=NONCE_SIZE)) signature = jose.Field("signature", decoder=other.Signature.from_json) @@ -331,7 +360,11 @@ class ProofOfPossessionResponse(ChallengeResponse): @Challenge.register class DNS(DVChallenge): - """ACME "dns" challenge.""" + """ACME "dns" challenge. + + :ivar unicode token: + + """ typ = "dns" token = jose.Field("token") diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index a1214c2f9..3543553c5 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -4,7 +4,8 @@ import unittest import mock import OpenSSL import requests -import urlparse + +from six.moves.urllib import parse as urllib_parse # pylint: disable=import-error from acme import jose from acme import other @@ -136,7 +137,7 @@ class SimpleHTTPResponseTest(unittest.TestCase): @mock.patch("acme.challenges.requests.get") def test_simple_verify_port(self, mock_get): self.resp_http.simple_verify(self.chall, "local", 4430) - self.assertEqual("local:4430", urlparse.urlparse( + self.assertEqual("local:4430", urllib_parse.urlparse( mock_get.mock_calls[0][1][0]).netloc) @@ -145,9 +146,9 @@ class DVSNITest(unittest.TestCase): def setUp(self): from acme.challenges import DVSNI self.msg = DVSNI( - r="O*\xb4-\xad\xec\x95>\xed\xa9\r0\x94\xe8\x97\x9c&6" - "\xbf'\xb3\xed\x9a9nX\x0f'\\m\xe7\x12", - nonce='\xa8-_\xf8\xeft\r\x12\x88\x1fm<"w\xab.') + r=b"O*\xb4-\xad\xec\x95>\xed\xa9\r0\x94\xe8\x97\x9c&6" + b"\xbf'\xb3\xed\x9a9nX\x0f'\\m\xe7\x12", + nonce=b'\xa8-_\xf8\xeft\r\x12\x88\x1fm<"w\xab.') self.jmsg = { 'type': 'dvsni', 'r': 'Tyq0La3slT7tqQ0wlOiXnCY2vyez7Zo5blgPJ1xt5xI', @@ -155,7 +156,7 @@ class DVSNITest(unittest.TestCase): } def test_nonce_domain(self): - self.assertEqual('a82d5ff8ef740d12881f6d3c2277ab2e.acme.invalid', + self.assertEqual(b'a82d5ff8ef740d12881f6d3c2277ab2e.acme.invalid', self.msg.nonce_domain) def test_to_partial_json(self): @@ -187,8 +188,8 @@ class DVSNIResponseTest(unittest.TestCase): def setUp(self): from acme.challenges import DVSNIResponse self.msg = DVSNIResponse( - s='\xf5\xd6\xe3\xb2]\xe0L\x0bN\x9cKJ\x14I\xa1K\xa3#\xf9\xa8' - '\xcd\x8c7\x0e\x99\x19)\xdc\xb7\xf3\x9bw') + s=b'\xf5\xd6\xe3\xb2]\xe0L\x0bN\x9cKJ\x14I\xa1K\xa3#\xf9\xa8' + b'\xcd\x8c7\x0e\x99\x19)\xdc\xb7\xf3\x9bw') self.jmsg = { 'type': 'dvsni', 's': '9dbjsl3gTAtOnEtKFEmhS6Mj-ajNjDcOmRkp3Lfzm3c', @@ -197,15 +198,14 @@ class DVSNIResponseTest(unittest.TestCase): def test_z_and_domain(self): from acme.challenges import DVSNI challenge = DVSNI( - r="O*\xb4-\xad\xec\x95>\xed\xa9\r0\x94\xe8\x97\x9c&6" - "\xbf'\xb3\xed\x9a9nX\x0f'\\m\xe7\x12", - nonce=long('439736375371401115242521957580409149254868992063' - '44333654741504362774620418661L')) + r=b"O*\xb4-\xad\xec\x95>\xed\xa9\r0\x94\xe8\x97\x9c&6" + b"\xbf'\xb3\xed\x9a9nX\x0f'\\m\xe7\x12", + nonce=int('439736375371401115242521957580409149254868992063' + '44333654741504362774620418661')) # pylint: disable=invalid-name - z = '38e612b0397cc2624a07d351d7ef50e46134c0213d9ed52f7d7c611acaeed41b' + z = b'38e612b0397cc2624a07d351d7ef50e46134c0213d9ed52f7d7c611acaeed41b' self.assertEqual(z, self.msg.z(challenge)) - self.assertEqual( - '{0}.acme.invalid'.format(z), self.msg.z_domain(challenge)) + self.assertEqual(z + b'.acme.invalid', self.msg.z_domain(challenge)) def test_to_partial_json(self): self.assertEqual(self.jmsg, self.msg.to_partial_json()) @@ -362,7 +362,7 @@ class ProofOfPossessionHintsTest(unittest.TestCase): self.jmsg_to = { 'jwk': jwk, 'certFingerprints': cert_fingerprints, - 'certs': (jose.b64encode(OpenSSL.crypto.dump_certificate( + 'certs': (jose.encode_b64jose(OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_ASN1, CERT)),), 'subjectKeyIdentifiers': subject_key_identifiers, 'serialNumbers': serial_numbers, @@ -413,7 +413,7 @@ class ProofOfPossessionTest(unittest.TestCase): issuers=(), authorized_for=()) self.msg = ProofOfPossession( alg=jose.RS256, hints=hints, - nonce='xD\xf9\xb9\xdbU\xed\xaa\x17\xf1y|\x81\x88\x99 ') + nonce=b'xD\xf9\xb9\xdbU\xed\xaa\x17\xf1y|\x81\x88\x99 ') self.jmsg_to = { 'type': 'proofOfPossession', @@ -449,16 +449,16 @@ class ProofOfPossessionResponseTest(unittest.TestCase): # mistake here... signature = other.Signature( alg=jose.RS256, jwk=jose.JWKRSA(key=KEY.public_key()), - sig='\xa7\xc1\xe7\xe82o\xbc\xcd\xd0\x1e\x010#Z|\xaf\x15\x83' - '\x94\x8f#\x9b\nQo(\x80\x15,\x08\xfcz\x1d\xfd\xfd.\xaap' - '\xfa\x06\xd1\xa2f\x8d8X2>%d\xbd%\xe1T\xdd\xaa0\x18\xde' - '\x99\x08\xf0\x0e{', - nonce='\x99\xc7Q\xb3f2\xbc\xdci\xfe\xd6\x98k\xc67\xdf', + sig=b'\xa7\xc1\xe7\xe82o\xbc\xcd\xd0\x1e\x010#Z|\xaf\x15\x83' + b'\x94\x8f#\x9b\nQo(\x80\x15,\x08\xfcz\x1d\xfd\xfd.\xaap' + b'\xfa\x06\xd1\xa2f\x8d8X2>%d\xbd%\xe1T\xdd\xaa0\x18\xde' + b'\x99\x08\xf0\x0e{', + nonce=b'\x99\xc7Q\xb3f2\xbc\xdci\xfe\xd6\x98k\xc67\xdf', ) from acme.challenges import ProofOfPossessionResponse self.msg = ProofOfPossessionResponse( - nonce='xD\xf9\xb9\xdbU\xed\xaa\x17\xf1y|\x81\x88\x99 ', + nonce=b'xD\xf9\xb9\xdbU\xed\xaa\x17\xf1y|\x81\x88\x99 ', signature=signature) self.jmsg_to = { diff --git a/acme/acme/client.py b/acme/acme/client.py index 33e4e4f7f..113042907 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -1,13 +1,15 @@ """ACME client API.""" import datetime import heapq -import httplib import json import logging import time +from six.moves import http_client # pylint: disable=import-error + import OpenSSL import requests +import six import werkzeug from acme import errors @@ -19,7 +21,8 @@ from acme import messages logger = logging.getLogger(__name__) # https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning -requests.packages.urllib3.contrib.pyopenssl.inject_into_urllib3() +if six.PY2: + requests.packages.urllib3.contrib.pyopenssl.inject_into_urllib3() class Client(object): # pylint: disable=too-many-instance-attributes @@ -80,7 +83,8 @@ class Client(object): # pylint: disable=too-many-instance-attributes new_reg = messages.Registration() if new_reg is None else new_reg response = self.net.post(self.new_reg_uri, new_reg) - assert response.status_code == httplib.CREATED # TODO: handle errors + # TODO: handle errors + assert response.status_code == http_client.CREATED # "Instance of 'Field' has no key/contact member" bug: # pylint: disable=no-member @@ -162,7 +166,8 @@ class Client(object): # pylint: disable=too-many-instance-attributes """ new_authz = messages.Authorization(identifier=identifier) response = self.net.post(new_authzr_uri, new_authz) - assert response.status_code == httplib.CREATED # TODO: handle errors + # TODO: handle errors + assert response.status_code == http_client.CREATED return self._authzr_from_response(response, identifier) def request_domain_challenges(self, domain, new_authz_uri): @@ -424,7 +429,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes """ response = self.net.post(messages.Revocation.url(self.new_reg_uri), messages.Revocation(certificate=cert)) - if response.status_code != httplib.OK: + if response.status_code != http_client.OK: raise errors.ClientError( 'Successful revocation must return HTTP OK status') @@ -447,12 +452,13 @@ class ClientNetwork(object): .. todo:: Implement ``acmePath``. :param .ClientRequestableResource obj: + :param bytes nonce: :rtype: `.JWS` """ jobj = obj.to_json() jobj['resource'] = obj.resource_type - dumps = json.dumps(jobj) + dumps = json.dumps(jobj).encode() logger.debug('Serialized JSON: %s', dumps) return jws.JWS.sign( payload=dumps, key=self.key, alg=self.alg, nonce=nonce).json_dumps() @@ -555,12 +561,12 @@ class ClientNetwork(object): def _add_nonce(self, response): if self.REPLAY_NONCE_HEADER in response.headers: nonce = response.headers[self.REPLAY_NONCE_HEADER] - error = jws.Header.validate_nonce(nonce) - if error is None: - logger.debug('Storing nonce: %r', nonce) - self._nonces.add(nonce) - else: + try: + decoded_nonce = jws.Header._fields['nonce'].decode(nonce) + except jose.DeserializationError as error: raise errors.BadNonce(nonce, error) + logger.debug('Storing nonce: %r', decoded_nonce) + self._nonces.add(decoded_nonce) else: raise errors.MissingNonce(response) diff --git a/acme/acme/client_test.py b/acme/acme/client_test.py index 3e3380a16..8e731febc 100644 --- a/acme/acme/client_test.py +++ b/acme/acme/client_test.py @@ -1,9 +1,10 @@ """Tests for acme.client.""" import datetime -import httplib import json import unittest +from six.moves import http_client # pylint: disable=import-error + import mock import requests @@ -27,7 +28,7 @@ class ClientTest(unittest.TestCase): def setUp(self): self.response = mock.MagicMock( - ok=True, status_code=httplib.OK, headers={}, links={}) + ok=True, status_code=http_client.OK, headers={}, links={}) self.net = mock.MagicMock() self.net.post.return_value = self.response self.net.get.return_value = self.response @@ -73,7 +74,7 @@ class ClientTest(unittest.TestCase): def test_register(self): # "Instance of 'Field' has no to_json/update member" bug: # pylint: disable=no-member - self.response.status_code = httplib.CREATED + self.response.status_code = http_client.CREATED self.response.json.return_value = self.regr.body.to_json() self.response.headers['Location'] = self.regr.uri self.response.links.update({ @@ -91,7 +92,7 @@ class ClientTest(unittest.TestCase): errors.UnexpectedUpdate, self.client.register, self.regr.body) def test_register_missing_next(self): - self.response.status_code = httplib.CREATED + self.response.status_code = http_client.CREATED self.assertRaises( errors.ClientError, self.client.register, self.regr.body) @@ -115,7 +116,7 @@ class ClientTest(unittest.TestCase): self.assertEqual(self.regr.terms_of_service, regr.body.agreement) def test_request_challenges(self): - self.response.status_code = httplib.CREATED + self.response.status_code = http_client.CREATED self.response.headers['Location'] = self.authzr.uri self.response.json.return_value = self.authz.to_json() self.response.links = { @@ -133,7 +134,7 @@ class ClientTest(unittest.TestCase): self.identifier, self.authzr.uri) def test_request_challenges_missing_next(self): - self.response.status_code = httplib.CREATED + self.response.status_code = http_client.CREATED self.assertRaises( errors.ClientError, self.client.request_challenges, self.identifier, self.regr) @@ -345,7 +346,7 @@ class ClientTest(unittest.TestCase): self.client.new_reg_uri), mock.ANY) def test_revoke_bad_status_raises_error(self): - self.response.status_code = httplib.METHOD_NOT_ALLOWED + self.response.status_code = http_client.METHOD_NOT_ALLOWED self.assertRaises(errors.ClientError, self.client.revoke, self.certr) @@ -360,7 +361,7 @@ class ClientNetworkTest(unittest.TestCase): self.net = ClientNetwork( key=KEY, alg=jose.RS256, verify_ssl=self.verify_ssl) - self.response = mock.MagicMock(ok=True, status_code=httplib.OK) + self.response = mock.MagicMock(ok=True, status_code=http_client.OK) self.response.headers = {} self.response.links = {} @@ -380,12 +381,11 @@ class ClientNetworkTest(unittest.TestCase): pass # pragma: no cover # pylint: disable=protected-access jws_dump = self.net._wrap_in_jws( - MockClientRequestableResource('foo'), nonce='Tg') + MockClientRequestableResource('foo'), nonce=b'Tg') jws = acme_jws.JWS.json_loads(jws_dump) - self.assertEqual(json.loads(jws.payload), + self.assertEqual(json.loads(jws.payload.decode()), {'foo': 'foo', 'resource': 'mock'}) - self.assertEqual(jws.signature.combined.nonce, 'Tg') - # TODO: check that nonce is in protected header + self.assertEqual(jws.signature.combined.nonce, b'Tg') def test_check_response_not_ok_jobj_no_error(self): self.response.ok = False @@ -473,7 +473,7 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase): from acme.client import ClientNetwork self.net = ClientNetwork(key=None, alg=None) - self.response = mock.MagicMock(ok=True, status_code=httplib.OK) + self.response = mock.MagicMock(ok=True, status_code=http_client.OK) self.response.headers = {} self.response.links = {} self.checked_response = mock.MagicMock() @@ -481,13 +481,14 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase): self.wrapped_obj = mock.MagicMock() self.content_type = mock.sentinel.content_type - self.all_nonces = [jose.b64encode('Nonce'), jose.b64encode('Nonce2')] + self.all_nonces = [jose.b64encode(b'Nonce'), jose.b64encode(b'Nonce2')] self.available_nonces = self.all_nonces[:] def send_request(*args, **kwargs): # pylint: disable=unused-argument,missing-docstring if self.available_nonces: self.response.headers = { - self.net.REPLAY_NONCE_HEADER: self.available_nonces.pop()} + self.net.REPLAY_NONCE_HEADER: + self.available_nonces.pop().decode()} else: self.response.headers = {} return self.response @@ -519,21 +520,21 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase): self.assertEqual(self.checked_response, self.net.post( 'uri', self.obj, content_type=self.content_type)) self.net._wrap_in_jws.assert_called_once_with( - self.obj, self.all_nonces.pop()) + self.obj, jose.b64decode(self.all_nonces.pop())) assert not self.available_nonces self.assertRaises(errors.MissingNonce, self.net.post, 'uri', self.obj, content_type=self.content_type) self.net._wrap_in_jws.assert_called_with( - self.obj, self.all_nonces.pop()) + self.obj, jose.b64decode(self.all_nonces.pop())) def test_post_wrong_initial_nonce(self): # HEAD - self.available_nonces = ['f', jose.b64encode('good')] + self.available_nonces = [b'f', jose.b64encode(b'good')] self.assertRaises(errors.BadNonce, self.net.post, 'uri', self.obj, content_type=self.content_type) def test_post_wrong_post_response_nonce(self): - self.available_nonces = [jose.b64encode('good'), 'f'] + self.available_nonces = [jose.b64encode(b'good'), b'f'] self.assertRaises(errors.BadNonce, self.net.post, 'uri', self.obj, content_type=self.content_type) diff --git a/acme/acme/interfaces.py b/acme/acme/interfaces.py index 9899b1093..39078f463 100644 --- a/acme/acme/interfaces.py +++ b/acme/acme/interfaces.py @@ -5,7 +5,7 @@ from acme import jose class ClientRequestableResource(jose.JSONDeSerializable): """Resource that can be requested by client. - :ivar str resource_type: ACME resource identifier used in client + :ivar unicode resource_type: ACME resource identifier used in client HTTPS requests in order to protect against MITM. """ diff --git a/acme/acme/jws.py b/acme/acme/jws.py index a23015d93..54bc26d94 100644 --- a/acme/acme/jws.py +++ b/acme/acme/jws.py @@ -1,5 +1,4 @@ """ACME JOSE JWS.""" -from acme import errors from acme import jose @@ -9,29 +8,15 @@ class Header(jose.Header): .. todo:: Implement ``acmePath``. """ - nonce = jose.Field('nonce', omitempty=True) - - @classmethod - def validate_nonce(cls, nonce): - """Validate nonce. - - :returns: ``None`` if ``nonce`` is valid, decoding errors otherwise. - - """ - try: - jose.b64decode(nonce) - except (ValueError, TypeError) as error: - return error - else: - return None + nonce = jose.Field('nonce', omitempty=True, encoder=jose.encode_b64jose) @nonce.decoder def nonce(value): # pylint: disable=missing-docstring,no-self-argument - error = Header.validate_nonce(value) - if error is not None: + try: + return jose.decode_b64jose(value) + except jose.DeserializationError as error: # TODO: custom error - raise errors.Error("Invalid nonce: {0}".format(error)) - return value + raise jose.DeserializationError("Invalid nonce: {0}".format(error)) class Signature(jose.Signature): diff --git a/acme/acme/jws_test.py b/acme/acme/jws_test.py index 07361581c..e8f8e871a 100644 --- a/acme/acme/jws_test.py +++ b/acme/acme/jws_test.py @@ -1,7 +1,6 @@ """Tests for acme.jws.""" import unittest -from acme import errors from acme import jose from acme import test_util @@ -12,8 +11,8 @@ KEY = jose.JWKRSA.load(test_util.load_vector('rsa512_key.pem')) class HeaderTest(unittest.TestCase): """Tests for acme.jws.Header.""" - good_nonce = jose.b64encode('foo') - wrong_nonce = 'F' + good_nonce = jose.encode_b64jose(b'foo') + wrong_nonce = u'F' # Following just makes sure wrong_nonce is wrong try: jose.b64decode(wrong_nonce) @@ -22,17 +21,13 @@ class HeaderTest(unittest.TestCase): else: assert False # pragma: no cover - def test_validate_nonce(self): - from acme.jws import Header - self.assertTrue(Header.validate_nonce(self.good_nonce) is None) - self.assertFalse(Header.validate_nonce(self.wrong_nonce) is None) - def test_nonce_decoder(self): from acme.jws import Header nonce_field = Header._fields['nonce'] - self.assertRaises(errors.Error, nonce_field.decode, self.wrong_nonce) - self.assertEqual(self.good_nonce, nonce_field.decode(self.good_nonce)) + self.assertRaises( + jose.DeserializationError, nonce_field.decode, self.wrong_nonce) + self.assertEqual(b'foo', nonce_field.decode(self.good_nonce)) class JWSTest(unittest.TestCase): @@ -41,13 +36,16 @@ class JWSTest(unittest.TestCase): def setUp(self): self.privkey = KEY self.pubkey = self.privkey.public_key() - self.nonce = jose.b64encode('Nonce') + self.nonce = jose.b64encode(b'Nonce') def test_it(self): from acme.jws import JWS - jws = JWS.sign(payload='foo', key=self.privkey, + jws = JWS.sign(payload=b'foo', key=self.privkey, alg=jose.RS256, nonce=self.nonce) - JWS.from_json(jws.to_json()) + self.assertEqual(jws.signature.combined.nonce, self.nonce) + # TODO: check that nonce is in protected header + + self.assertEqual(jws, JWS.from_json(jws.to_json())) if __name__ == '__main__': diff --git a/acme/acme/messages.py b/acme/acme/messages.py index cccc34cd5..1ffdc48cc 100644 --- a/acme/acme/messages.py +++ b/acme/acme/messages.py @@ -1,5 +1,7 @@ """ACME protocol messages.""" -import urlparse +import collections + +from six.moves.urllib import parse as urllib_parse # pylint: disable=import-error from acme import challenges from acme import fields @@ -12,6 +14,10 @@ class Error(jose.JSONObjectWithFields, Exception): https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-00 + :ivar unicode typ: + :ivar unicode title: + :ivar unicode detail: + """ ERROR_TYPE_NAMESPACE = 'urn:acme:error:' ERROR_TYPE_DESCRIPTIONS = { @@ -49,7 +55,11 @@ class Error(jose.JSONObjectWithFields, Exception): @property def description(self): - """Hardcoded error description based on its type.""" + """Hardcoded error description based on its type. + + :rtype: unicode + + """ return self.ERROR_TYPE_DESCRIPTIONS[self.typ] def __str__(self): @@ -59,7 +69,7 @@ class Error(jose.JSONObjectWithFields, Exception): return str(self.detail) -class _Constant(jose.JSONDeSerializable): +class _Constant(jose.JSONDeSerializable, collections.Hashable): """ACME constant.""" __slots__ = ('name',) POSSIBLE_NAMES = NotImplemented @@ -84,6 +94,9 @@ class _Constant(jose.JSONDeSerializable): def __eq__(self, other): return isinstance(other, type(self)) and other.name == self.name + def __hash__(self): + return hash((self.__class__, self.name)) + def __ne__(self, other): return not self == other @@ -108,7 +121,8 @@ IDENTIFIER_FQDN = IdentifierType('dns') # IdentifierDNS in Boulder class Identifier(jose.JSONObjectWithFields): """ACME identifier. - :ivar acme.messages.IdentifierType typ: + :ivar IdentifierType typ: + :ivar unicode value: """ typ = jose.Field('type', decoder=IdentifierType.from_json) @@ -127,7 +141,7 @@ class Resource(jose.JSONObjectWithFields): class ResourceWithURI(Resource): """ACME Resource with URI. - :ivar str uri: Location of the resource. + :ivar unicode uri: Location of the resource. """ uri = jose.Field('uri') # no ChallengeResource.uri @@ -141,7 +155,10 @@ class Registration(interfaces.ClientRequestableResource, ResourceBody): """Registration Resource Body. :ivar acme.jose.jwk.JWK key: Public key. - :ivar tuple contact: Contact information following ACME spec + :ivar tuple contact: Contact information following ACME spec, + `tuple` of `unicode`. + :ivar unicode recovery_token: + :ivar unicode agreement: """ resource_type = 'new-reg' @@ -188,8 +205,8 @@ class RegistrationResource(interfaces.ClientRequestableResource, """Registration Resource. :ivar acme.messages.Registration body: - :ivar str new_authzr_uri: URI found in the 'next' ``Link`` header - :ivar str terms_of_service: URL for the CA TOS. + :ivar unicode new_authzr_uri: URI found in the 'next' ``Link`` header + :ivar unicode terms_of_service: URL for the CA TOS. """ resource_type = 'reg' @@ -212,6 +229,7 @@ class ChallengeBody(ResourceBody): call ``challb.x`` to get ``challb.chall.x`` contents. :ivar acme.messages.Status status: :ivar datetime.datetime validated: + :ivar Error error: """ __slots__ = ('chall',) @@ -241,7 +259,7 @@ class ChallengeResource(Resource): """Challenge Resource. :ivar acme.messages.ChallengeBody body: - :ivar str authzr_uri: URI found in the 'up' ``Link`` header. + :ivar unicode authzr_uri: URI found in the 'up' ``Link`` header. """ body = jose.Field('body', decoder=ChallengeBody.from_json) @@ -261,8 +279,6 @@ class Authorization(interfaces.ClientRequestableResource, ResourceBody): :ivar list challenges: `list` of `.ChallengeBody` :ivar tuple combinations: Challenge combinations (`tuple` of `tuple` of `int`, as opposed to `list` of `list` from the spec). - :ivar acme.jose.jwk.JWK key: Public key. - :ivar tuple contact: :ivar acme.messages.Status status: :ivar datetime.datetime expires: @@ -294,7 +310,7 @@ class AuthorizationResource(ResourceWithURI): """Authorization Resource. :ivar acme.messages.Authorization body: - :ivar str new_cert_uri: URI found in the 'next' ``Link`` header + :ivar unicode new_cert_uri: URI found in the 'next' ``Link`` header """ body = jose.Field('body', decoder=Authorization.from_json) @@ -321,7 +337,7 @@ class CertificateResource(interfaces.ClientRequestableResource, :ivar acme.jose.util.ComparableX509 body: `OpenSSL.crypto.X509` wrapped in `.ComparableX509` - :ivar str cert_chain_uri: URI found in the 'up' ``Link`` header + :ivar unicode cert_chain_uri: URI found in the 'up' ``Link`` header :ivar tuple authzrs: `tuple` of `AuthorizationResource`. """ @@ -353,4 +369,4 @@ class Revocation(interfaces.ClientRequestableResource, :param str base: New Registration Resource or server (root) URL. """ - return urlparse.urljoin(base, cls.PATH) + return urllib_parse.urljoin(base, cls.PATH) diff --git a/acme/acme/other.py b/acme/acme/other.py index cf6425b7f..59bb0129b 100644 --- a/acme/acme/other.py +++ b/acme/acme/other.py @@ -12,22 +12,20 @@ logger = logging.getLogger(__name__) class Signature(jose.JSONObjectWithFields): """ACME signature. - :ivar str alg: Signature algorithm. - :ivar str sig: Signature. - :ivar str nonce: Nonce. - - :ivar jwk: JWK. - :type jwk: :class:`JWK` + :ivar .JWASignature alg: Signature algorithm. + :ivar bytes sig: Signature. + :ivar bytes nonce: Nonce. + :ivar .JWK jwk: JWK. """ NONCE_SIZE = 16 """Minimum size of nonce in bytes.""" alg = jose.Field('alg', decoder=jose.JWASignature.from_json) - sig = jose.Field('sig', encoder=jose.b64encode, + sig = jose.Field('sig', encoder=jose.encode_b64jose, decoder=jose.decode_b64jose) nonce = jose.Field( - 'nonce', encoder=jose.b64encode, decoder=functools.partial( + 'nonce', encoder=jose.encode_b64jose, decoder=functools.partial( jose.decode_b64jose, size=NONCE_SIZE, minimum=True)) jwk = jose.Field('jwk', decoder=jose.JWK.from_json) @@ -35,27 +33,26 @@ class Signature(jose.JSONObjectWithFields): def from_msg(cls, msg, key, nonce=None, nonce_size=None, alg=jose.RS256): """Create signature with nonce prepended to the message. - .. todo:: Protect against crypto unicode errors... is this sufficient? - Do I need to escape? - - :param str msg: Message to be signed. + :param bytes msg: Message to be signed. :param key: Key used for signing. :type key: `cryptography.hazmat.primitives.assymetric.rsa.RSAPrivateKey` (optionally wrapped in `.ComparableRSAKey`). - :param str nonce: Nonce to be used. If None, nonce of + :param bytes nonce: Nonce to be used. If None, nonce of ``nonce_size`` will be randomly generated. :param int nonce_size: Size of the automatically generated nonce. Defaults to :const:`NONCE_SIZE`. + :param .JWASignature alg: + """ nonce_size = cls.NONCE_SIZE if nonce_size is None else nonce_size nonce = os.urandom(nonce_size) if nonce is None else nonce msg_with_nonce = nonce + msg sig = alg.sign(key, nonce + msg) - logger.debug('%s signed as %s', msg_with_nonce, sig) + logger.debug('%r signed as %r', msg_with_nonce, sig) return cls(alg=alg, sig=sig, nonce=nonce, jwk=alg.kty(key=key.public_key())) @@ -63,7 +60,7 @@ class Signature(jose.JSONObjectWithFields): def verify(self, msg): """Verify the signature. - :param str msg: Message that was used in signing. + :param bytes msg: Message that was used in signing. """ # self.alg is not Field, but JWA | pylint: disable=no-member diff --git a/acme/acme/other_test.py b/acme/acme/other_test.py index 428fca81f..40fad9451 100644 --- a/acme/acme/other_test.py +++ b/acme/acme/other_test.py @@ -13,12 +13,12 @@ class SignatureTest(unittest.TestCase): """Tests for acme.sig.Signature.""" def setUp(self): - self.msg = 'message' - self.sig = ('IC\xd8*\xe7\x14\x9e\x19S\xb7\xcf\xec3\x12\xe2\x8a\x03' - '\x98u\xff\xf0\x94\xe2\xd7<\x8f\xa8\xed\xa4KN\xc3\xaa' - '\xb9X\xc3w\xaa\xc0_\xd0\x05$y>l#\x10<\x96\xd2\xcdr\xa3' - '\x1b\xa1\xf5!f\xef\xc64\xb6\x13') - self.nonce = '\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9' + self.msg = b'message' + self.sig = (b'IC\xd8*\xe7\x14\x9e\x19S\xb7\xcf\xec3\x12\xe2\x8a\x03' + b'\x98u\xff\xf0\x94\xe2\xd7<\x8f\xa8\xed\xa4KN\xc3\xaa' + b'\xb9X\xc3w\xaa\xc0_\xd0\x05$y>l#\x10<\x96\xd2\xcdr\xa3' + b'\x1b\xa1\xf5!f\xef\xc64\xb6\x13') + self.nonce = b'\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9' self.alg = jose.RS256 self.jwk = jose.JWKRSA(key=KEY.public_key()) @@ -54,7 +54,7 @@ class SignatureTest(unittest.TestCase): self.assertTrue(self.signature.verify(self.msg)) def test_verify_bad_fails(self): - self.assertFalse(self.signature.verify(self.msg + 'x')) + self.assertFalse(self.signature.verify(self.msg + b'x')) @classmethod def _from_msg(cls, *args, **kwargs): From 5d6d901655d0a4c71830ecb4ef17af308edb1d3d Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 11:38:33 +0000 Subject: [PATCH 19/30] Add py3 tox tests for acme.jose --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index d1b9253ed..7d5027bf8 100644 --- a/tox.ini +++ b/tox.ini @@ -30,7 +30,7 @@ setenv = envdir = {toxinidir}/tox.venv3 commands = pip install -e acme[testing] - nosetests acme/acme/jose + nosetests acme/acme [testenv:cover] basepython = python2.7 From 12720a225210afe73f301c2112f0a7ddcdc41bcb Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 11:39:37 +0000 Subject: [PATCH 20/30] Fix CSR loading in ACME example client script. --- examples/acme_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/acme_client.py b/examples/acme_client.py index 0d906d539..eacfb8ab8 100644 --- a/examples/acme_client.py +++ b/examples/acme_client.py @@ -41,7 +41,7 @@ authzr, authzr_response = acme.poll(authzr) csr = OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string( - 'acme.jose', os.path.join('testdata', 'csr.der'))) + 'acme', os.path.join('testdata', 'csr.der'))) try: acme.request_issuance(csr, (authzr,)) except messages.Error as error: From d361937b6780323639c1332a79a5948bd4376be7 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 13:39:40 +0000 Subject: [PATCH 21/30] RTFD: install subpkgs. --- readthedocs.org.requirements.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readthedocs.org.requirements.txt b/readthedocs.org.requirements.txt index 27cccb0a6..f686b00bf 100644 --- a/readthedocs.org.requirements.txt +++ b/readthedocs.org.requirements.txt @@ -7,4 +7,7 @@ # in --editable mode (-e), just "pip install .[docs]" does not work as # expected and "pip install -e .[docs]" must be used instead +-e acme -e .[docs] +-e letsencrypt-apache +-e letsencrypt-nginx From 7bc1cd4454080ca7bf2e656b9ed6276068d65d84 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 15:04:01 +0000 Subject: [PATCH 22/30] Remove shared tox venv --- .travis.yml | 2 +- tox.ini | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 31348f066..a7b03d20a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ env: install: "travis_retry pip install tox coveralls" before_script: '[ "${TOXENV:0:2}" != "py" ] || ./tests/boulder-start.sh' # TODO: eliminate substring slice bashism -script: 'travis_retry tox && ([ "${TOXENV:0:2}" != "py" ] || (source tox.venv/bin/activate && ./tests/boulder-integration.sh))' +script: 'travis_retry tox && ([ "${TOXENV:0:2}" != "py" ] || (source .tox/$TOXENV/bin/activate && ./tests/boulder-integration.sh))' after_success: '[ "$TOXENV" == "cover" ] && coveralls' diff --git a/tox.ini b/tox.ini index 7d5027bf8..9d5ccf49c 100644 --- a/tox.ini +++ b/tox.ini @@ -9,10 +9,6 @@ skipsdist = true envlist = py26,py27,py34,cover,lint [testenv] -# share one venv across testenvs, instead of multiple -# .tox/{py26,py27,cover,lint}; but do NOT set envdir to -# {toxinidir}/venv as it will destroy existing dev venv -envdir = {toxinidir}/tox.venv commands = pip install -r requirements.txt -e acme -e .[testing] -e letsencrypt-apache -e letsencrypt-nginx # -q does not suppress errors @@ -27,7 +23,6 @@ setenv = # https://testrun.org/tox/latest/example/basic.html#special-handling-of-pythonhas [testenv:py34] -envdir = {toxinidir}/tox.venv3 commands = pip install -e acme[testing] nosetests acme/acme From 596132292aee59c291f4086be554934ead50a4c8 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 15:07:25 +0000 Subject: [PATCH 23/30] Travis: test Python 3.4. --- .travis.yml | 8 ++++---- tox.ini | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index a7b03d20a..a771c372d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,15 +12,15 @@ env: global: - GOPATH=/tmp/go matrix: - - TOXENV=py26 - - TOXENV=py27 + - TOXENV=py26 BOULDER_INTEGRATION=1 + - TOXENV=py27 BOULDER_INTEGRATION=1 + - TOXENV=py34 - TOXENV=lint - TOXENV=cover install: "travis_retry pip install tox coveralls" before_script: '[ "${TOXENV:0:2}" != "py" ] || ./tests/boulder-start.sh' -# TODO: eliminate substring slice bashism -script: 'travis_retry tox && ([ "${TOXENV:0:2}" != "py" ] || (source .tox/$TOXENV/bin/activate && ./tests/boulder-integration.sh))' +script: 'travis_retry tox && ([ "xxx$BOULDER_INTEGRATION" = "xxx" ] || (source .tox/$TOXENV/bin/activate && ./tests/boulder-integration.sh))' after_success: '[ "$TOXENV" == "cover" ] && coveralls' diff --git a/tox.ini b/tox.ini index 9d5ccf49c..a2d4fbde7 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,7 @@ setenv = [testenv:py34] commands = pip install -e acme[testing] - nosetests acme/acme + nosetests acme [testenv:cover] basepython = python2.7 From 5859e87cedbd50681070a4cf4d0b64316ca12814 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 15:20:25 +0000 Subject: [PATCH 24/30] b64encode: no support for bytearray (py2.6 problems) --- acme/acme/jose/b64.py | 7 +++---- acme/acme/jose/b64_test.py | 3 --- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/acme/acme/jose/b64.py b/acme/acme/jose/b64.py index 5fccdce2e..cf79aa820 100644 --- a/acme/acme/jose/b64.py +++ b/acme/acme/jose/b64.py @@ -22,7 +22,7 @@ def b64encode(data): """JOSE Base64 encode. :param data: Data to be encoded. - :type data: `bytes` or `bytearray` + :type data: `bytes` :returns: JOSE Base64 string. :rtype: bytes @@ -30,9 +30,8 @@ def b64encode(data): :raises TypeError: if `data` is of incorrect type """ - if not isinstance(data, (six.binary_type, bytearray)): - raise TypeError('argument should be {0} or bytearray'.format( - six.binary_type)) + if not isinstance(data, six.binary_type): + raise TypeError('argument should be {0}'.format(six.binary_type)) return base64.urlsafe_b64encode(data).rstrip(b'=') diff --git a/acme/acme/jose/b64_test.py b/acme/acme/jose/b64_test.py index 989f8e7fe..cbabe2251 100644 --- a/acme/acme/jose/b64_test.py +++ b/acme/acme/jose/b64_test.py @@ -39,9 +39,6 @@ class B64EncodeTest(unittest.TestCase): for text, (b64, _) in six.iteritems(B64_PADDING_EXAMPLES): self.assertEqual(self._call(text), b64) - def test_bytearray_ok(self): - self.assertEqual(self._call(bytearray(b'foo')), b'Zm9v') - def test_unicode_fails_with_type_error(self): self.assertRaises(TypeError, self._call, u'some unicode') From 160a96052b9e088d914cd368a6cae109a25b4e06 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 15:20:52 +0000 Subject: [PATCH 25/30] tox/Travis: test Python 3.3 --- .travis.yml | 1 + tox.ini | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a771c372d..4f17e7fd8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ env: matrix: - TOXENV=py26 BOULDER_INTEGRATION=1 - TOXENV=py27 BOULDER_INTEGRATION=1 + - TOXENV=py33 - TOXENV=py34 - TOXENV=lint - TOXENV=cover diff --git a/tox.ini b/tox.ini index a2d4fbde7..1921fdd9c 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ # acme and letsencrypt are not yet on pypi, so when Tox invokes # "install *.zip", it will not find deps skipsdist = true -envlist = py26,py27,py34,cover,lint +envlist = py26,py27,py33,py34,cover,lint [testenv] commands = @@ -22,6 +22,11 @@ setenv = PYTHONHASHSEED = 0 # https://testrun.org/tox/latest/example/basic.html#special-handling-of-pythonhas +[testenv:py33] +commands = + pip install -e acme[testing] + nosetests acme + [testenv:py34] commands = pip install -e acme[testing] From f37b9192106b570d92e95417bb9c5bff8fcef3a6 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 15:25:43 +0000 Subject: [PATCH 26/30] Travis: run boulder-start.sh only if BOULDER_INTEGRATION is set. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4f17e7fd8..7cccd20c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ env: - TOXENV=cover install: "travis_retry pip install tox coveralls" -before_script: '[ "${TOXENV:0:2}" != "py" ] || ./tests/boulder-start.sh' +before_script: '[ "xxx$BOULDER_INTEGRATION" = "xxx" ] || ./tests/boulder-start.sh' script: 'travis_retry tox && ([ "xxx$BOULDER_INTEGRATION" = "xxx" ] || (source .tox/$TOXENV/bin/activate && ./tests/boulder-integration.sh))' after_success: '[ "$TOXENV" == "cover" ] && coveralls' From 7f46e69454f6cb53116c048c6379dece2c7a1f87 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 12 Jul 2015 15:30:51 +0000 Subject: [PATCH 27/30] Update ignore files to remove shared tox.venv --- .dockerignore | 5 ++--- .gitignore | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.dockerignore b/.dockerignore index 5ee05ea89..b94bf7960 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,13 +1,12 @@ # this file uses slightly different syntax than .gitignore, -# e.g. "tox.cover/" will not ignore tox.cover directory +# e.g. ".tox/" will not ignore .tox directory # well, official docker build should be done on clean git checkout # anyway, so .tox should be empty... But I'm sure people will try to # test docker on their git working directories. .git -tox.venv -tox.venv3 +.tox venv venv3 docs diff --git a/.gitignore b/.gitignore index 990564fca..c9a7e54e9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,6 @@ build/ dist/ /venv/ /venv3/ -/tox.venv/ -/tox.venv/ letsencrypt.log # coverage From 86c8fb141049fe704b99f1904fc3620c6b5ed4e4 Mon Sep 17 00:00:00 2001 From: Ceesjan Luiten Date: Fri, 10 Jul 2015 22:54:54 +0200 Subject: [PATCH 28/30] Do not silently truncate nginx config files --- .../letsencrypt_nginx/nginxparser.py | 4 ++-- .../letsencrypt_nginx/tests/nginxparser_test.py | 6 ++++++ .../tests/testdata/etc_nginx/broken.conf | 12 ++++++++++++ letsencrypt-nginx/letsencrypt_nginx/tests/util.py | 15 +++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/broken.conf diff --git a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py index f24455d59..6cce8d03a 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py +++ b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py @@ -4,7 +4,7 @@ import string from pyparsing import ( Literal, White, Word, alphanums, CharsNotIn, Forward, Group, Optional, OneOrMore, Regex, ZeroOrMore, pythonStyleComment) - +from pyparsing import stringEnd class RawNginxParser(object): # pylint: disable=expression-not-assigned @@ -35,7 +35,7 @@ class RawNginxParser(object): + Group(ZeroOrMore(Group(assignment) | block)) + right_bracket) - script = OneOrMore(Group(assignment) | block).ignore(pythonStyleComment) + script = (OneOrMore(Group(assignment) | block) + stringEnd).ignore(pythonStyleComment) def __init__(self, source): self.source = source diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py index 73a89534b..59bb070b2 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py @@ -2,6 +2,8 @@ import operator import unittest +from pyparsing import ParseException + from letsencrypt_nginx.nginxparser import ( RawNginxParser, load, dumps, dump) from letsencrypt_nginx.tests import util @@ -104,6 +106,10 @@ class TestRawNginxParser(unittest.TestCase): ['blah', '"hello;world"'], ['try_files', '$uri @rewrites']]]]]]) + def test_abort_on_parse_failure(self): + with open(util.get_data_filename('broken.conf')) as handle: + self.assertRaises(ParseException, load, handle) + def test_dump_as_file(self): parsed = load(open(util.get_data_filename('nginx.conf'))) parsed[-1][-1].append([['server'], diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/broken.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/broken.conf new file mode 100644 index 000000000..98aef55d6 --- /dev/null +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/broken.conf @@ -0,0 +1,12 @@ +# A faulty configuration file + +pid logs/nginx.pid; + + +events { + worker_connections 1024; +} + +include foo.conf; + +@@@ diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/util.py b/letsencrypt-nginx/letsencrypt_nginx/tests/util.py index a7db398c6..e7675f34d 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/util.py +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/util.py @@ -59,3 +59,18 @@ def get_nginx_configurator( version=version) config.prepare() return config + + +def filter_comments(tree): + """Filter comment nodes from parsed configurations.""" + + def traverse(tree): + """Generator dropping comment nodes""" + for key, values in tree: + if isinstance(key, list): + yield [key, filter_comments(values)] + else: + if key != '#': + yield [key, values] + + return list(traverse(tree)) From 1f552cab743a846f9941b0ed31842dbce1a85ae6 Mon Sep 17 00:00:00 2001 From: Ceesjan Luiten Date: Sat, 11 Jul 2015 09:15:59 +0200 Subject: [PATCH 29/30] Parse nginx comments --- .../letsencrypt_nginx/nginxparser.py | 36 ++++++------- .../tests/configurator_test.py | 10 ++-- .../tests/nginxparser_test.py | 51 +++++++++++++++---- .../etc_nginx/minimalistic_comments.conf | 12 +++++ .../etc_nginx/minimalistic_comments.new.conf | 11 ++++ .../tests/testdata/etc_nginx/nginx.new.conf | 20 ++++---- 6 files changed, 100 insertions(+), 40 deletions(-) create mode 100644 letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.conf create mode 100644 letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf diff --git a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py index 6cce8d03a..a22355c4b 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py +++ b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py @@ -3,8 +3,9 @@ import string from pyparsing import ( Literal, White, Word, alphanums, CharsNotIn, Forward, Group, - Optional, OneOrMore, Regex, ZeroOrMore, pythonStyleComment) + Optional, OneOrMore, Regex, ZeroOrMore) from pyparsing import stringEnd +from pyparsing import restOfLine class RawNginxParser(object): # pylint: disable=expression-not-assigned @@ -24,7 +25,8 @@ class RawNginxParser(object): modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~") # rules - assignment = (key + Optional(space + value) + semicolon) + comment = Literal('#') + restOfLine() + assignment = (key + Optional(space + value, default=None) + semicolon) location_statement = Optional(space + modifier) + Optional(space + location) if_statement = Literal("if") + space + Regex(r"\(.+\)") + space block = Forward() @@ -32,10 +34,10 @@ class RawNginxParser(object): block << Group( (Group(key + location_statement) ^ Group(if_statement)) + left_bracket - + Group(ZeroOrMore(Group(assignment) | block)) + + Group(ZeroOrMore(Group(comment | assignment) | block)) + right_bracket) - script = (OneOrMore(Group(assignment) | block) + stringEnd).ignore(pythonStyleComment) + script = OneOrMore(Group(comment | assignment) | block) + stringEnd def __init__(self, source): self.source = source @@ -60,26 +62,26 @@ class RawNginxDumper(object): """Iterates the dumped nginx content.""" blocks = blocks or self.blocks for key, values in blocks: - if current_indent: - yield spacer indentation = spacer * current_indent if isinstance(key, list): + if current_indent: + yield '' yield indentation + spacer.join(key) + ' {' + for parameter in values: - if isinstance(parameter[0], list): - dumped = self.__iter__( - [parameter], - current_indent + self.indentation) - for line in dumped: - yield line - else: - dumped = spacer.join(parameter) + ';' - yield spacer * ( - current_indent + self.indentation) + dumped + dumped = self.__iter__([parameter], current_indent + self.indentation) + for line in dumped: + yield line yield indentation + '}' else: - yield spacer * current_indent + key + spacer + values + ';' + if key == '#': + yield spacer * current_indent + key + values + else: + if values is None: + yield spacer * current_indent + key + ';' + else: + yield spacer * current_indent + key + spacer + values + ';' def as_string(self): """Return the parsed block as a string.""" diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py index bd700f144..2b7a4e08e 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py @@ -111,6 +111,10 @@ class NginxConfiguratorTest(util.NginxTest): self.config.parser.load() + parsed_example_conf = util.filter_comments(self.config.parser.parsed[example_conf]) + parsed_server_conf = util.filter_comments(self.config.parser.parsed[server_conf]) + parsed_nginx_conf = util.filter_comments(self.config.parser.parsed[nginx_conf]) + access_log = os.path.join(self.work_dir, "access.log") error_log = os.path.join(self.work_dir, "error.log") self.assertEqual([[['server'], @@ -125,9 +129,9 @@ class NginxConfiguratorTest(util.NginxTest): ['ssl_certificate_key', 'example/key.pem'], ['include', self.config.parser.loc["ssl_options"]]]]], - self.config.parser.parsed[example_conf]) + parsed_example_conf) self.assertEqual([['server_name', 'somename alias another.alias']], - self.config.parser.parsed[server_conf]) + parsed_server_conf) self.assertEqual([['server'], [['listen', '8000'], ['listen', 'somename:8080'], @@ -142,7 +146,7 @@ class NginxConfiguratorTest(util.NginxTest): ['ssl_certificate_key', '/etc/nginx/key.pem'], ['include', self.config.parser.loc["ssl_options"]]]], - self.config.parser.parsed[nginx_conf][-1][-1][-1]) + parsed_nginx_conf[-1][-1][-1]) def test_get_all_certs_keys(self): nginx_conf = self.config.parser.abs_path('nginx.conf') diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py index 59bb070b2..718ea1e85 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py @@ -44,7 +44,7 @@ class TestRawNginxParser(unittest.TestCase): ['server_name', 'foo.com'], ['root', '/home/ubuntu/sites/foo/'], [['location', '/status'], [ - ['check_status'], + ['check_status', None], [['types'], [['image/jpeg', 'jpg']]], ]] ]]]) @@ -54,9 +54,11 @@ class TestRawNginxParser(unittest.TestCase): 'server {\n' ' listen 80;\n' ' server_name foo.com;\n' - ' root /home/ubuntu/sites/foo/;\n \n' + ' root /home/ubuntu/sites/foo/;\n' + '\n' ' location /status {\n' - ' check_status;\n \n' + ' check_status;\n' + '\n' ' types {\n' ' image/jpeg jpg;\n' ' }\n' @@ -64,7 +66,8 @@ class TestRawNginxParser(unittest.TestCase): '}') def test_parse_from_file(self): - parsed = load(open(util.get_data_filename('foo.conf'))) + with open(util.get_data_filename('foo.conf')) as handle: + parsed = util.filter_comments(load(handle)) self.assertEqual( parsed, [['user', 'www-data'], @@ -87,7 +90,8 @@ class TestRawNginxParser(unittest.TestCase): ) def test_parse_from_file2(self): - parsed = load(open(util.get_data_filename('edge_cases.conf'))) + with open(util.get_data_filename('edge_cases.conf')) as handle: + parsed = util.filter_comments(load(handle)) self.assertEqual( parsed, [[['server'], [['server_name', 'simple']]], @@ -111,7 +115,8 @@ class TestRawNginxParser(unittest.TestCase): self.assertRaises(ParseException, load, handle) def test_dump_as_file(self): - parsed = load(open(util.get_data_filename('nginx.conf'))) + with open(util.get_data_filename('nginx.conf')) as handle: + parsed = util.filter_comments(load(handle)) parsed[-1][-1].append([['server'], [['listen', '443 ssl'], ['server_name', 'localhost'], @@ -123,12 +128,38 @@ class TestRawNginxParser(unittest.TestCase): [['location', '/'], [['root', 'html'], ['index', 'index.html index.htm']]]]]) - _file = open(util.get_data_filename('nginx.new.conf'), 'w') - dump(parsed, _file) - _file.close() - parsed_new = load(open(util.get_data_filename('nginx.new.conf'))) + + with open(util.get_data_filename('nginx.new.conf'), 'w') as handle: + dump(parsed, handle) + with open(util.get_data_filename('nginx.new.conf')) as handle: + parsed_new = util.filter_comments(load(handle)) self.assertEquals(parsed, parsed_new) + def test_comments(self): + with open(util.get_data_filename('minimalistic_comments.conf')) as handle: + parsed = load(handle) + + with open(util.get_data_filename('minimalistic_comments.new.conf'), 'w') as handle: + dump(parsed, handle) + + with open(util.get_data_filename('minimalistic_comments.new.conf')) as handle: + parsed_new = load(handle) + + self.assertEquals(parsed, parsed_new) + + self.assertEqual(parsed_new, [ + ['#', " Use bar.conf when it's a full moon!"], + ['include', 'foo.conf'], + ['#', ' Kilroy was here'], + ['check_status', None], + [['server'], + [['#', ''], + ['#', " Don't forget to open up your firewall!"], + ['#', ''], + ['listen', '1234'], + ['#', ' listen 80;']]], + ]) + if __name__ == '__main__': unittest.main() # pragma: no cover diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.conf new file mode 100644 index 000000000..cf4648592 --- /dev/null +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.conf @@ -0,0 +1,12 @@ +# Use bar.conf when it's a full moon! +include foo.conf; # Kilroy was here +check_status; + +server { + # + # Don't forget to open up your firewall! + # + listen 1234; + # listen 80; +} + diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf new file mode 100644 index 000000000..963490603 --- /dev/null +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf @@ -0,0 +1,11 @@ +# Use bar.conf when it's a full moon! +include foo.conf; +# Kilroy was here +check_status; +server { + # + # Don't forget to open up your firewall! + # + listen 1234; + # listen 80; +} \ No newline at end of file diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf index 0a43b5842..6beec1ced 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf @@ -20,52 +20,52 @@ http { tcp_nopush on; keepalive_timeout 0; gzip on; - + server { listen 8080; server_name localhost; server_name ~^(www\.)?(example|bar)\.; charset koi8-r; access_log logs/host.access.log main; - + location / { root html; index index.html index.htm; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; - + location = /50x.html { root html; } - + location ~ \.php$ { proxy_pass http://127.0.0.1; } - + location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; } - + location ~ /\.ht { deny all; } } - + server { listen 8000; listen somename:8080; include server.conf; - + location / { root html; index index.html index.htm; } } - + server { listen 443 ssl; server_name localhost; @@ -74,7 +74,7 @@ http { ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; - + location / { root html; index index.html index.htm; From 88c824c0ec2a4a7fe88f93bf22b949d8e2b8f4c1 Mon Sep 17 00:00:00 2001 From: Ceesjan Luiten Date: Sat, 11 Jul 2015 11:04:25 +0200 Subject: [PATCH 30/30] End nginx configuration files with a newline --- letsencrypt-nginx/letsencrypt_nginx/nginxparser.py | 2 +- letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py | 2 +- .../tests/testdata/etc_nginx/minimalistic_comments.new.conf | 2 +- .../letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py index a22355c4b..7870581b4 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py +++ b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py @@ -85,7 +85,7 @@ class RawNginxDumper(object): def as_string(self): """Return the parsed block as a string.""" - return '\n'.join(self) + return '\n'.join(self) + '\n' # Shortcut functions to respect Python's serialization interface diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py index 718ea1e85..0d6e5c453 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/nginxparser_test.py @@ -63,7 +63,7 @@ class TestRawNginxParser(unittest.TestCase): ' image/jpeg jpg;\n' ' }\n' ' }\n' - '}') + '}\n') def test_parse_from_file(self): with open(util.get_data_filename('foo.conf')) as handle: diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf index 963490603..d1b7be91e 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf @@ -8,4 +8,4 @@ server { # listen 1234; # listen 80; -} \ No newline at end of file +} diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf index 6beec1ced..59c1c968f 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/testdata/etc_nginx/nginx.new.conf @@ -80,4 +80,4 @@ http { index index.html index.htm; } } -} \ No newline at end of file +}