From 55ca1b484fc18626e89b111ff5e960a4081694c1 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Fri, 1 Jan 2016 20:55:52 -0500 Subject: [PATCH 001/264] Initial verison of DNS-01 implementation --- acme/acme/challenges.py | 79 ++++++++++++++++++++++++++++++ acme/acme/challenges_test.py | 93 ++++++++++++++++++++++++++++++++++++ acme/setup.py | 1 + 3 files changed, 173 insertions(+) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 1e456d325..f48c20443 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -1,5 +1,8 @@ """ACME Identifier Validation Challenges.""" import abc +import base64 +import dns.resolver +import dns.exception import functools import hashlib import logging @@ -215,6 +218,82 @@ class KeyAuthorizationChallenge(_TokenDVChallenge): self.validation(account_key, *args, **kwargs)) +@ChallengeResponse.register +class DNS01Response(KeyAuthorizationChallengeResponse): + """ACME "dns-01" challenge response.""" + typ = "dns-01" + + def simple_verify(self, chall, domain, account_public_key): + """Simple verify. + + :param challenges.DNS01 chall: Corresponding challenge. + :param unicode domain: Domain name being verified. + :param account_public_key: Public key for the key pair + being authorized. If ``None`` key verification is not + performed! + :param JWK account_public_key: + + :returns: ``True`` iff validation is successful, ``False`` + otherwise. + :rtype: bool + + """ + if not self.verify(chall, account_public_key): + logger.debug("Verification of key authorization in response failed") + return False + + validation_name = chall.validation_domain_name(domain) + validation = chall.validation(account_public_key) + logger.debug("Verifying %s at %s...", chall.typ, validation_name) + txt_records = [] + try: + dns_response = dns.resolver.query(validation_name, 'TXT') + for rdata in dns_response: + for txt_record in rdata.strings: + txt_records.append(txt_record) + except dns.exception.DNSException as error: + logger.error("Unable to resolve %s: %s", validation_name, error) + return False + + for txt_record in txt_records: + if txt_record == validation: + return True + + logger.debug("Key authorization from response (%r) doesn't match any " + "DNS response in %r", self.key_authorization, txt_records) + return False + +@Challenge.register # pylint: disable=too-many-ancestors +class DNS01(KeyAuthorizationChallenge): + """ACME "dns-01" challenge.""" + + response_cls = DNS01Response + typ = response_cls.typ + + LABEL = "_acme-challenge" + """Label clients prepend to the domain name being validated.""" + + def validation(self, account_key, **unused_kwargs): + """Generate validation. + + :param JWK account_key: + :rtype: unicode + + """ + key_authorization = self.key_authorization(account_key) + # FIXME Once boulder response according to the spec this needs to be fixed + # return base64.b64encode(hashlib.sha256(key_authorization).digest()) + return hashlib.sha256(key_authorization).hexdigest() + + def validation_domain_name(self, name): + """Domain name for TXT validation record. + + :param unicode name: Domain name being validated. + + """ + return "{0}.{1}".format(self.LABEL, name) + + @ChallengeResponse.register class HTTP01Response(KeyAuthorizationChallengeResponse): """ACME http-01 challenge response.""" diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index a4e78ebe9..a587d3f61 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -1,6 +1,7 @@ """Tests for acme.challenges.""" import unittest +import dns.rrset import mock import OpenSSL import requests @@ -76,6 +77,98 @@ class KeyAuthorizationChallengeResponseTest(unittest.TestCase): key_authorization='.foo.oKGqedy-b-acd5eoybm2f-NVFxvyOoET5CNy3xnv8WY') self.assertFalse(response.verify(self.chall, KEY.public_key())) +class DNS01ResponseTest(unittest.TestCase): + # pylint: disable=too-many-instance-attributes + + def setUp(self): + from acme.challenges import DNS01Response + self.msg = DNS01Response(key_authorization=u'foo') + self.jmsg = { + 'resource': 'challenge', + 'type': 'dns-01', + 'keyAuthorization': u'foo', + } + + from acme.challenges import DNS01 + self.chall = DNS01(token=(b'x' * 16)) + self.response = self.chall.response(KEY) + + # This takes advantage of the fact that an answer object mostly behaves like + # an RRset + def create_txt_response(self, name, txt_record): + return dns.rrset.from_text(name, 60, "IN", "TXT", txt_record) + + def test_to_partial_json(self): + self.assertEqual(self.jmsg, self.msg.to_partial_json()) + + def test_from_json(self): + from acme.challenges import DNS01Response + self.assertEqual( + self.msg, DNS01Response.from_json(self.jmsg)) + + def test_from_json_hashable(self): + from acme.challenges import DNS01Response + hash(DNS01Response.from_json(self.jmsg)) + + def test_simple_verify_bad_key_authorization(self): + key2 = jose.JWKRSA.load(test_util.load_vector('rsa256_key.pem')) + self.response.simple_verify(self.chall, "local", key2.public_key()) + + @mock.patch("acme.challenges.dns.resolver.query") + def test_simple_verify_good_validation(self, mock_dns): + mock_dns.return_value = self.create_txt_response( + self.chall.validation_domain_name("local"), + self.chall.validation(KEY.public_key())) + self.assertTrue(self.response.simple_verify( + self.chall, "local", KEY.public_key())) + mock_dns.assert_called_once_with( + self.chall.validation_domain_name("local"), "TXT") + + @mock.patch("acme.challenges.dns.resolver.query") + def test_simple_verify_bad_validation(self, mock_dns): + mock_dns.return_value = self.create_txt_response( + self.chall.validation_domain_name("local"), "!") + self.assertFalse(self.response.simple_verify( + self.chall, "local", KEY.public_key())) + + @mock.patch("acme.challenges.dns.resolver.query") + def test_simple_verify_connection_error(self, mock_dns): + mock_dns.side_effect = dns.exception.DNSException + self.assertFalse(self.response.simple_verify( + self.chall, "local", KEY.public_key())) + +class DNS01Test(unittest.TestCase): + + def setUp(self): + from acme.challenges import DNS01 + self.msg = DNS01( + token=jose.decode_b64jose( + 'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ+PCt92wr+oA')) + self.jmsg = { + 'type': 'dns-01', + 'token': 'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA', + } + + def test_validation_domain_name(self): + self.assertEqual('_acme-challenge.www.example.com', + self.msg.validation_domain_name('www.example.com')) + + def test_validation(self): + self.assertEqual( + "ac06bb8888382b6cbaddfbd48427f2f1d3f55e5ef0121990ab4a02853704dd99", + self.msg.validation(KEY)) + + def test_to_partial_json(self): + self.assertEqual(self.jmsg, self.msg.to_partial_json()) + + def test_from_json(self): + from acme.challenges import DNS01 + self.assertEqual(self.msg, DNS01.from_json(self.jmsg)) + + def test_from_json_hashable(self): + from acme.challenges import DNS01 + hash(DNS01.from_json(self.jmsg)) + class HTTP01ResponseTest(unittest.TestCase): # pylint: disable=too-many-instance-attributes diff --git a/acme/setup.py b/acme/setup.py index ba2c88394..dd2bce5d9 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -12,6 +12,7 @@ install_requires = [ 'cryptography>=0.8', # Connection.set_tlsext_host_name (>=0.13), X509Req.get_extensions (>=0.15) 'PyOpenSSL>=0.15', + 'dnspython', 'pyrfc3339', 'pytz', 'requests', From ffc2b1ee7864a848c0f2a22ca873ac970bb911bf Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sat, 2 Jan 2016 01:42:47 -0500 Subject: [PATCH 002/264] - Lint fixes - Add test for multiple TXT records returned - Add extra parameter in DNS01.validation to select hexdigit vs. bas64 encoded validation --- acme/acme/challenges.py | 23 +++++++++++------------ acme/acme/challenges_test.py | 36 +++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index f48c20443..6c13ec906 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -242,17 +242,15 @@ class DNS01Response(KeyAuthorizationChallengeResponse): logger.debug("Verification of key authorization in response failed") return False - validation_name = chall.validation_domain_name(domain) + validation_domain_name = chall.validation_domain_name(domain) validation = chall.validation(account_public_key) - logger.debug("Verifying %s at %s...", chall.typ, validation_name) - txt_records = [] + logger.debug("Verifying %s at %s...", chall.typ, validation_domain_name) try: - dns_response = dns.resolver.query(validation_name, 'TXT') - for rdata in dns_response: - for txt_record in rdata.strings: - txt_records.append(txt_record) + dns_response = dns.resolver.query(validation_domain_name, 'TXT') + txt_records = sum([rdata.strings for rdata in dns_response], []) except dns.exception.DNSException as error: - logger.error("Unable to resolve %s: %s", validation_name, error) + logger.error("Unable to resolve %s: %s", validation_domain_name, + error) return False for txt_record in txt_records: @@ -273,7 +271,8 @@ class DNS01(KeyAuthorizationChallenge): LABEL = "_acme-challenge" """Label clients prepend to the domain name being validated.""" - def validation(self, account_key, **unused_kwargs): + # FIXME: Remove extra parameter once #2052 is integrated + def validation(self, account_key, dns01_hexdigit_response=True, **unused_kwargs): """Generate validation. :param JWK account_key: @@ -281,9 +280,9 @@ class DNS01(KeyAuthorizationChallenge): """ key_authorization = self.key_authorization(account_key) - # FIXME Once boulder response according to the spec this needs to be fixed - # return base64.b64encode(hashlib.sha256(key_authorization).digest()) - return hashlib.sha256(key_authorization).hexdigest() + if dns01_hexdigit_response: + return hashlib.sha256(key_authorization).hexdigest() + return base64.urlsafe_b64encode(hashlib.sha256(key_authorization).digest()) def validation_domain_name(self, name): """Domain name for TXT validation record. diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index a587d3f61..c2a629bb3 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -93,10 +93,15 @@ class DNS01ResponseTest(unittest.TestCase): self.chall = DNS01(token=(b'x' * 16)) self.response = self.chall.response(KEY) - # This takes advantage of the fact that an answer object mostly behaves like - # an RRset - def create_txt_response(self, name, txt_record): - return dns.rrset.from_text(name, 60, "IN", "TXT", txt_record) + def create_txt_response(self, name, txt_records): + """ + Returns an RRSet containing the 'txt_records' as the result of a DNS + query for 'name'. + + This takes advantage of the fact that an Answer object mostly behaves + like an RRset. + """ + return dns.rrset.from_text_list(name, 60, "IN", "TXT", txt_records) def test_to_partial_json(self): self.assertEqual(self.jmsg, self.msg.to_partial_json()) @@ -118,7 +123,17 @@ class DNS01ResponseTest(unittest.TestCase): def test_simple_verify_good_validation(self, mock_dns): mock_dns.return_value = self.create_txt_response( self.chall.validation_domain_name("local"), - self.chall.validation(KEY.public_key())) + [self.chall.validation(KEY.public_key())]) + self.assertTrue(self.response.simple_verify( + self.chall, "local", KEY.public_key())) + mock_dns.assert_called_once_with( + self.chall.validation_domain_name("local"), "TXT") + + @mock.patch("acme.challenges.dns.resolver.query") + def test_simple_verify_good_validation_multiple_txts(self, mock_dns): + mock_dns.return_value = self.create_txt_response( + self.chall.validation_domain_name("local"), + ["!", self.chall.validation(KEY.public_key())]) self.assertTrue(self.response.simple_verify( self.chall, "local", KEY.public_key())) mock_dns.assert_called_once_with( @@ -127,7 +142,7 @@ class DNS01ResponseTest(unittest.TestCase): @mock.patch("acme.challenges.dns.resolver.query") def test_simple_verify_bad_validation(self, mock_dns): mock_dns.return_value = self.create_txt_response( - self.chall.validation_domain_name("local"), "!") + self.chall.validation_domain_name("local"), ["!"]) self.assertFalse(self.response.simple_verify( self.chall, "local", KEY.public_key())) @@ -153,10 +168,17 @@ class DNS01Test(unittest.TestCase): self.assertEqual('_acme-challenge.www.example.com', self.msg.validation_domain_name('www.example.com')) + # FIXME: Remove extra parameter once #2052 is integrated def test_validation(self): + self.assertEqual( + "rAa7iIg4K2y63fvUhCfy8dP1Xl7wEhmQq0oChTcE3Zk=", + self.msg.validation(KEY, dns01_hexdigit_response=False)) + + # FIXME: Remove this once #2052 is integrated + def test_validation_for_server_with_hexdigit_response(self): self.assertEqual( "ac06bb8888382b6cbaddfbd48427f2f1d3f55e5ef0121990ab4a02853704dd99", - self.msg.validation(KEY)) + self.msg.validation(KEY, dns01_hexdigit_response=True)) def test_to_partial_json(self): self.assertEqual(self.jmsg, self.msg.to_partial_json()) From 7e2a1532ef5a3c48e3d1cf9c382a13da0ed62097 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sat, 2 Jan 2016 12:53:47 -0500 Subject: [PATCH 003/264] Move dns record retrieval into a separate method. --- acme/acme/challenges.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 6c13ec906..cc938dd31 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -223,6 +223,22 @@ class DNS01Response(KeyAuthorizationChallengeResponse): """ACME "dns-01" challenge response.""" typ = "dns-01" + def txt_records_for_name(self, name): + """Resolve the name and return the TXT records. + + :param unicode name: Domain name being verified. + + :returns: A list of txt records, or None if the name could not be resolved + :rtype: list of unicode + + """ + try: + dns_response = dns.resolver.query(name, 'TXT') + except dns.exception.DNSException as error: + logger.error("Unable to resolve %s: %s", name, error) + return None + return sum([rdata.strings for rdata in dns_response], []) + def simple_verify(self, chall, domain, account_public_key): """Simple verify. @@ -245,15 +261,7 @@ class DNS01Response(KeyAuthorizationChallengeResponse): validation_domain_name = chall.validation_domain_name(domain) validation = chall.validation(account_public_key) logger.debug("Verifying %s at %s...", chall.typ, validation_domain_name) - try: - dns_response = dns.resolver.query(validation_domain_name, 'TXT') - txt_records = sum([rdata.strings for rdata in dns_response], []) - except dns.exception.DNSException as error: - logger.error("Unable to resolve %s: %s", validation_domain_name, - error) - return False - - for txt_record in txt_records: + for txt_record in self.txt_records_for_domain(validation_domain_name): if txt_record == validation: return True From 64f3f53467b33d97359d0ba6f9795d5757d3f4a7 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sat, 2 Jan 2016 13:51:37 -0500 Subject: [PATCH 004/264] Fix --- acme/acme/challenges.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index cc938dd31..5c3c8e8aa 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -261,7 +261,11 @@ class DNS01Response(KeyAuthorizationChallengeResponse): validation_domain_name = chall.validation_domain_name(domain) validation = chall.validation(account_public_key) logger.debug("Verifying %s at %s...", chall.typ, validation_domain_name) - for txt_record in self.txt_records_for_domain(validation_domain_name): + txt_records = self.txt_records_for_name(validation_domain_name) + if txt_records == None: + return False + + for txt_record in txt_records: if txt_record == validation: return True From 97fb1a03f99cd219cffe7e77ab6c616c03b9afec Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sun, 3 Jan 2016 13:19:32 -0500 Subject: [PATCH 005/264] Documentation fixes. --- acme/acme/challenges.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 5c3c8e8aa..6ca36d482 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -249,8 +249,8 @@ class DNS01Response(KeyAuthorizationChallengeResponse): performed! :param JWK account_public_key: - :returns: ``True`` iff validation is successful, ``False`` - otherwise. + :returns: ``True`` iff validation with the TXT records resolved from a + DNS server is successful. :rtype: bool """ @@ -332,8 +332,8 @@ class HTTP01Response(KeyAuthorizationChallengeResponse): :param JWK account_public_key: :param int port: Port used in the validation. - :returns: ``True`` iff validation is successful, ``False`` - otherwise. + :returns: ``True`` iff validation of the files currently server by the + HTTP server is successful. :rtype: bool """ @@ -504,7 +504,7 @@ class TLSSNI01Response(KeyAuthorizationChallengeResponse): :returns: ``True`` iff client's control of the domain has been - verified, ``False`` otherwise. + verified. :rtype: bool """ From 74a9703269a320a0180e8360218e6f8de599d0ba Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Mon, 4 Jan 2016 16:16:42 -0500 Subject: [PATCH 006/264] Style fix --- acme/acme/challenges.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 6ca36d482..b783eee9c 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -262,7 +262,7 @@ class DNS01Response(KeyAuthorizationChallengeResponse): validation = chall.validation(account_public_key) logger.debug("Verifying %s at %s...", chall.typ, validation_domain_name) txt_records = self.txt_records_for_name(validation_domain_name) - if txt_records == None: + if txt_records is None: return False for txt_record in txt_records: From 7747dc8488f2ea67b21ad53ffe9e31cd8e7d1232 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Mon, 4 Jan 2016 19:46:28 -0500 Subject: [PATCH 007/264] Remove non-compliant hexdigit encoding for dns-01 challenges (#2052 is now merged). --- acme/acme/challenges.py | 8 ++------ acme/acme/challenges_test.py | 11 ++--------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 6ca36d482..77ca2e214 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -1,6 +1,5 @@ """ACME Identifier Validation Challenges.""" import abc -import base64 import dns.resolver import dns.exception import functools @@ -283,8 +282,7 @@ class DNS01(KeyAuthorizationChallenge): LABEL = "_acme-challenge" """Label clients prepend to the domain name being validated.""" - # FIXME: Remove extra parameter once #2052 is integrated - def validation(self, account_key, dns01_hexdigit_response=True, **unused_kwargs): + def validation(self, account_key, **unused_kwargs): """Generate validation. :param JWK account_key: @@ -292,9 +290,7 @@ class DNS01(KeyAuthorizationChallenge): """ key_authorization = self.key_authorization(account_key) - if dns01_hexdigit_response: - return hashlib.sha256(key_authorization).hexdigest() - return base64.urlsafe_b64encode(hashlib.sha256(key_authorization).digest()) + return jose.b64encode(hashlib.sha256(key_authorization).digest()) def validation_domain_name(self, name): """Domain name for TXT validation record. diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index c2a629bb3..b6c771d1b 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -168,17 +168,10 @@ class DNS01Test(unittest.TestCase): self.assertEqual('_acme-challenge.www.example.com', self.msg.validation_domain_name('www.example.com')) - # FIXME: Remove extra parameter once #2052 is integrated def test_validation(self): self.assertEqual( - "rAa7iIg4K2y63fvUhCfy8dP1Xl7wEhmQq0oChTcE3Zk=", - self.msg.validation(KEY, dns01_hexdigit_response=False)) - - # FIXME: Remove this once #2052 is integrated - def test_validation_for_server_with_hexdigit_response(self): - self.assertEqual( - "ac06bb8888382b6cbaddfbd48427f2f1d3f55e5ef0121990ab4a02853704dd99", - self.msg.validation(KEY, dns01_hexdigit_response=True)) + "rAa7iIg4K2y63fvUhCfy8dP1Xl7wEhmQq0oChTcE3Zk", + self.msg.validation(KEY)) def test_to_partial_json(self): self.assertEqual(self.jmsg, self.msg.to_partial_json()) From b5bb90628c080d7719546438d73b01534c7db25a Mon Sep 17 00:00:00 2001 From: wteiken Date: Tue, 5 Jan 2016 20:33:30 -0500 Subject: [PATCH 008/264] Style changes. --- acme/acme/challenges.py | 30 ++++++++++++------------------ acme/acme/challenges_test.py | 4 ++-- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 77ca2e214..cb8873984 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -1,13 +1,13 @@ """ACME Identifier Validation Challenges.""" import abc -import dns.resolver -import dns.exception import functools import hashlib import logging import socket from cryptography.hazmat.primitives import hashes +import dns.resolver +import dns.exception import OpenSSL import requests @@ -217,17 +217,16 @@ class KeyAuthorizationChallenge(_TokenDVChallenge): self.validation(account_key, *args, **kwargs)) -@ChallengeResponse.register class DNS01Response(KeyAuthorizationChallengeResponse): """ACME "dns-01" challenge response.""" typ = "dns-01" - def txt_records_for_name(self, name): + def txt_records_for_name(name): """Resolve the name and return the TXT records. :param unicode name: Domain name being verified. - :returns: A list of txt records, or None if the name could not be resolved + :returns: A list of txt records, if empty the name could not be resolved :rtype: list of unicode """ @@ -235,17 +234,17 @@ class DNS01Response(KeyAuthorizationChallengeResponse): dns_response = dns.resolver.query(name, 'TXT') except dns.exception.DNSException as error: logger.error("Unable to resolve %s: %s", name, error) - return None - return sum([rdata.strings for rdata in dns_response], []) + return [] + return [txt_rec in dns_response for txt_rec in rdata.strings] +@ChallengeResponse.register def simple_verify(self, chall, domain, account_public_key): """Simple verify. :param challenges.DNS01 chall: Corresponding challenge. :param unicode domain: Domain name being verified. :param account_public_key: Public key for the key pair - being authorized. If ``None`` key verification is not - performed! + being authorized. :param JWK account_public_key: :returns: ``True`` iff validation with the TXT records resolved from a @@ -260,14 +259,9 @@ class DNS01Response(KeyAuthorizationChallengeResponse): validation_domain_name = chall.validation_domain_name(domain) validation = chall.validation(account_public_key) logger.debug("Verifying %s at %s...", chall.typ, validation_domain_name) - txt_records = self.txt_records_for_name(validation_domain_name) - if txt_records == None: - return False - - for txt_record in txt_records: - if txt_record == validation: - return True + if validation in txt_records_for_name(validation_domain_name): + return True logger.debug("Key authorization from response (%r) doesn't match any " "DNS response in %r", self.key_authorization, txt_records) return False @@ -289,8 +283,8 @@ class DNS01(KeyAuthorizationChallenge): :rtype: unicode """ - key_authorization = self.key_authorization(account_key) - return jose.b64encode(hashlib.sha256(key_authorization).digest()) + return jose.b64encode(hashlib.sha256( + self.key_authorization(account_key)).digest()) def validation_domain_name(self, name): """Domain name for TXT validation record. diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index b6c771d1b..b744de024 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -77,6 +77,7 @@ class KeyAuthorizationChallengeResponseTest(unittest.TestCase): key_authorization='.foo.oKGqedy-b-acd5eoybm2f-NVFxvyOoET5CNy3xnv8WY') self.assertFalse(response.verify(self.chall, KEY.public_key())) + class DNS01ResponseTest(unittest.TestCase): # pylint: disable=too-many-instance-attributes @@ -108,8 +109,7 @@ class DNS01ResponseTest(unittest.TestCase): def test_from_json(self): from acme.challenges import DNS01Response - self.assertEqual( - self.msg, DNS01Response.from_json(self.jmsg)) + self.assertEqual(self.msg, DNS01Response.from_json(self.jmsg)) def test_from_json_hashable(self): from acme.challenges import DNS01Response From 4403a78e52e684d5b94b8982f5b86609fc1fc20f Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Tue, 5 Jan 2016 22:25:24 -0500 Subject: [PATCH 009/264] Move txt_records_for_name out of class. --- acme/acme/challenges.py | 49 +++++++++++++++++++----------------- acme/acme/challenges_test.py | 1 + 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index cb8873984..e235a087e 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -217,27 +217,11 @@ class KeyAuthorizationChallenge(_TokenDVChallenge): self.validation(account_key, *args, **kwargs)) +@ChallengeResponse.register class DNS01Response(KeyAuthorizationChallengeResponse): """ACME "dns-01" challenge response.""" typ = "dns-01" - def txt_records_for_name(name): - """Resolve the name and return the TXT records. - - :param unicode name: Domain name being verified. - - :returns: A list of txt records, if empty the name could not be resolved - :rtype: list of unicode - - """ - try: - dns_response = dns.resolver.query(name, 'TXT') - except dns.exception.DNSException as error: - logger.error("Unable to resolve %s: %s", name, error) - return [] - return [txt_rec in dns_response for txt_rec in rdata.strings] - -@ChallengeResponse.register def simple_verify(self, chall, domain, account_public_key): """Simple verify. @@ -260,16 +244,18 @@ class DNS01Response(KeyAuthorizationChallengeResponse): validation = chall.validation(account_public_key) logger.debug("Verifying %s at %s...", chall.typ, validation_domain_name) - if validation in txt_records_for_name(validation_domain_name): - return True - logger.debug("Key authorization from response (%r) doesn't match any " - "DNS response in %r", self.key_authorization, txt_records) - return False + txt_records = txt_records_for_name(validation_domain_name) + exists = validation in txt_records + if not exists: + logger.debug("Key authorization from response (%r) doesn't match " + "any DNS response in %r", self.key_authorization, + txt_records) + return exists + @Challenge.register # pylint: disable=too-many-ancestors class DNS01(KeyAuthorizationChallenge): """ACME "dns-01" challenge.""" - response_cls = DNS01Response typ = response_cls.typ @@ -716,3 +702,20 @@ class DNSResponse(ChallengeResponse): """ return chall.check_validation(self.validation, account_public_key) + + +def txt_records_for_name(name): + """Resolve the name and return the TXT records. + + :param unicode name: Domain name being verified. + + :returns: A list of txt records, if empty the name could not be resolved + :rtype: list of unicode + + """ + try: + dns_response = dns.resolver.query(name, 'TXT') + except dns.exception.DNSException as error: + logger.error("Unable to resolve %s: %s", name, error) + return [] + return [txt_rec for rdata in dns_response for txt_rec in rdata.strings] diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index b744de024..79a928456 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -152,6 +152,7 @@ class DNS01ResponseTest(unittest.TestCase): self.assertFalse(self.response.simple_verify( self.chall, "local", KEY.public_key())) + class DNS01Test(unittest.TestCase): def setUp(self): From fd2709a6fa2c2cc764aa2b1a50178ad62e71a1c5 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Tue, 5 Jan 2016 23:58:23 -0500 Subject: [PATCH 010/264] Move dnspython dependency to tests only and only import the dns.resolver when actually resolving the client. That way user code that does not call 'simple_verify' for DNS01 challenges does not depend on dnspython. --- acme/acme/challenges.py | 10 ++++++---- acme/setup.py | 3 +-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index e235a087e..aa7b20689 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -6,8 +6,6 @@ import logging import socket from cryptography.hazmat.primitives import hashes -import dns.resolver -import dns.exception import OpenSSL import requests @@ -714,8 +712,12 @@ def txt_records_for_name(name): """ try: + import dns.resolver dns_response = dns.resolver.query(name, 'TXT') - except dns.exception.DNSException as error: - logger.error("Unable to resolve %s: %s", name, error) + except ImportError as error: + raise ImportError("Local validation for 'dns-01' challenges requires " + "'dnspython'"); + except Exception as error: + logger.error("Unable to resolve %s: %s", name, str(error)) return [] return [txt_rec for rdata in dns_response for txt_rec in rdata.strings] diff --git a/acme/setup.py b/acme/setup.py index dd2bce5d9..76a2c1b72 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -12,7 +12,6 @@ install_requires = [ 'cryptography>=0.8', # Connection.set_tlsext_host_name (>=0.13), X509Req.get_extensions (>=0.15) 'PyOpenSSL>=0.15', - 'dnspython', 'pyrfc3339', 'pytz', 'requests', @@ -76,7 +75,7 @@ setup( install_requires=install_requires, extras_require={ 'docs': docs_extras, - 'testing': testing_extras, + 'testing': testing_extras + 'dnspython', }, entry_points={ 'console_scripts': [ From 57c265c7f36087bb3de0f96a25cfcd8ae62538ab Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 00:27:07 -0500 Subject: [PATCH 011/264] Setup.py and style fixes --- acme/acme/challenges.py | 5 +++-- acme/setup.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index aa7b20689..f4eb115c4 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -713,11 +713,12 @@ def txt_records_for_name(name): """ try: import dns.resolver + import dns.exception dns_response = dns.resolver.query(name, 'TXT') except ImportError as error: raise ImportError("Local validation for 'dns-01' challenges requires " - "'dnspython'"); - except Exception as error: + "'dnspython'") + except dns.exception.DNSException as error: logger.error("Unable to resolve %s: %s", name, str(error)) return [] return [txt_rec for rdata in dns_response for txt_rec in rdata.strings] diff --git a/acme/setup.py b/acme/setup.py index 76a2c1b72..e00476117 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -75,7 +75,7 @@ setup( install_requires=install_requires, extras_require={ 'docs': docs_extras, - 'testing': testing_extras + 'dnspython', + 'testing': testing_extras + ['dnspython'], }, entry_points={ 'console_scripts': [ From dc743fb57cc9c3c7fb805ece50681f1388440f9c Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 01:11:24 -0500 Subject: [PATCH 012/264] Move DNS resolver to separate module to decouple dependencies and testing. --- acme/acme/challenges.py | 30 ++++++---------------- acme/acme/challenges_test.py | 46 +++++++++------------------------- acme/acme/dns_resolver.py | 28 +++++++++++++++++++++ acme/acme/dns_resolver_test.py | 37 +++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 57 deletions(-) create mode 100644 acme/acme/dns_resolver.py create mode 100644 acme/acme/dns_resolver_test.py diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index f4eb115c4..221eb406c 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -15,7 +15,6 @@ from acme import fields from acme import jose from acme import other - logger = logging.getLogger(__name__) @@ -242,7 +241,13 @@ class DNS01Response(KeyAuthorizationChallengeResponse): validation = chall.validation(account_public_key) logger.debug("Verifying %s at %s...", chall.typ, validation_domain_name) - txt_records = txt_records_for_name(validation_domain_name) + try: + from acme import dns_resolver + txt_records = dns_resolver.txt_records_for_name( + validation_domain_name) + except ImportError as error: + raise ImportError("Local validation for 'dns-01' challenges " + "requires 'dnspython'") exists = validation in txt_records if not exists: logger.debug("Key authorization from response (%r) doesn't match " @@ -701,24 +706,3 @@ class DNSResponse(ChallengeResponse): """ return chall.check_validation(self.validation, account_public_key) - -def txt_records_for_name(name): - """Resolve the name and return the TXT records. - - :param unicode name: Domain name being verified. - - :returns: A list of txt records, if empty the name could not be resolved - :rtype: list of unicode - - """ - try: - import dns.resolver - import dns.exception - dns_response = dns.resolver.query(name, 'TXT') - except ImportError as error: - raise ImportError("Local validation for 'dns-01' challenges requires " - "'dnspython'") - except dns.exception.DNSException as error: - logger.error("Unable to resolve %s: %s", name, str(error)) - return [] - return [txt_rec for rdata in dns_response for txt_rec in rdata.strings] diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index 79a928456..0fc8fcef7 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -1,7 +1,6 @@ """Tests for acme.challenges.""" import unittest -import dns.rrset import mock import OpenSSL import requests @@ -94,16 +93,6 @@ class DNS01ResponseTest(unittest.TestCase): self.chall = DNS01(token=(b'x' * 16)) self.response = self.chall.response(KEY) - def create_txt_response(self, name, txt_records): - """ - Returns an RRSet containing the 'txt_records' as the result of a DNS - query for 'name'. - - This takes advantage of the fact that an Answer object mostly behaves - like an RRset. - """ - return dns.rrset.from_text_list(name, 60, "IN", "TXT", txt_records) - def test_to_partial_json(self): self.assertEqual(self.jmsg, self.msg.to_partial_json()) @@ -119,36 +108,25 @@ class DNS01ResponseTest(unittest.TestCase): key2 = jose.JWKRSA.load(test_util.load_vector('rsa256_key.pem')) self.response.simple_verify(self.chall, "local", key2.public_key()) - @mock.patch("acme.challenges.dns.resolver.query") - def test_simple_verify_good_validation(self, mock_dns): - mock_dns.return_value = self.create_txt_response( - self.chall.validation_domain_name("local"), - [self.chall.validation(KEY.public_key())]) + @mock.patch("acme.dns_resolver.txt_records_for_name") + def test_simple_verify_good_validation(self, mock_resolver): + mock_resolver.return_value = [self.chall.validation(KEY.public_key())] self.assertTrue(self.response.simple_verify( self.chall, "local", KEY.public_key())) - mock_dns.assert_called_once_with( - self.chall.validation_domain_name("local"), "TXT") + mock_resolver.assert_called_once_with( + self.chall.validation_domain_name("local")) - @mock.patch("acme.challenges.dns.resolver.query") - def test_simple_verify_good_validation_multiple_txts(self, mock_dns): - mock_dns.return_value = self.create_txt_response( - self.chall.validation_domain_name("local"), - ["!", self.chall.validation(KEY.public_key())]) + @mock.patch("acme.dns_resolver.txt_records_for_name") + def test_simple_verify_good_validation_multiple_txts(self, mock_resolver): + mock_resolver.return_value = ["!", self.chall.validation(KEY.public_key())] self.assertTrue(self.response.simple_verify( self.chall, "local", KEY.public_key())) - mock_dns.assert_called_once_with( - self.chall.validation_domain_name("local"), "TXT") + mock_resolver.assert_called_once_with( + self.chall.validation_domain_name("local")) - @mock.patch("acme.challenges.dns.resolver.query") + @mock.patch("acme.dns_resolver.txt_records_for_name") def test_simple_verify_bad_validation(self, mock_dns): - mock_dns.return_value = self.create_txt_response( - self.chall.validation_domain_name("local"), ["!"]) - self.assertFalse(self.response.simple_verify( - self.chall, "local", KEY.public_key())) - - @mock.patch("acme.challenges.dns.resolver.query") - def test_simple_verify_connection_error(self, mock_dns): - mock_dns.side_effect = dns.exception.DNSException + mock_dns.return_value = ["!"] self.assertFalse(self.response.simple_verify( self.chall, "local", KEY.public_key())) diff --git a/acme/acme/dns_resolver.py b/acme/acme/dns_resolver.py new file mode 100644 index 000000000..04e52224e --- /dev/null +++ b/acme/acme/dns_resolver.py @@ -0,0 +1,28 @@ +"""DNS Resolver for ACME client. +Required only for local validation of 'dns-01' challenges. +""" +import logging + +import dns.resolver +import dns.exception + +logger = logging.getLogger(__name__) + +def txt_records_for_name(name): + """Resolve the name and return the TXT records. + + :param unicode name: Domain name being verified. + + :returns: A list of txt records, if empty the name could not be resolved + :rtype: list of unicode + + """ + try: + dns_response = dns.resolver.query(name, 'TXT') + except ImportError as error: + raise ImportError("Local validation for 'dns-01' challenges requires " + "'dnspython'") + except dns.exception.DNSException as error: + logger.error("Unable to resolve %s: %s", name, str(error)) + return [] + return [txt_rec for rdata in dns_response for txt_rec in rdata.strings] diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py new file mode 100644 index 000000000..d1daa2d37 --- /dev/null +++ b/acme/acme/dns_resolver_test.py @@ -0,0 +1,37 @@ +"""Tests for acme.dns_resolver.""" +import unittest + +import dns +import mock + +from acme import dns_resolver + +class TxtRecordsForNameTest(unittest.TestCase): + + def create_txt_response(self, name, txt_records): + """ + Returns an RRSet containing the 'txt_records' as the result of a DNS + query for 'name'. + + This takes advantage of the fact that an Answer object mostly behaves + like an RRset. + """ + return dns.rrset.from_text_list(name, 60, "IN", "TXT", txt_records) + + @mock.patch("acme.dns_resolver.dns.resolver.query") + def test_txt_records_for_name_test_with_single_response(self, mock_dns): + mock_dns.return_value = self.create_txt_response('name', ['response']) + self.assertEqual(['response'], + dns_resolver.txt_records_for_name('name')) + + @mock.patch("acme.dns_resolver.dns.resolver.query") + def test_txt_records_for_name_with_multiple_responses(self, mock_dns): + mock_dns.return_value = self.create_txt_response( + 'name', ['response1', 'response2']) + self.assertEqual(['response1', 'response2'], + dns_resolver.txt_records_for_name('name')) + + @mock.patch("acme.dns_resolver.dns.resolver.query") + def test_txt_records_for_name_domain_not_found(self, mock_dns): + mock_dns.side_effect = dns.exception.DNSException + self.assertEquals([], dns_resolver.txt_records_for_name('name')) From a9a5e60bc59a65fb8d02f60f88946f1bafcc655c Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 01:26:32 -0500 Subject: [PATCH 013/264] Added requirements for coverage and lint. --- acme/acme/challenges.py | 2 +- acme/acme/dns_resolver_test.py | 2 +- acme/setup.py | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 221eb406c..22bda6445 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -245,7 +245,7 @@ class DNS01Response(KeyAuthorizationChallengeResponse): from acme import dns_resolver txt_records = dns_resolver.txt_records_for_name( validation_domain_name) - except ImportError as error: + except ImportError: raise ImportError("Local validation for 'dns-01' challenges " "requires 'dnspython'") exists = validation in txt_records diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index d1daa2d37..2202ce4e8 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -23,7 +23,7 @@ class TxtRecordsForNameTest(unittest.TestCase): mock_dns.return_value = self.create_txt_response('name', ['response']) self.assertEqual(['response'], dns_resolver.txt_records_for_name('name')) - + @mock.patch("acme.dns_resolver.dns.resolver.query") def test_txt_records_for_name_with_multiple_responses(self, mock_dns): mock_dns.return_value = self.create_txt_response( diff --git a/acme/setup.py b/acme/setup.py index e00476117..269d9e1fd 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -74,7 +74,9 @@ setup( include_package_data=True, install_requires=install_requires, extras_require={ + 'coverage': ['dnspython'], 'docs': docs_extras, + 'lint': ['dnspython'], 'testing': testing_extras + ['dnspython'], }, entry_points={ From d2ced2de6aa31d6fe2aab4b68a7feb89aad307d1 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 01:48:12 -0500 Subject: [PATCH 014/264] Dep fixes for lint/coverage. --- acme/setup.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 269d9e1fd..e4a525605 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -35,6 +35,10 @@ if sys.version_info < (2, 7, 9): install_requires.append('ndg-httpsclient') install_requires.append('pyasn1') +dev_extras = [ + 'dnspython', +] + docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', @@ -42,6 +46,7 @@ docs_extras = [ ] testing_extras = [ + 'dnspython', 'nose', 'tox', ] @@ -74,10 +79,9 @@ setup( include_package_data=True, install_requires=install_requires, extras_require={ - 'coverage': ['dnspython'], + 'dev': dev_extras, 'docs': docs_extras, - 'lint': ['dnspython'], - 'testing': testing_extras + ['dnspython'], + 'testing': testing_extras, }, entry_points={ 'console_scripts': [ From 52c487f462067ca810f3f3b840876306dfd1e9b1 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 02:44:19 -0500 Subject: [PATCH 015/264] Add new 'test' extras and update tox.ini accordingly. --- acme/acme/challenges_test.py | 5 ++--- acme/setup.py | 5 ++--- tox.ini | 10 +++++----- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index 0fc8fcef7..ac94619b5 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -135,9 +135,8 @@ class DNS01Test(unittest.TestCase): def setUp(self): from acme.challenges import DNS01 - self.msg = DNS01( - token=jose.decode_b64jose( - 'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ+PCt92wr+oA')) + self.msg = DNS01(token=jose.decode_b64jose( + 'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ+PCt92wr+oA')) self.jmsg = { 'type': 'dns-01', 'token': 'evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA', diff --git a/acme/setup.py b/acme/setup.py index e4a525605..3cb69ce9e 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -35,7 +35,7 @@ if sys.version_info < (2, 7, 9): install_requires.append('ndg-httpsclient') install_requires.append('pyasn1') -dev_extras = [ +dns_extras = [ 'dnspython', ] @@ -46,7 +46,6 @@ docs_extras = [ ] testing_extras = [ - 'dnspython', 'nose', 'tox', ] @@ -79,7 +78,7 @@ setup( include_package_data=True, install_requires=install_requires, extras_require={ - 'dev': dev_extras, + 'dns': dns_extras, 'docs': docs_extras, 'testing': testing_extras, }, diff --git a/tox.ini b/tox.ini index 1abe1cf39..98e185cfa 100644 --- a/tox.ini +++ b/tox.ini @@ -33,23 +33,23 @@ setenv = [testenv:py33] commands = - pip install -e acme[testing] + pip install -e acme[dev,testing] nosetests -v acme [testenv:py34] commands = - pip install -e acme[testing] + pip install -e acme[dev,testing] nosetests -v acme [testenv:py35] commands = - pip install -e acme[testing] + pip install -e acme[dev,testing] nosetests -v acme [testenv:cover] basepython = python2.7 commands = - pip install -e acme -e .[testing] -e letsencrypt-apache -e letsencrypt-nginx -e letshelp-letsencrypt + pip install -e acme[dns] -e .[testing] -e letsencrypt-apache -e letsencrypt-nginx -e letshelp-letsencrypt ./tox.cover.sh [testenv:lint] @@ -59,7 +59,7 @@ 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 -e acme -e .[dev] -e letsencrypt-apache -e letsencrypt-nginx -e letsencrypt-compatibility-test -e letshelp-letsencrypt + pip install -e acme -e .[dns,dev] -e letsencrypt-apache -e letsencrypt-nginx -e letsencrypt-compatibility-test -e letshelp-letsencrypt ./pep8.travis.sh pylint --rcfile=.pylintrc letsencrypt pylint --rcfile=.pylintrc acme/acme From cead22f4a7d46ff921a66bd049317c78733c596b Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 02:45:20 -0500 Subject: [PATCH 016/264] Add dns env to lint/cover --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 98e185cfa..a1ed23cf7 100644 --- a/tox.ini +++ b/tox.ini @@ -59,7 +59,7 @@ 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 -e acme -e .[dns,dev] -e letsencrypt-apache -e letsencrypt-nginx -e letsencrypt-compatibility-test -e letshelp-letsencrypt + pip install -e acme[dns] -e .[dns,dev] -e letsencrypt-apache -e letsencrypt-nginx -e letsencrypt-compatibility-test -e letshelp-letsencrypt ./pep8.travis.sh pylint --rcfile=.pylintrc letsencrypt pylint --rcfile=.pylintrc acme/acme From e61e83f7e26803b556c7e6620cd014779d1f5e36 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 02:46:29 -0500 Subject: [PATCH 017/264] tox.ini fix --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index a1ed23cf7..cdc2c2396 100644 --- a/tox.ini +++ b/tox.ini @@ -59,7 +59,7 @@ 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 -e acme[dns] -e .[dns,dev] -e letsencrypt-apache -e letsencrypt-nginx -e letsencrypt-compatibility-test -e letshelp-letsencrypt + pip install -e acme[dns] -e .[dev] -e letsencrypt-apache -e letsencrypt-nginx -e letsencrypt-compatibility-test -e letshelp-letsencrypt ./pep8.travis.sh pylint --rcfile=.pylintrc letsencrypt pylint --rcfile=.pylintrc acme/acme From b8a9c2597c4ba6a02ed9b530c1286a1c24b7ccac Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 02:57:53 -0500 Subject: [PATCH 018/264] add dns environment to pyXX --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index cdc2c2396..4a7aea0d0 100644 --- a/tox.ini +++ b/tox.ini @@ -33,17 +33,17 @@ setenv = [testenv:py33] commands = - pip install -e acme[dev,testing] + pip install -e acme[dns,testing] nosetests -v acme [testenv:py34] commands = - pip install -e acme[dev,testing] + pip install -e acme[dns,testing] nosetests -v acme [testenv:py35] commands = - pip install -e acme[dev,testing] + pip install -e acme[dns,testing] nosetests -v acme [testenv:cover] From b73b410729e90bf0c6c1882130f6c0759675d7c3 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 02:59:25 -0500 Subject: [PATCH 019/264] Exclude import error case from coverage in dns_resolver --- acme/acme/dns_resolver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme/dns_resolver.py b/acme/acme/dns_resolver.py index 04e52224e..e28f132f1 100644 --- a/acme/acme/dns_resolver.py +++ b/acme/acme/dns_resolver.py @@ -19,7 +19,7 @@ def txt_records_for_name(name): """ try: dns_response = dns.resolver.query(name, 'TXT') - except ImportError as error: + except ImportError as error: # pragma: no cover raise ImportError("Local validation for 'dns-01' challenges requires " "'dnspython'") except dns.exception.DNSException as error: From 6bc3060fbb6a3d248654b6f97c004ce682e1e52f Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 03:11:09 -0500 Subject: [PATCH 020/264] More fixes for travis tests --- acme/acme/challenges.py | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 22bda6445..08d847627 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -245,7 +245,7 @@ class DNS01Response(KeyAuthorizationChallengeResponse): from acme import dns_resolver txt_records = dns_resolver.txt_records_for_name( validation_domain_name) - except ImportError: + except ImportError: # pragma: no cover raise ImportError("Local validation for 'dns-01' challenges " "requires 'dnspython'") exists = validation in txt_records diff --git a/tox.ini b/tox.ini index 4a7aea0d0..c0a819b5e 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ envlist = py26,py27,py33,py34,py35,cover,lint # packages installed separately to ensure that dowstream deps problems # are detected, c.f. #1002 commands = - pip install -e acme[testing] + pip install -e acme[dns,testing] nosetests -v acme pip install -e .[testing] nosetests -v letsencrypt From 02a493011ef039ca6ec1d52d9c87d4317afe0d12 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Wed, 6 Jan 2016 22:56:59 -0500 Subject: [PATCH 021/264] Remove superfluous except: and change Exception returned if dnspython is not available. --- acme/acme/challenges.py | 4 ++-- acme/acme/dns_resolver.py | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 08d847627..3a78e403a 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -246,8 +246,8 @@ class DNS01Response(KeyAuthorizationChallengeResponse): txt_records = dns_resolver.txt_records_for_name( validation_domain_name) except ImportError: # pragma: no cover - raise ImportError("Local validation for 'dns-01' challenges " - "requires 'dnspython'") + raise errors.Error("Local validation for 'dns-01' challenges " + "requires 'dnspython'") exists = validation in txt_records if not exists: logger.debug("Key authorization from response (%r) doesn't match " diff --git a/acme/acme/dns_resolver.py b/acme/acme/dns_resolver.py index e28f132f1..3572ee277 100644 --- a/acme/acme/dns_resolver.py +++ b/acme/acme/dns_resolver.py @@ -19,9 +19,6 @@ def txt_records_for_name(name): """ try: dns_response = dns.resolver.query(name, 'TXT') - except ImportError as error: # pragma: no cover - raise ImportError("Local validation for 'dns-01' challenges requires " - "'dnspython'") except dns.exception.DNSException as error: logger.error("Unable to resolve %s: %s", name, str(error)) return [] From 446994e8ef11a860ac94a52751bc51a9fded6b04 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sat, 9 Jan 2016 14:58:19 -0500 Subject: [PATCH 022/264] Limit length of try block. --- acme/acme/challenges.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 3a78e403a..493d230d8 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -243,11 +243,10 @@ class DNS01Response(KeyAuthorizationChallengeResponse): try: from acme import dns_resolver - txt_records = dns_resolver.txt_records_for_name( - validation_domain_name) except ImportError: # pragma: no cover raise errors.Error("Local validation for 'dns-01' challenges " "requires 'dnspython'") + txt_records = dns_resolver.txt_records_for_name(validation_domain_name) exists = validation in txt_records if not exists: logger.debug("Key authorization from response (%r) doesn't match " From 56154f1301725dff575e22011a81ca18d5729307 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sat, 9 Jan 2016 16:43:43 -0500 Subject: [PATCH 023/264] - Use dnspython3 fir py3X environments. - Fix encoding for simple_verify. --- acme/acme/challenges.py | 4 ++-- acme/setup.py | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 493d230d8..3fa259b13 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -271,8 +271,8 @@ class DNS01(KeyAuthorizationChallenge): :rtype: unicode """ - return jose.b64encode(hashlib.sha256( - self.key_authorization(account_key)).digest()) + return jose.b64encode(hashlib.sha256(self.key_authorization( + account_key).encode("utf-8")).digest()).decode() def validation_domain_name(self, name): """Domain name for TXT validation record. diff --git a/acme/setup.py b/acme/setup.py index c54dc42e6..df5cfba0e 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -35,9 +35,14 @@ if sys.version_info < (2, 7, 9): install_requires.append('ndg-httpsclient') install_requires.append('pyasn1') -dns_extras = [ - 'dnspython', -] +if sys.version_info < (3, 0): + dns_extras = [ + 'dnspython', + ] +else: + dns_extras = [ + 'dnspython3', + ] docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags From d842f268e5414f418e69913f6ac4fadffb327fb1 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sat, 9 Jan 2016 17:07:20 -0500 Subject: [PATCH 024/264] - Use dnspython3 fir py3X environments. - Fix encoding for simple_verify. --- acme/acme/challenges.py | 4 ++-- acme/setup.py | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 493d230d8..3fa259b13 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -271,8 +271,8 @@ class DNS01(KeyAuthorizationChallenge): :rtype: unicode """ - return jose.b64encode(hashlib.sha256( - self.key_authorization(account_key)).digest()) + return jose.b64encode(hashlib.sha256(self.key_authorization( + account_key).encode("utf-8")).digest()).decode() def validation_domain_name(self, name): """Domain name for TXT validation record. diff --git a/acme/setup.py b/acme/setup.py index c54dc42e6..df5cfba0e 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -35,9 +35,14 @@ if sys.version_info < (2, 7, 9): install_requires.append('ndg-httpsclient') install_requires.append('pyasn1') -dns_extras = [ - 'dnspython', -] +if sys.version_info < (3, 0): + dns_extras = [ + 'dnspython', + ] +else: + dns_extras = [ + 'dnspython3', + ] docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags From b7c00a889a607add72823aa20ccf4874a585a8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20B=C3=B6gershausen?= Date: Sun, 10 Jan 2016 18:31:49 +0100 Subject: [PATCH 025/264] .gitattributes: EOL=LF overrides auto The line * text=auto eol=lf in .gitattributes does not work as expected: setting eol=lf overrides text=auto, and works as * eol=lf or * text eol=lf This is not what is intended, as binary files like *.gz go through a CRLF -> LF conversion at commit time. Use * crlf=auto instead (which is even understood by older Git versions, which are still in use) --- .gitattributes | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 5eee84cce..2a18bd183 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,15 @@ -* text=auto eol=lf +#Default, normalize CRLF into LF in non-binary files +# Files identified as binary by Git are not changed +* crlf=auto # special files +*.sh crlf=input +*.py crlf=input + *.bat text eol=crlf + +*.der binary +*.gz binary *.jpeg binary *.jpg binary *.png binary From f2b52bd830457200474e98394b8aff0315e9d51f Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sun, 10 Jan 2016 12:58:29 -0500 Subject: [PATCH 026/264] Fix dcumentation --- acme/acme/challenges.py | 1 - 1 file changed, 1 deletion(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 3fa259b13..a5b142c5b 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -226,7 +226,6 @@ class DNS01Response(KeyAuthorizationChallengeResponse): :param unicode domain: Domain name being verified. :param account_public_key: Public key for the key pair being authorized. - :param JWK account_public_key: :returns: ``True`` iff validation with the TXT records resolved from a DNS server is successful. From 49c40e7a584d1d8faeac4436c6c7787e44a12b6d Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sun, 10 Jan 2016 13:00:38 -0500 Subject: [PATCH 027/264] Skip dns_resolver tests if dnspython is not available. --- acme/acme/dns_resolver_test.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index 2202ce4e8..0d5cc2543 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -1,11 +1,17 @@ """Tests for acme.dns_resolver.""" import unittest -import dns import mock +try: + import dns +except ImportError: + dns = None + from acme import dns_resolver +@unittest.skipIf(dns is None, + "dnspython is not available, skipping dns_resolver tests") class TxtRecordsForNameTest(unittest.TestCase): def create_txt_response(self, name, txt_records): From cfe56cbd925a4c90a051355f4f891ee8f15308d0 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sun, 10 Jan 2016 17:00:14 -0500 Subject: [PATCH 028/264] 2.6 compatible skipping of tests. --- acme/acme/dns_resolver_test.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index 0d5cc2543..54f074a92 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -1,17 +1,15 @@ """Tests for acme.dns_resolver.""" import unittest - import mock -try: - import dns -except ImportError: - dns = None - from acme import dns_resolver -@unittest.skipIf(dns is None, - "dnspython is not available, skipping dns_resolver tests") +try: + import dns +except ImportError: # pragma: no cover + dns = None + + class TxtRecordsForNameTest(unittest.TestCase): def create_txt_response(self, name, txt_records): @@ -41,3 +39,9 @@ class TxtRecordsForNameTest(unittest.TestCase): def test_txt_records_for_name_domain_not_found(self, mock_dns): mock_dns.side_effect = dns.exception.DNSException self.assertEquals([], dns_resolver.txt_records_for_name('name')) + + def run(self, result=None): + if dns is None: + print self, "... SKIPPING, no dnspython available" + return + super(TxtRecordsForNameTest, self).run(result) From 0010610a4a038fd592c0544d02fd0f36a8ff3495 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sun, 10 Jan 2016 17:06:03 -0500 Subject: [PATCH 029/264] py3X fix --- acme/acme/dns_resolver_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index 54f074a92..8e92cd4a3 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -42,6 +42,6 @@ class TxtRecordsForNameTest(unittest.TestCase): def run(self, result=None): if dns is None: - print self, "... SKIPPING, no dnspython available" + print(self, "... SKIPPING, no dnspython available") return super(TxtRecordsForNameTest, self).run(result) From 2d8de74f4abd659cad518ec5d74d8613fe9830ac Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sun, 10 Jan 2016 17:13:25 -0500 Subject: [PATCH 030/264] pcoverage fix --- acme/acme/dns_resolver_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index 8e92cd4a3..770a95a77 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -7,7 +7,7 @@ from acme import dns_resolver try: import dns except ImportError: # pragma: no cover - dns = None + dns = Nones class TxtRecordsForNameTest(unittest.TestCase): @@ -41,7 +41,7 @@ class TxtRecordsForNameTest(unittest.TestCase): self.assertEquals([], dns_resolver.txt_records_for_name('name')) def run(self, result=None): - if dns is None: + if dns is None: # pragma: no cover print(self, "... SKIPPING, no dnspython available") return super(TxtRecordsForNameTest, self).run(result) From 1ff121b616c8d599549be19a07bd45fb8429fc49 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sun, 10 Jan 2016 18:08:16 -0500 Subject: [PATCH 031/264] pcoverage fix --- acme/acme/dns_resolver_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index 770a95a77..5d160fc07 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -7,7 +7,7 @@ from acme import dns_resolver try: import dns except ImportError: # pragma: no cover - dns = Nones + dns = None class TxtRecordsForNameTest(unittest.TestCase): From 9179276cb982945f6d6083b26d7a55d0112894e9 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sun, 10 Jan 2016 20:59:11 -0500 Subject: [PATCH 032/264] Modify dns_resolver_test to skip tests if dnspython is not available. --- acme/acme/dns_resolver_test.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index 2202ce4e8..5d160fc07 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -1,11 +1,15 @@ """Tests for acme.dns_resolver.""" import unittest - -import dns import mock from acme import dns_resolver +try: + import dns +except ImportError: # pragma: no cover + dns = None + + class TxtRecordsForNameTest(unittest.TestCase): def create_txt_response(self, name, txt_records): @@ -35,3 +39,9 @@ class TxtRecordsForNameTest(unittest.TestCase): def test_txt_records_for_name_domain_not_found(self, mock_dns): mock_dns.side_effect = dns.exception.DNSException self.assertEquals([], dns_resolver.txt_records_for_name('name')) + + def run(self, result=None): + if dns is None: # pragma: no cover + print(self, "... SKIPPING, no dnspython available") + return + super(TxtRecordsForNameTest, self).run(result) From 05a61c181b277d4a3f94abe038da0fda549faeda Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sun, 10 Jan 2016 21:42:20 -0500 Subject: [PATCH 033/264] Lint fixes. --- acme/acme/challenges_test.py | 2 +- acme/acme/dns_resolver_test.py | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index ac94619b5..b32bebed0 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -114,7 +114,7 @@ class DNS01ResponseTest(unittest.TestCase): self.assertTrue(self.response.simple_verify( self.chall, "local", KEY.public_key())) mock_resolver.assert_called_once_with( - self.chall.validation_domain_name("local")) + self.chall.validation_domain_name("local")) @mock.patch("acme.dns_resolver.txt_records_for_name") def test_simple_verify_good_validation_multiple_txts(self, mock_resolver): diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index 5d160fc07..39645c492 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -9,28 +9,28 @@ try: except ImportError: # pragma: no cover dns = None +def create_txt_response(name, txt_records): + """ + Returns an RRSet containing the 'txt_records' as the result of a DNS + query for 'name'. + + This takes advantage of the fact that an Answer object mostly behaves + like an RRset. + """ + return dns.rrset.from_text_list(name, 60, "IN", "TXT", txt_records) + class TxtRecordsForNameTest(unittest.TestCase): - def create_txt_response(self, name, txt_records): - """ - Returns an RRSet containing the 'txt_records' as the result of a DNS - query for 'name'. - - This takes advantage of the fact that an Answer object mostly behaves - like an RRset. - """ - return dns.rrset.from_text_list(name, 60, "IN", "TXT", txt_records) - @mock.patch("acme.dns_resolver.dns.resolver.query") - def test_txt_records_for_name_test_with_single_response(self, mock_dns): - mock_dns.return_value = self.create_txt_response('name', ['response']) + def test_txt_records_for_name_with_single_response(self, mock_dns): + mock_dns.return_value = create_txt_response('name', ['response']) self.assertEqual(['response'], dns_resolver.txt_records_for_name('name')) @mock.patch("acme.dns_resolver.dns.resolver.query") def test_txt_records_for_name_with_multiple_responses(self, mock_dns): - mock_dns.return_value = self.create_txt_response( + mock_dns.return_value = create_txt_response( 'name', ['response1', 'response2']) self.assertEqual(['response1', 'response2'], dns_resolver.txt_records_for_name('name')) From c15581bcfd4b9ffe8d1e1ceb03e316c337691524 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Thu, 14 Jan 2016 23:37:05 -0500 Subject: [PATCH 034/264] Fix lint problems. --- acme/acme/challenges_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index 39f7449f2..af4b81f80 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -119,7 +119,8 @@ class DNS01ResponseTest(unittest.TestCase): @mock.patch("acme.dns_resolver.txt_records_for_name") def test_simple_verify_good_validation_multiple_txts(self, mock_resolver): - mock_resolver.return_value = ["!", self.chall.validation(KEY.public_key())] + mock_resolver.return_value = [ + "!", self.chall.validation(KEY.public_key())] self.assertTrue(self.response.simple_verify( self.chall, "local", KEY.public_key())) mock_resolver.assert_called_once_with( From 7c3271545fe48de9c67b2781ab1fd58328e4e095 Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Sat, 13 Feb 2016 01:05:35 -0500 Subject: [PATCH 035/264] Do not log an error when getting NXDOMAIN. --- acme/acme/dns_resolver.py | 4 +++- acme/acme/dns_resolver_test.py | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/acme/acme/dns_resolver.py b/acme/acme/dns_resolver.py index 3572ee277..badbf486a 100644 --- a/acme/acme/dns_resolver.py +++ b/acme/acme/dns_resolver.py @@ -19,7 +19,9 @@ def txt_records_for_name(name): """ try: dns_response = dns.resolver.query(name, 'TXT') + except dns.resolver.NXDOMAIN as error: + return [] except dns.exception.DNSException as error: - logger.error("Unable to resolve %s: %s", name, str(error)) + logger.error("Error resolving %s: %s", name, str(error)) return [] return [txt_rec for rdata in dns_response for txt_rec in rdata.strings] diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index 80481343d..53fc0cc77 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -38,6 +38,11 @@ class TxtRecordsForNameTest(unittest.TestCase): @mock.patch("acme.dns_resolver.dns.resolver.query") def test_txt_records_for_name_domain_not_found(self, mock_dns): + mock_dns.side_effect = dns.resolver.NXDOMAIN + self.assertEquals([], dns_resolver.txt_records_for_name('name')) + + @mock.patch("acme.dns_resolver.dns.resolver.query") + def test_txt_records_for_name_domain_other_error(self, mock_dns): mock_dns.side_effect = dns.exception.DNSException self.assertEquals([], dns_resolver.txt_records_for_name('name')) From ac2ec3457df6b699916864f26a89a1cc6fcadd9d Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 5 Apr 2016 11:33:33 -0700 Subject: [PATCH 036/264] NcursesDisplay.menu: treat ESC as cancel Currently it will fire a weird traceback like: File "/home/ubuntu/letsencrypt/letsencrypt/plugins/selection.py", line 113, in choose_plugin code, index = disp.menu(question, opts, help_label="More Info") File "/home/ubuntu/letsencrypt/letsencrypt/display/util.py", line 129, in menu return code, int(index) - 1 ValueError: invalid literal for int() with base 10: '' --- letsencrypt/display/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/display/util.py b/letsencrypt/display/util.py index 20c6be156..40dd00f8b 100644 --- a/letsencrypt/display/util.py +++ b/letsencrypt/display/util.py @@ -123,7 +123,7 @@ class NcursesDisplay(object): # pylint: disable=star-args code, index = self.dialog.menu(message, **menu_options) - if code == CANCEL: + if code == CANCEL or index == "": return code, -1 return code, int(index) - 1 From 9396e92a966cbc07c0a69b7148f760b4337823dd Mon Sep 17 00:00:00 2001 From: Wilfried Teiken Date: Mon, 25 Apr 2016 00:46:45 -0400 Subject: [PATCH 037/264] Fix lint issues. --- acme/acme/challenges.py | 1 - acme/acme/dns_resolver.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index d27719449..f611578dd 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -599,4 +599,3 @@ class DNSResponse(ChallengeResponse): """ return chall.check_validation(self.validation, account_public_key) - diff --git a/acme/acme/dns_resolver.py b/acme/acme/dns_resolver.py index badbf486a..15638e5d0 100644 --- a/acme/acme/dns_resolver.py +++ b/acme/acme/dns_resolver.py @@ -8,6 +8,7 @@ import dns.exception logger = logging.getLogger(__name__) + def txt_records_for_name(name): """Resolve the name and return the TXT records. From ecbff9e60d7913be893f1931ccd5e19fe3ab00f9 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 9 May 2016 14:40:03 -0700 Subject: [PATCH 038/264] migrate packaging info --- docs/packaging.rst | 77 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/docs/packaging.rst b/docs/packaging.rst index 5f09b65fa..c0baf6232 100644 --- a/docs/packaging.rst +++ b/docs/packaging.rst @@ -2,5 +2,78 @@ Packaging Guide =============== -Documentation can be found at -https://github.com/letsencrypt/letsencrypt/wiki/Packaging. +## Releases + +We release packages and upload them to PyPI (wheels and source tarballs). + +- https://pypi.python.org/pypi/acme +- https://pypi.python.org/pypi/letsencrypt +- https://pypi.python.org/pypi/letsencrypt-apache +- https://pypi.python.org/pypi/letsencrypt-nginx +- https://pypi.python.org/pypi/letshelp-letsencrypt + +The following scripts are used in the process: + +- https://github.com/letsencrypt/letsencrypt/blob/master/tools/release.sh +- https://gist.github.com/kuba/b9a3a2ca3bd35b8368ef + +We currently version as `0.0.0.devYYYYMMDD`, and will change at GA time to the following scheme: +- `0.1.0` +- `0.2.0dev` for developement in `master` +- `0.2.0` (only temporarily in `master`) +- ... + +Tracking issue for non-dev release scripts: https://github.com/letsencrypt/letsencrypt/issues/1185 + +## Notes for package maintainers + +0. Please use our releases, not `master`! + +1. Do not package `letsencrypt-compatibility-test` - it's only used internally. + +2. `letsencrypt-renewer` should be added to crontab... but it currently doesn't work well + +3. `letsencrypt.client` provides developer API so it should be possible to `import letsencrypt.client` when the package is installed (`letsencrypt` vs `python-letsencrypt` debate for Debian). + +4. `jws` is an internal script for `acme` module and it doesn't have to be packaged - it's mostly for debugging: you can use it as `echo foo | jws sign | jws verify`. + +5. Do get in touch with us. We are happy to make any changes that will make packaging easier. If you need to apply some patches don't do it downstream - make a PR here. + +## Already ongoing efforts + + + +### Arch + +From PyPI: +- https://www.archlinux.org/packages/community/any/python2-acme +- https://www.archlinux.org/packages/community/any/letsencrypt +- https://www.archlinux.org/packages/community/any/letsencrypt-apache +- https://www.archlinux.org/packages/community/any/letsencrypt-nginx +- https://www.archlinux.org/packages/community/any/letshelp-letsencrypt + +From `master`: https://aur.archlinux.org/packages/letsencrypt-git + +### Debian (and its derivatives, including Ubuntu) + +https://alioth.debian.org/projects/letsencrypt/ + +### Fedora +In Fedora 23+. + +- https://admin.fedoraproject.org/pkgdb/package/letsencrypt/ +- https://admin.fedoraproject.org/pkgdb/package/python-acme/ +- https://bugzilla.redhat.com/show_bug.cgi?id=1287193 (review request, closed) + +### FreeBSD + +https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=203405 + +### GNU Guix +- https://www.gnu.org/software/guix/package-list.html#letsencrypt + +### OpenBSD + +- http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/security/letsencrypt/ +- https://github.com/letsencrypt/letsencrypt/pull/1175 +- https://github.com/letsencrypt/letsencrypt/issues/1174 From 05131da32e6f88101c300aebfb7e4f3e7eec4263 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 9 May 2016 14:44:26 -0700 Subject: [PATCH 039/264] make code blocks code blocks --- docs/packaging.rst | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/packaging.rst b/docs/packaging.rst index c0baf6232..8ec7d7fca 100644 --- a/docs/packaging.rst +++ b/docs/packaging.rst @@ -2,7 +2,8 @@ Packaging Guide =============== -## Releases +Releases +======== We release packages and upload them to PyPI (wheels and source tarballs). @@ -17,25 +18,25 @@ The following scripts are used in the process: - https://github.com/letsencrypt/letsencrypt/blob/master/tools/release.sh - https://gist.github.com/kuba/b9a3a2ca3bd35b8368ef -We currently version as `0.0.0.devYYYYMMDD`, and will change at GA time to the following scheme: -- `0.1.0` -- `0.2.0dev` for developement in `master` -- `0.2.0` (only temporarily in `master`) +We currently version as ``0.0.0.devYYYYMMDD``, and will change at GA time to the following scheme: +- ``0.1.0`` +- ``0.2.0dev`` for developement in ``master`` +- ``0.2.0`` (only temporarily in ``master``) - ... Tracking issue for non-dev release scripts: https://github.com/letsencrypt/letsencrypt/issues/1185 ## Notes for package maintainers -0. Please use our releases, not `master`! +0. Please use our releases, not ``master``! -1. Do not package `letsencrypt-compatibility-test` - it's only used internally. +1. Do not package ``letsencrypt-compatibility-test`` - it's only used internally. -2. `letsencrypt-renewer` should be added to crontab... but it currently doesn't work well +2. ``letsencrypt-renewer`` should be added to crontab... but it currently doesn't work well -3. `letsencrypt.client` provides developer API so it should be possible to `import letsencrypt.client` when the package is installed (`letsencrypt` vs `python-letsencrypt` debate for Debian). +3. ``letsencrypt.client`` provides developer API so it should be possible to ``import letsencrypt.client`` when the package is installed (``letsencrypt`` vs ``python-letsencrypt`` debate for Debian). -4. `jws` is an internal script for `acme` module and it doesn't have to be packaged - it's mostly for debugging: you can use it as `echo foo | jws sign | jws verify`. +4. ``jws`` is an internal script for ``acme`` module and it doesn't have to be packaged - it's mostly for debugging: you can use it as ``echo foo | jws sign | jws verify``. 5. Do get in touch with us. We are happy to make any changes that will make packaging easier. If you need to apply some patches don't do it downstream - make a PR here. @@ -52,7 +53,7 @@ From PyPI: - https://www.archlinux.org/packages/community/any/letsencrypt-nginx - https://www.archlinux.org/packages/community/any/letshelp-letsencrypt -From `master`: https://aur.archlinux.org/packages/letsencrypt-git +From ``master``: https://aur.archlinux.org/packages/letsencrypt-git ### Debian (and its derivatives, including Ubuntu) From 505b8854f67b95e84217a7833c02a92ee79191d2 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 9 May 2016 14:46:37 -0700 Subject: [PATCH 040/264] break sections correctly --- docs/packaging.rst | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/docs/packaging.rst b/docs/packaging.rst index 8ec7d7fca..0113fbbe6 100644 --- a/docs/packaging.rst +++ b/docs/packaging.rst @@ -19,6 +19,7 @@ The following scripts are used in the process: - https://gist.github.com/kuba/b9a3a2ca3bd35b8368ef We currently version as ``0.0.0.devYYYYMMDD``, and will change at GA time to the following scheme: + - ``0.1.0`` - ``0.2.0dev`` for developement in ``master`` - ``0.2.0`` (only temporarily in ``master``) @@ -26,7 +27,8 @@ We currently version as ``0.0.0.devYYYYMMDD``, and will change at GA time to the Tracking issue for non-dev release scripts: https://github.com/letsencrypt/letsencrypt/issues/1185 -## Notes for package maintainers +Notes for package maintainers +============================= 0. Please use our releases, not ``master``! @@ -40,11 +42,12 @@ Tracking issue for non-dev release scripts: https://github.com/letsencrypt/letse 5. Do get in touch with us. We are happy to make any changes that will make packaging easier. If you need to apply some patches don't do it downstream - make a PR here. -## Already ongoing efforts +Already ongoing efforts +----------------------- - -### Arch +Arch +==== From PyPI: - https://www.archlinux.org/packages/community/any/python2-acme @@ -55,25 +58,32 @@ From PyPI: From ``master``: https://aur.archlinux.org/packages/letsencrypt-git -### Debian (and its derivatives, including Ubuntu) +Debian (and its derivatives, including Ubuntu) +====== https://alioth.debian.org/projects/letsencrypt/ -### Fedora +Fedora +====== + In Fedora 23+. - https://admin.fedoraproject.org/pkgdb/package/letsencrypt/ - https://admin.fedoraproject.org/pkgdb/package/python-acme/ - https://bugzilla.redhat.com/show_bug.cgi?id=1287193 (review request, closed) -### FreeBSD +FreeBSD +======= https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=203405 -### GNU Guix +GNU Guix +======== + - https://www.gnu.org/software/guix/package-list.html#letsencrypt -### OpenBSD +OpenBSD +======= - http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/security/letsencrypt/ - https://github.com/letsencrypt/letsencrypt/pull/1175 From c4c1fa3a26b8291532d936f194b89a4ffea45081 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 9 May 2016 14:48:28 -0700 Subject: [PATCH 041/264] switch size of subheadings --- docs/packaging.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/packaging.rst b/docs/packaging.rst index 0113fbbe6..6bf359bf2 100644 --- a/docs/packaging.rst +++ b/docs/packaging.rst @@ -43,11 +43,11 @@ Notes for package maintainers 5. Do get in touch with us. We are happy to make any changes that will make packaging easier. If you need to apply some patches don't do it downstream - make a PR here. Already ongoing efforts ------------------------ +======================= Arch -==== +---- From PyPI: - https://www.archlinux.org/packages/community/any/python2-acme @@ -59,12 +59,12 @@ From PyPI: From ``master``: https://aur.archlinux.org/packages/letsencrypt-git Debian (and its derivatives, including Ubuntu) -====== +------ https://alioth.debian.org/projects/letsencrypt/ Fedora -====== +------ In Fedora 23+. @@ -73,17 +73,17 @@ In Fedora 23+. - https://bugzilla.redhat.com/show_bug.cgi?id=1287193 (review request, closed) FreeBSD -======= +------- https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=203405 GNU Guix -======== +-------- - https://www.gnu.org/software/guix/package-list.html#letsencrypt OpenBSD -======= +------- - http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/security/letsencrypt/ - https://github.com/letsencrypt/letsencrypt/pull/1175 From 63c79f98ca44453c3fe68c37ddcacb5b7bed938c Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Wed, 18 May 2016 10:59:58 +0300 Subject: [PATCH 042/264] Remove dangling footnote This footnote has no references! --- docs/using.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 12ea3ea11..e81aca16a 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -552,10 +552,3 @@ Beyond the methods discussed here, other methods may be possible, such as installing Certbot directly with pip from PyPI or downloading a ZIP archive from GitHub may be technically possible but are not presently recommended or supported. - - -.. rubric:: Footnotes - -.. [#venv] By using this virtualized Python environment (`virtualenv - `_) we don't pollute the main - OS space with packages from PyPI! From 12a356298c6217e5b9934262742ebed04c1ddfec Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Wed, 25 May 2016 20:34:38 +0200 Subject: [PATCH 043/264] Displaying DialogError details correctly --- certbot/main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/certbot/main.py b/certbot/main.py index fa5d43b72..b5407370a 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -623,7 +623,11 @@ def _handle_exception(exc_type, exc_value, trace, config): # Here we're passing a client or ACME error out to the client at the shell # Tell the user a bit about what happened, without overwhelming # them with a full traceback - err = traceback.format_exception_only(exc_type, exc_value)[0] + from dialog import DialogError + if issubclass(exc_type, DialogError): + err = exc_value.complete_message() + else: + err = traceback.format_exception_only(exc_type, exc_value)[0] # Typical error from the ACME module: # acme.messages.Error: urn:acme:error:malformed :: The request message was # malformed :: Error creating new registration :: Validation of contact From 4a8f71277c51d8cb26970f98bdbbc8ee67396397 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 20 May 2016 21:25:44 +0200 Subject: [PATCH 044/264] Limiting tox envlist to really needed tests --- docs/contributing.rst | 3 +++ tox.ini | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 3318ec103..9ceb0fbdd 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -71,6 +71,9 @@ The following tools are there to help you: experimental, non-production Apache2 install on them. ``tox -e apacheconftest`` can be used to run those specific Apache conf tests. +- ``tox --skip-missing-interpreters`` runs tox while ignoring missing versions + of Python needed for running the tests. + - ``tox -e py27``, ``tox -e py26`` etc, run unit tests for specific Python versions. diff --git a/tox.ini b/tox.ini index 5c88dfd21..4067bada9 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ [tox] skipsdist = true -envlist = py{26,27,33,34,35},py{26,27}-oldest,cover,lint +envlist = py{26,33,34,35},cover,lint # nosetest -v => more verbose output, allows to detect busy waiting # loops, especially on Travis From 928ea2f5cb7edf22d77ff3bc4bbca1b36c92b7cd Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Sat, 28 May 2016 02:18:49 +0200 Subject: [PATCH 045/264] Fixing minute problems with code --- certbot/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot/main.py b/certbot/main.py index 235d7c3ff..9c8849cfe 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -1,6 +1,7 @@ """Certbot main entry point.""" from __future__ import print_function import atexit +import dialog import functools import logging.handlers import os @@ -623,8 +624,7 @@ def _handle_exception(exc_type, exc_value, trace, config): # Here we're passing a client or ACME error out to the client at the shell # Tell the user a bit about what happened, without overwhelming # them with a full traceback - from dialog import DialogError - if issubclass(exc_type, DialogError): + if issubclass(exc_type, dialog.error): err = exc_value.complete_message() else: err = traceback.format_exception_only(exc_type, exc_value)[0] From ec49afb7c05b5523b0eb8fc87f749478086d6a36 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 3 Jun 2016 16:45:24 -0700 Subject: [PATCH 046/264] UnspacedList: infrastructure for parsing but hiding nginx whitespace --- certbot-nginx/certbot_nginx/nginxparser.py | 68 +++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 1577c7b1e..f9348398a 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -1,4 +1,5 @@ """Very low-level nginx config parser based on pyparsing.""" +import copy import string from pyparsing import ( @@ -26,8 +27,8 @@ class RawNginxParser(object): modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~") # rules - comment = Literal('#') + restOfLine() - assignment = (key + Optional(space + value, default=None) + semicolon) + comment = White() + Literal('#') + restOfLine() + assignment = White() + key + Optional(space + value, default=None) + semicolon location_statement = Optional(space + modifier) + Optional(space + location) if_statement = Literal("if") + space + Regex(r"\(.+\)") + space map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space @@ -136,3 +137,66 @@ def dump(blocks, _file, indentation=4): """ return _file.write(dumps(blocks, indentation)) + + + +spacey = lambda x: isinstance(x, str) and x.isspace() + +class UnspacedList(list): + """Wrap a list [of lists], making any whitespace entries magically invisible""" + + def __init__(self, list_source): + self.spaced = copy.deepcopy(list(list_source)) + + # Turn self into a version of the source list that has spaces removed + # and all sub-lists also UnspaceList()ed + list.__init__(self, list_source) + for i, entry in reversed(list(enumerate(self))): + if isinstance(entry, list): + list.__setitem__(self, i, UnspacedList(entry)) + elif spacey(entry): + list.__delitem__(self, i) + + def insert(self, i, x): + self.spaced.insert(i + self._spaces_before(i), x) + list.insert(self, i, x) + + def append(self, x): + self.spaced.append(x) + list.append(self, x) + + def extend(self, x): + self.spaced.extend(x) + list.extend(self, x) + + def __add__(self, other): + if hasattr(other, "spaced"): + # If the thing added to us is an UnspacedList, use its spaced form + self.spaced.__add__(other.spaced) + else: + self.spaced.__add__(other) + list.__add__(self, other) + + def __setitem__(self, i, value): + self.spaced.__setitem__(i + self._spaces_before(i), value) + list.__setitem__(self, i, value) + + def __delitem__(self, i): + self.spaced.__delitem__(i + self._spaces_before(i)) + list.__delitem__(self, i) + + def _spaces_before(self, idx): + "Count the number of spaces in the spaced list before pos idx in the spaceless one" + spaces = 0 + pos = 0 + while idx != -1: + if spacey(self.spaced[pos]): + spaces += 1 + else: + idx -= 1 + pos += 1 + return spaces + + def with_spaces(self): + return self.spaced + From 111ca657d86e0caf31dbc81f83037a021fd22131 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Mon, 6 Jun 2016 21:17:02 +0200 Subject: [PATCH 047/264] Adding testing --- certbot/tests/cli_test.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 4ae69e69d..06aba4ab3 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -882,6 +882,15 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods mock_sys.exit.assert_called_with(''.join( traceback.format_exception_only(KeyboardInterrupt, interrupt))) + # Test dialog errors + + import dialog + exception = dialog.error(message="test message") + main._handle_exception( + dialog.DialogError, exc_value=exception, trace=None, config=None) + error_msg = mock_sys.exit.call_args_list[-1][0][0] + self.assertTrue("test message" in error_msg) + def test_read_file(self): rel_test_path = os.path.relpath(os.path.join(self.tmp_dir, 'foo')) self.assertRaises( From 0db7b5998b8abb5c70cc13bf2ed61b671fcdef0c Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 6 Jun 2016 15:15:52 -0700 Subject: [PATCH 048/264] fix broken link in contributing.rst --- docs/contributing.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 3318ec103..267d466e4 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -266,8 +266,7 @@ with the core upstream source code. An example is provided in it with any necessary API changes. .. _`setuptools entry points`: - https://pythonhosted.org/setuptools/setuptools.html#dynamic-discovery-of-services-and-plugins - + http://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points .. _coding-style: From ac220976f1032a26d1801da2528ffd554e0e400d Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 7 Jun 2016 14:46:49 -0700 Subject: [PATCH 049/264] work in progress --- acme/acme/errors.py | 2 +- certbot-nginx/certbot_nginx/nginxparser.py | 52 ++++++++++++++++++---- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/acme/acme/errors.py b/acme/acme/errors.py index 77d47c522..ca2ab1874 100644 --- a/acme/acme/errors.py +++ b/acme/acme/errors.py @@ -49,7 +49,7 @@ class MissingNonce(NonceError): def __str__(self): return ('Server {0} response did not include a replay ' - 'nonce, headers: {1}'.format( + 'nonce, headers: {1}\n(This may be a service outage)'.format( self.response.request.method, self.response.headers)) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index f9348398a..7b39234dc 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -53,8 +53,44 @@ class RawNginxParser(object): """Returns the parsed tree as a list.""" return self.parse().asList() - class RawNginxDumper(object): + # pylint: disable=too-few-public-methods + """A class that dumps nginx configuration from the provided tree.""" + def __init__(self, blocks, indentation=0): + self.blocks = blocks + self.indentation = indentation + + def __iter__(self, blocks=None, current_indent=0, spacer=''): + """Iterates the dumped nginx content.""" + blocks = blocks or self.blocks + for key, values in blocks.spaced: + #indentation = spacer * current_indent + if isinstance(key, list): + yield "".join(key) + ' {' + + for parameter in values: + dumped = self.__iter__([parameter], current_indent + self.indentation) + for line in dumped: + yield line + + yield '}' + else: + if key == '#': + yield key + values + else: + if values is None: + yield key + ';' + else: + yield key + values + ';' + + def __str__(self): + """Return the parsed block as a string.""" + return '\n'.join(self) + '\n' + + + + +class OldRawNginxDumper(object): # pylint: disable=too-few-public-methods """A class that dumps nginx configuration from the provided tree.""" def __init__(self, blocks, indentation=4): @@ -102,7 +138,7 @@ def loads(source): :rtype: list """ - return RawNginxParser(source).as_list() + return UnspacedList(RawNginxParser(source).as_list()) def load(_file): @@ -113,13 +149,13 @@ def load(_file): :rtype: list """ - return loads(_file.read()) + return UnspacedList(loads(_file.read())) def dumps(blocks, indentation=4): """Dump to a string. - :param list block: The parsed tree + :param UnspacedList block: The parsed tree :param int indentation: The number of spaces to indent :rtype: str @@ -130,7 +166,7 @@ def dumps(blocks, indentation=4): def dump(blocks, _file, indentation=4): """Dump to a file. - :param list block: The parsed tree + :param UnspacedList block: The parsed tree :param file _file: The file to dump to :param int indentation: The number of spaces to indent :rtype: NoneType @@ -149,14 +185,14 @@ class UnspacedList(list): self.spaced = copy.deepcopy(list(list_source)) # Turn self into a version of the source list that has spaces removed - # and all sub-lists also UnspaceList()ed + # and all sub-lists also UnspacedList()ed list.__init__(self, list_source) for i, entry in reversed(list(enumerate(self))): if isinstance(entry, list): list.__setitem__(self, i, UnspacedList(entry)) elif spacey(entry): list.__delitem__(self, i) - + def insert(self, i, x): self.spaced.insert(i + self._spaces_before(i), x) list.insert(self, i, x) @@ -176,7 +212,7 @@ class UnspacedList(list): else: self.spaced.__add__(other) list.__add__(self, other) - + def __setitem__(self, i, value): self.spaced.__setitem__(i + self._spaces_before(i), value) list.__setitem__(self, i, value) From 9be5f7d7d961cf1def5872acec9cb9bc41e11016 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 7 Jun 2016 17:17:17 -0700 Subject: [PATCH 050/264] Further WIP --- certbot-nginx/certbot_nginx/nginxparser.py | 99 +++++++++++++++++++--- certbot-nginx/certbot_nginx/parser.py | 2 +- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 7b39234dc..8c2ba197e 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -1,6 +1,7 @@ """Very low-level nginx config parser based on pyparsing.""" import copy import string +import sys from pyparsing import ( Literal, White, Word, alphanums, CharsNotIn, Forward, Group, @@ -18,6 +19,7 @@ class RawNginxParser(object): right_bracket = Literal("}").suppress() semicolon = Literal(";").suppress() space = White().suppress() + keepSpace = Optional(White()) key = Word(alphanums + "_/+-.") # Matches anything that is not a special character AND any chars in single # or double quotes @@ -27,8 +29,9 @@ class RawNginxParser(object): modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~") # rules - comment = White() + Literal('#') + restOfLine() - assignment = White() + key + Optional(space + value, default=None) + semicolon + comment = Literal('#') + restOfLine() + + assignment = keepSpace + key + Optional(space + value, default=None) + semicolon location_statement = Optional(space + modifier) + Optional(space + location) if_statement = Literal("if") + space + Regex(r"\(.+\)") + space map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space @@ -53,6 +56,51 @@ class RawNginxParser(object): """Returns the parsed tree as a list.""" return self.parse().asList() +class OldRawNginxParser(object): + # pylint: disable=expression-not-assigned + """A class that parses nginx configuration with pyparsing.""" + + # constants + left_bracket = Literal("{").suppress() + right_bracket = Literal("}").suppress() + semicolon = Literal(";").suppress() + space = White().suppress() + key = Word(alphanums + "_/+-.") + # Matches anything that is not a special character AND any chars in single + # or double quotes + value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+") + location = CharsNotIn("{};," + string.whitespace) + # modifier for location uri [ = | ~ | ~* | ^~ ] + modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~") + + # rules + 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 + map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space + block = Forward() + + block << Group( + (Group(key + location_statement) ^ Group(if_statement) ^ Group(map_statement)) + + left_bracket + + Group(ZeroOrMore(Group(comment | assignment) | block)) + + right_bracket) + + script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd + + def __init__(self, source): + self.source = source + + def parse(self): + """Returns the parsed tree.""" + return self.script.parseString(self.source) + + def as_list(self): + """Returns the parsed tree as a list.""" + return self.parse().asList() + + class RawNginxDumper(object): # pylint: disable=too-few-public-methods """A class that dumps nginx configuration from the provided tree.""" @@ -60,13 +108,24 @@ class RawNginxDumper(object): self.blocks = blocks self.indentation = indentation - def __iter__(self, blocks=None, current_indent=0, spacer=''): + def __iter__(self, blocks=None, current_indent=0, spacer=' '): """Iterates the dumped nginx content.""" blocks = blocks or self.blocks - for key, values in blocks.spaced: + print "iterating", blocks + for b in blocks: + if len(b) == 2: + key, values = b + indentation = "" + elif len(b) == 3: + indentation, key, values = b + assert indentation.isspace(), indentation + " is not space" + yield indentation + else: + print "Cannot process", b + sys.exit(1) #indentation = spacer * current_indent if isinstance(key, list): - yield "".join(key) + ' {' + yield spacer.join(key) + ' {' for parameter in values: dumped = self.__iter__([parameter], current_indent + self.indentation) @@ -75,13 +134,13 @@ class RawNginxDumper(object): yield '}' else: - if key == '#': + if isinstance(key, str) and key.strip() == '#': yield key + values else: if values is None: yield key + ';' else: - yield key + values + ';' + yield key + spacer + values + ';' def __str__(self): """Return the parsed block as a string.""" @@ -138,7 +197,28 @@ def loads(source): :rtype: list """ - return UnspacedList(RawNginxParser(source).as_list()) + old = OldRawNginxParser(source).as_list() + print "Old:" + for entry in old: + print len(entry), " ", + new = UnspacedList(RawNginxParser(source).as_list()) + print "\nNew:" + print new + for entry in new: + print len(entry), " ", + print "\nNewspaced:" + for entry in new.spaced: + print str(len(entry))+ " ", + print "\ngo" + if old != new: + print "NON-MATCH" + for a, b in zip(old, new): + if a != b: + print "Entry", a, "!=", b + import sys + else: + print "Parallel" + return new def load(_file): @@ -149,7 +229,7 @@ def load(_file): :rtype: list """ - return UnspacedList(loads(_file.read())) + return loads(_file.read()) def dumps(blocks, indentation=4): @@ -175,7 +255,6 @@ def dump(blocks, _file, indentation=4): return _file.write(dumps(blocks, indentation)) - spacey = lambda x: isinstance(x, str) and x.isspace() class UnspacedList(list): diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index 2f08c15d3..2872654b5 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -209,7 +209,7 @@ class NginxParser(object): """ for filename in self.parsed: - tree = self.parsed[filename] + tree = self.parsed[filename].spaced if ext: filename = filename + os.path.extsep + ext try: From 80a52d8f018c99f186d6d7642edc86294852702d Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 7 Jun 2016 17:55:53 -0700 Subject: [PATCH 051/264] Vaguely close to working? --- certbot-nginx/certbot_nginx/nginxparser.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 8c2ba197e..9e7136ced 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -31,7 +31,7 @@ class RawNginxParser(object): # rules comment = Literal('#') + restOfLine() - assignment = keepSpace + key + Optional(space + value, default=None) + semicolon + assignment = keepSpace + key + Optional(White() + value, default=None) + semicolon location_statement = Optional(space + modifier) + Optional(space + location) if_statement = Literal("if") + space + Regex(r"\(.+\)") + space map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space @@ -119,14 +119,13 @@ class RawNginxDumper(object): elif len(b) == 3: indentation, key, values = b assert indentation.isspace(), indentation + " is not space" - yield indentation + indentation = indentation.replace("\n", "", 1) else: print "Cannot process", b sys.exit(1) #indentation = spacer * current_indent if isinstance(key, list): - yield spacer.join(key) + ' {' - + yield indentation + spacer.join(key) + ' {' for parameter in values: dumped = self.__iter__([parameter], current_indent + self.indentation) for line in dumped: @@ -135,15 +134,16 @@ class RawNginxDumper(object): yield '}' else: if isinstance(key, str) and key.strip() == '#': - yield key + values + yield indentation + key + values else: if values is None: - yield key + ';' + yield indentation + key + ';' else: - yield key + spacer + values + ';' + yield indentation + key + spacer + values + ';' def __str__(self): """Return the parsed block as a string.""" + print "Merging:\n", '\n'.join(self) return '\n'.join(self) + '\n' From 443f2ebb580faf6a582efe359405c4180f7ee0a6 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 7 Jun 2016 18:19:58 -0700 Subject: [PATCH 052/264] WIP --- certbot-nginx/certbot_nginx/nginxparser.py | 23 ++++++++++------------ 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 9e7136ced..2a68de77b 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -31,7 +31,7 @@ class RawNginxParser(object): # rules comment = Literal('#') + restOfLine() - assignment = keepSpace + key + Optional(White() + value, default=None) + semicolon + assignment = keepSpace + key + Optional(space + value, default=None) + semicolon location_statement = Optional(space + modifier) + Optional(space + location) if_statement = Literal("if") + space + Regex(r"\(.+\)") + space map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space @@ -108,31 +108,28 @@ class RawNginxDumper(object): self.blocks = blocks self.indentation = indentation - def __iter__(self, blocks=None, current_indent=0, spacer=' '): + def __iter__(self, blocks=None, spacer=' '): """Iterates the dumped nginx content.""" blocks = blocks or self.blocks print "iterating", blocks for b in blocks: - if len(b) == 2: - key, values = b - indentation = "" - elif len(b) == 3: - indentation, key, values = b - assert indentation.isspace(), indentation + " is not space" + indentation = "" + if spacey(b[0]): + indentation = b.pop(0) indentation = indentation.replace("\n", "", 1) - else: - print "Cannot process", b - sys.exit(1) - #indentation = spacer * current_indent + key = b.pop(0) + + values = b if isinstance(key, list): yield indentation + spacer.join(key) + ' {' for parameter in values: - dumped = self.__iter__([parameter], current_indent + self.indentation) + dumped = self.__iter__([parameter]) for line in dumped: yield line yield '}' else: + #yield b if isinstance(key, str) and key.strip() == '#': yield indentation + key + values else: From 8147c671e42c95cd7aa63f15f2d8bb3cf280c0bd Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 8 Jun 2016 17:52:35 -0700 Subject: [PATCH 053/264] Now handles some conf files in whitespace-preserving mode (but not all of them) --- certbot-nginx/certbot_nginx/nginxparser.py | 136 ++++----------------- certbot-nginx/certbot_nginx/parser.py | 22 +++- certbot-nginx/certbot_nginx/tls_sni_01.py | 9 +- 3 files changed, 53 insertions(+), 114 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 2a68de77b..13498bee2 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -18,8 +18,7 @@ class RawNginxParser(object): left_bracket = Literal("{").suppress() right_bracket = Literal("}").suppress() semicolon = Literal(";").suppress() - space = White().suppress() - keepSpace = Optional(White()) + space = Optional(White()) key = Word(alphanums + "_/+-.") # Matches anything that is not a special character AND any chars in single # or double quotes @@ -29,21 +28,23 @@ class RawNginxParser(object): modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~") # rules - comment = Literal('#') + restOfLine() + comment = space + Literal('#') + restOfLine() - assignment = keepSpace + key + Optional(space + value, default=None) + semicolon - location_statement = Optional(space + modifier) + Optional(space + location) - if_statement = Literal("if") + space + Regex(r"\(.+\)") + space - map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space + assignment = space + key + Optional(space + value, default=None) + semicolon + location_statement = space + Optional(modifier) + Optional(space + location) + if_statement = space + Literal("if") + space + Regex(r"\(.+\)") + space + map_statement = space + Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space block = Forward() block << Group( + # XXX could this "key" be Literal("location")? (Group(key + location_statement) ^ Group(if_statement) ^ Group(map_statement)) + left_bracket + Group(ZeroOrMore(Group(comment | assignment) | block)) + right_bracket) script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd + script.parseWithTabs() def __init__(self, source): self.source = source @@ -56,51 +57,6 @@ class RawNginxParser(object): """Returns the parsed tree as a list.""" return self.parse().asList() -class OldRawNginxParser(object): - # pylint: disable=expression-not-assigned - """A class that parses nginx configuration with pyparsing.""" - - # constants - left_bracket = Literal("{").suppress() - right_bracket = Literal("}").suppress() - semicolon = Literal(";").suppress() - space = White().suppress() - key = Word(alphanums + "_/+-.") - # Matches anything that is not a special character AND any chars in single - # or double quotes - value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+") - location = CharsNotIn("{};," + string.whitespace) - # modifier for location uri [ = | ~ | ~* | ^~ ] - modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~") - - # rules - 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 - map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space - block = Forward() - - block << Group( - (Group(key + location_statement) ^ Group(if_statement) ^ Group(map_statement)) + - left_bracket + - Group(ZeroOrMore(Group(comment | assignment) | block)) + - right_bracket) - - script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd - - def __init__(self, source): - self.source = source - - def parse(self): - """Returns the parsed tree.""" - return self.script.parseString(self.source) - - def as_list(self): - """Returns the parsed tree as a list.""" - return self.parse().asList() - - class RawNginxDumper(object): # pylint: disable=too-few-public-methods """A class that dumps nginx configuration from the provided tree.""" @@ -108,35 +64,41 @@ class RawNginxDumper(object): self.blocks = blocks self.indentation = indentation - def __iter__(self, blocks=None, spacer=' '): + def __iter__(self, blocks=None): """Iterates the dumped nginx content.""" blocks = blocks or self.blocks print "iterating", blocks for b in blocks: + b0 = b + b = copy.deepcopy(b) indentation = "" if spacey(b[0]): indentation = b.pop(0) indentation = indentation.replace("\n", "", 1) key = b.pop(0) + values = b.pop(0) - values = b if isinstance(key, list): - yield indentation + spacer.join(key) + ' {' + yield indentation + "".join(key) + '{' for parameter in values: dumped = self.__iter__([parameter]) for line in dumped: yield line - yield '}' else: - #yield b if isinstance(key, str) and key.strip() == '#': yield indentation + key + values else: + gap = "" + # Sometimes the parser has stuck some gap whitespace in here; + # if so rotate it into gap + if spacey(values): + gap = values + values = b.pop(0) if values is None: - yield indentation + key + ';' + yield indentation + key + gap + ';' else: - yield indentation + key + spacer + values + ';' + yield indentation + key + gap + values + ';' def __str__(self): """Return the parsed block as a string.""" @@ -146,42 +108,6 @@ class RawNginxDumper(object): -class OldRawNginxDumper(object): - # pylint: disable=too-few-public-methods - """A class that dumps nginx configuration from the provided tree.""" - def __init__(self, blocks, indentation=4): - self.blocks = blocks - self.indentation = indentation - - def __iter__(self, blocks=None, current_indent=0, spacer=' '): - """Iterates the dumped nginx content.""" - blocks = blocks or self.blocks - for key, values in blocks: - indentation = spacer * current_indent - if isinstance(key, list): - if current_indent: - yield '' - yield indentation + spacer.join(key) + ' {' - - for parameter in values: - dumped = self.__iter__([parameter], current_indent + self.indentation) - for line in dumped: - yield line - - yield indentation + '}' - else: - 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 __str__(self): - """Return the parsed block as a string.""" - return '\n'.join(self) + '\n' - # Shortcut functions to respect Python's serialization interface # (like pyyaml, picker or json) @@ -194,10 +120,6 @@ def loads(source): :rtype: list """ - old = OldRawNginxParser(source).as_list() - print "Old:" - for entry in old: - print len(entry), " ", new = UnspacedList(RawNginxParser(source).as_list()) print "\nNew:" print new @@ -207,14 +129,6 @@ def loads(source): for entry in new.spaced: print str(len(entry))+ " ", print "\ngo" - if old != new: - print "NON-MATCH" - for a, b in zip(old, new): - if a != b: - print "Entry", a, "!=", b - import sys - else: - print "Parallel" return new @@ -229,7 +143,7 @@ def load(_file): return loads(_file.read()) -def dumps(blocks, indentation=4): +def dumps(blocks): """Dump to a string. :param UnspacedList block: The parsed tree @@ -237,10 +151,10 @@ def dumps(blocks, indentation=4): :rtype: str """ - return str(RawNginxDumper(blocks, indentation)) + return str(RawNginxDumper(blocks)) -def dump(blocks, _file, indentation=4): +def dump(blocks, _file): """Dump to a file. :param UnspacedList block: The parsed tree @@ -249,7 +163,7 @@ def dump(blocks, _file, indentation=4): :rtype: NoneType """ - return _file.write(dumps(blocks, indentation)) + return _file.write(dumps(blocks)) spacey = lambda x: isinstance(x, str) and x.isspace() diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index 2872654b5..642702c9f 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -4,6 +4,7 @@ import logging import os import pyparsing import re +import sys from certbot import errors @@ -213,9 +214,26 @@ class NginxParser(object): if ext: filename = filename + os.path.extsep + ext try: - logger.debug('Dumping to %s:\n%s', filename, nginxparser.dumps(tree)) + out = nginxparser.dumps(tree) + logger.debug('Dumping to %s:\n%s', filename, out) with open(filename, 'w') as _file: - nginxparser.dump(tree, _file) + _file.write(out) + + if "owncloud" in filename: + print "Outputting", filename + print out + a = open("/tmp/nginx/sites-enabled/owncloud.conf").read() + b = open(filename).read() + for linea, lineb in zip(a.split('\n'), b.split('\n')): + if linea != lineb: + print "a", repr(linea) + print "b", repr(lineb) + if a != b: + print "Mismatch!" + if a != out: + print "Double mismatch", len(a), len(out) + else: + print "Match!" except IOError: logger.error("Could not open file for writing: %s", filename) diff --git a/certbot-nginx/certbot_nginx/tls_sni_01.py b/certbot-nginx/certbot_nginx/tls_sni_01.py index e4c5d31a6..efb5d53e6 100644 --- a/certbot-nginx/certbot_nginx/tls_sni_01.py +++ b/certbot-nginx/certbot_nginx/tls_sni_01.py @@ -3,6 +3,7 @@ import itertools import logging import os +import sys from certbot import errors from certbot.plugins import common @@ -123,7 +124,13 @@ class NginxTlsSni01(common.TLSSNI01): True, self.challenge_conf) with open(self.challenge_conf, "w") as new_conf: - nginxparser.dump(config, new_conf) + if "mime" in self.challenge_conf: + print "Weird" + out = nginxparser.dumps(config) + print out + #sys.exit(1) + #nginxparser.dump(config, new_conf) + new_conf.write(out) def _make_server_block(self, achall, addrs): """Creates a server block for a challenge. From bc50ad48c6af5ff1b392dd1379a1cda6fe2d7c04 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 10 Jun 2016 06:02:50 +0200 Subject: [PATCH 054/264] Changing default logging level --- certbot/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/constants.py b/certbot/constants.py index 1d4efe80e..fb278161d 100644 --- a/certbot/constants.py +++ b/certbot/constants.py @@ -18,7 +18,7 @@ CLI_DEFAULTS = dict( os.path.join(os.environ.get("XDG_CONFIG_HOME", "~/.config"), "letsencrypt", "cli.ini"), ], - verbose_count=-(logging.WARNING / 10), + verbose_count=-(logging.INFO / 10), server="https://acme-v01.api.letsencrypt.org/directory", rsa_key_size=2048, rollback_checkpoints=1, From b51280875081c868698a2a4b8603c1a9f9905926 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 10 Jun 2016 06:15:03 +0200 Subject: [PATCH 055/264] Changing CLI logging format --- certbot/main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/certbot/main.py b/certbot/main.py index fa14bbf99..bb65680af 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -615,11 +615,12 @@ def _cli_log_handler(config, level, fmt): def setup_logging(config, cli_handler_factory, logfile): """Setup logging.""" - fmt = "%(asctime)s:%(levelname)s:%(name)s:%(message)s" + file_fmt = "%(asctime)s:%(levelname)s:%(name)s:%(message)s" + cli_fmt = "%(message)s" level = -config.verbose_count * 10 file_handler, log_file_path = setup_log_file_handler( - config, logfile=logfile, fmt=fmt) - cli_handler = cli_handler_factory(config, level, fmt) + config, logfile=logfile, fmt=file_fmt) + cli_handler = cli_handler_factory(config, level, cli_fmt) # TODO: use fileConfig? From 7f9a8f0f089a21769aa80bfd6696cdb19f7f5fa0 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 10 Jun 2016 06:26:33 +0200 Subject: [PATCH 056/264] Adjusting logging level of certain messages --- certbot/client.py | 2 +- certbot/main.py | 2 +- certbot/renewal.py | 6 +++--- certbot/reporter.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/certbot/client.py b/certbot/client.py index 1dec6a1a9..81b7ccdc6 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -282,7 +282,7 @@ class Client(object): "by your operating system package manager") if self.config.dry_run: - logger.info("Dry run: Skipping creating new lineage for %s", + logger.debug("Dry run: Skipping creating new lineage for %s", domains[0]) return None else: diff --git a/certbot/main.py b/certbot/main.py index bb65680af..c19375c32 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -525,7 +525,7 @@ def _csr_obtain_cert(config, le_client): csr, typ = config.actual_csr certr, chain = le_client.obtain_certificate_from_csr(config.domains, csr, typ) if config.dry_run: - logger.info( + logger.debug( "Dry run: skipping saving certificate to %s", config.cert_path) else: cert_path, _, cert_fullchain = le_client.save_certificate( diff --git a/certbot/renewal.py b/certbot/renewal.py index d04e2d27c..059fd6cd9 100644 --- a/certbot/renewal.py +++ b/certbot/renewal.py @@ -107,7 +107,7 @@ def _restore_webroot_config(config, renewalparams): if not cli.set_by_cli("webroot_map"): config.namespace.webroot_map = renewalparams["webroot_map"] elif "webroot_path" in renewalparams: - logger.info("Ancient renewal conf file without webroot-map, restoring webroot-path") + logger.debug("Ancient renewal conf file without webroot-map, restoring webroot-path") wp = renewalparams["webroot_path"] if isinstance(wp, str): # prior to 0.1.0, webroot_path was a string wp = [wp] @@ -193,7 +193,7 @@ def _restore_required_config_elements(config, renewalparams): def should_renew(config, lineage): "Return true if any of the circumstances for automatic renewal apply." if config.renew_by_default: - logger.info("Auto-renewal forced with --force-renewal...") + logger.debug("Auto-renewal forced with --force-renewal...") return True if lineage.should_autorenew(interactive=True): logger.info("Cert is due for renewal, auto-renewing...") @@ -235,7 +235,7 @@ def renew_cert(config, domains, le_client, lineage): _avoid_invalidating_lineage(config, lineage, original_server) new_certr, new_chain, new_key, _ = le_client.obtain_certificate(domains) if config.dry_run: - logger.info("Dry run: skipping updating lineage at %s", + logger.debug("Dry run: skipping updating lineage at %s", os.path.dirname(lineage.cert)) else: prior_version = lineage.latest_common_version() diff --git a/certbot/reporter.py b/certbot/reporter.py index e07011aee..118b13166 100644 --- a/certbot/reporter.py +++ b/certbot/reporter.py @@ -58,7 +58,7 @@ class Reporter(object): """ assert self.HIGH_PRIORITY <= priority <= self.LOW_PRIORITY self.messages.put(self._msg_type(priority, msg, on_crash)) - logger.info("Reporting to user: %s", msg) + logger.debug("Reporting to user: %s", msg) def atexit_print_messages(self, pid=None): """Function to be registered with atexit to print messages. From 8c8125c6fd120e7e8d5297ef43ba449b70e924ac Mon Sep 17 00:00:00 2001 From: Geoffroy Doucet Date: Fri, 10 Jun 2016 20:33:25 -0400 Subject: [PATCH 057/264] Added the argument --quiet and -q so then when used with a regular user there is no output to the screen. --- letsencrypt-auto-source/letsencrypt-auto | 13 ++++++++++--- letsencrypt-auto-source/letsencrypt-auto.template | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 569f6d6f3..0ef97c8c1 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -34,6 +34,7 @@ Help for certbot itself cannot be provided until it is installed. -n, --non-interactive, --noninteractive run without asking for user input --no-self-upgrade do not download updates --os-packages-only install OS dependencies and exit + -q, --quiet provide only update/error output -v, --verbose provide more output All arguments are accepted and forwarded to the Certbot client when run." @@ -52,15 +53,19 @@ for arg in "$@" ; do HELP=1;; --noninteractive|--non-interactive) ASSUME_YES=1;; + --quiet) + QUIET=1;; --verbose) VERBOSE=1;; -[!-]*) - while getopts ":hnv" short_arg $arg; do + while getopts ":hnvq" short_arg $arg; do case "$short_arg" in h) HELP=1;; n) ASSUME_YES=1;; + q) + QUIET=1;; v) VERBOSE=1;; esac @@ -898,8 +903,10 @@ UNLIKELY_EOF fi if [ -n "$SUDO" ]; then # SUDO is su wrapper or sudo - echo "Requesting root privileges to run certbot..." - echo " $VENV_BIN/letsencrypt" "$@" + if [ "$QUIET" != 1 ]; then + echo "Requesting root privileges to run certbot..." + echo " $VENV_BIN/letsencrypt" "$@" + fi fi if [ -z "$SUDO_ENV" ] ; then # SUDO is su wrapper / noop diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 73d819b4a..b254cd429 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -34,6 +34,7 @@ Help for certbot itself cannot be provided until it is installed. -n, --non-interactive, --noninteractive run without asking for user input --no-self-upgrade do not download updates --os-packages-only install OS dependencies and exit + -q, --quiet provide only update/error output -v, --verbose provide more output All arguments are accepted and forwarded to the Certbot client when run." @@ -52,15 +53,19 @@ for arg in "$@" ; do HELP=1;; --noninteractive|--non-interactive) ASSUME_YES=1;; + --quiet) + QUIET=1;; --verbose) VERBOSE=1;; -[!-]*) - while getopts ":hnv" short_arg $arg; do + while getopts ":hnvq" short_arg $arg; do case "$short_arg" in h) HELP=1;; n) ASSUME_YES=1;; + q) + QUIET=1;; v) VERBOSE=1;; esac @@ -257,8 +262,10 @@ UNLIKELY_EOF fi if [ -n "$SUDO" ]; then # SUDO is su wrapper or sudo - echo "Requesting root privileges to run certbot..." - echo " $VENV_BIN/letsencrypt" "$@" + if [ "$QUIET" != 1 ]; then + echo "Requesting root privileges to run certbot..." + echo " $VENV_BIN/letsencrypt" "$@" + fi fi if [ -z "$SUDO_ENV" ] ; then # SUDO is su wrapper / noop From 4158656058cb14e8afa9048b9a3612da73abf1b5 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 14 Jun 2016 16:56:16 -0700 Subject: [PATCH 058/264] Release 0.8.1 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-auto | 52 ++++++++++++++---- certbot-compatibility-test/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/__init__.py | 2 +- docs/cli-help.txt | 9 +++ letsencrypt-auto | 52 ++++++++++++++---- letsencrypt-auto-source/certbot-auto.asc | 14 ++--- letsencrypt-auto-source/letsencrypt-auto | 20 +++---- letsencrypt-auto-source/letsencrypt-auto.sig | Bin 256 -> 256 bytes .../pieces/letsencrypt-auto-requirements.txt | 18 +++--- 12 files changed, 120 insertions(+), 55 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index ed133e128..2bcec9128 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.0.dev0' +version = '0.8.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index e3dbe4563..87214d2e5 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.0.dev0' +version = '0.8.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-auto b/certbot-auto index 2de5ff48f..80f39cf59 100755 --- a/certbot-auto +++ b/certbot-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.8.0" +LE_AUTO_VERSION="0.8.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -172,7 +172,7 @@ BootstrapDebCommon() { # distro version (#346) virtualenv= - if apt-cache show virtualenv > /dev/null 2>&1; then + if apt-cache show virtualenv > /dev/null 2>&1 && ! apt-cache --quiet=0 show virtualenv 2>&1 | grep -q 'No packages found'; then virtualenv="virtualenv" fi @@ -458,12 +458,39 @@ BootstrapSmartOS() { pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv' } +BootstrapMageiaCommon() { + if ! $SUDO urpmi --force \ + python \ + libpython-devel \ + python-virtualenv + then + echo "Could not install Python dependencies. Aborting bootstrap!" + exit 1 + fi + + if ! $SUDO urpmi --force \ + git \ + gcc \ + cdialog \ + python-augeas \ + libopenssl-devel \ + libffi-devel \ + rootcerts + then + echo "Could not install additional dependencies. Aborting bootstrap!" + exit 1 + fi +} + # Install required OS packages: Bootstrap() { if [ -f /etc/debian_version ]; then echo "Bootstrapping dependencies for Debian-based OSes..." BootstrapDebCommon + elif [ -f /etc/mageia-release ] ; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + ExperimentalBootstrap "Mageia" BootstrapMageiaCommon elif [ -f /etc/redhat-release ]; then echo "Bootstrapping dependencies for RedHat-based OSes..." BootstrapRpmCommon @@ -476,7 +503,7 @@ Bootstrap() { BootstrapArchCommon else echo "Please use pacman to install letsencrypt packages:" - echo "# pacman -S letsencrypt letsencrypt-apache" + echo "# pacman -S certbot certbot-apache" echo echo "If you would like to use the virtualenv way, please run the script again with the" echo "--debug flag." @@ -500,6 +527,7 @@ Bootstrap() { echo "You will need to bootstrap, configure virtualenv, and run pip install manually." echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" echo "for more info." + exit 1 fi } @@ -719,15 +747,15 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.8.0 \ - --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ - --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da -certbot==0.8.0 \ - --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ - --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 -certbot-apache==0.8.0 \ - --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ - --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 +acme==0.8.1 \ + --hash=sha256:ccd7883772efbf933f91713b8241455993834f3620c8fbd459d9ed5e50bbaaca \ + --hash=sha256:d3ea4acf280bf6253ad7d641cb0970f230a19805acfed809e7a8ddcf62157d9f +certbot==0.8.1 \ + --hash=sha256:89805d9f70249ae859ec4d7a99c00b4bb7083ca90cd12d4d202b76dfc284f7c5 \ + --hash=sha256:6ca8df3d310ced6687d38aac17c0fb8c1b2ec7a3bea156a254e4cc2a1c132771 +certbot-apache==0.8.1 \ + --hash=sha256:c9e3fdc15e65589c2e39eb0e6b1f61f0c0a1db3c17b00bb337f0ff636cc61cb3 \ + --hash=sha256:0faf2879884d3b7a58b071902fba37d4b8b58a50e2c3b8ac262c0a74134045ed UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index fb56be65f..cd282af50 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.0.dev0' +version = '0.8.1' install_requires = [ 'certbot', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 62c705b4c..f76cbe596 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.0.dev0' +version = '0.8.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index 34358a5d9..e5d5629b1 100644 --- a/certbot/__init__.py +++ b/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '0.9.0.dev0' +__version__ = '0.8.1' diff --git a/docs/cli-help.txt b/docs/cli-help.txt index b25326148..e5f1fdcb4 100644 --- a/docs/cli-help.txt +++ b/docs/cli-help.txt @@ -200,6 +200,15 @@ renew: and keys; the shell variable $RENEWED_DOMAINS will contain a space-delimited list of renewed cert domains (default: None) + --disable-hook-validation + Ordinarily the commands specified for --pre-hook + /--post-hook/--renew-hook will be checked for + validity, to see if the programs being run are in the + $PATH, so that mistakes can be caught early, even when + the hooks aren't being run just yet. The validation is + rather simplistic and fails if you use more advanced + shell constructs, so you can use this switch to + disable it. (default: True) certonly: Options for modifying how a cert is obtained diff --git a/letsencrypt-auto b/letsencrypt-auto index 2de5ff48f..80f39cf59 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.8.0" +LE_AUTO_VERSION="0.8.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -172,7 +172,7 @@ BootstrapDebCommon() { # distro version (#346) virtualenv= - if apt-cache show virtualenv > /dev/null 2>&1; then + if apt-cache show virtualenv > /dev/null 2>&1 && ! apt-cache --quiet=0 show virtualenv 2>&1 | grep -q 'No packages found'; then virtualenv="virtualenv" fi @@ -458,12 +458,39 @@ BootstrapSmartOS() { pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv' } +BootstrapMageiaCommon() { + if ! $SUDO urpmi --force \ + python \ + libpython-devel \ + python-virtualenv + then + echo "Could not install Python dependencies. Aborting bootstrap!" + exit 1 + fi + + if ! $SUDO urpmi --force \ + git \ + gcc \ + cdialog \ + python-augeas \ + libopenssl-devel \ + libffi-devel \ + rootcerts + then + echo "Could not install additional dependencies. Aborting bootstrap!" + exit 1 + fi +} + # Install required OS packages: Bootstrap() { if [ -f /etc/debian_version ]; then echo "Bootstrapping dependencies for Debian-based OSes..." BootstrapDebCommon + elif [ -f /etc/mageia-release ] ; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + ExperimentalBootstrap "Mageia" BootstrapMageiaCommon elif [ -f /etc/redhat-release ]; then echo "Bootstrapping dependencies for RedHat-based OSes..." BootstrapRpmCommon @@ -476,7 +503,7 @@ Bootstrap() { BootstrapArchCommon else echo "Please use pacman to install letsencrypt packages:" - echo "# pacman -S letsencrypt letsencrypt-apache" + echo "# pacman -S certbot certbot-apache" echo echo "If you would like to use the virtualenv way, please run the script again with the" echo "--debug flag." @@ -500,6 +527,7 @@ Bootstrap() { echo "You will need to bootstrap, configure virtualenv, and run pip install manually." echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" echo "for more info." + exit 1 fi } @@ -719,15 +747,15 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.8.0 \ - --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ - --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da -certbot==0.8.0 \ - --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ - --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 -certbot-apache==0.8.0 \ - --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ - --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 +acme==0.8.1 \ + --hash=sha256:ccd7883772efbf933f91713b8241455993834f3620c8fbd459d9ed5e50bbaaca \ + --hash=sha256:d3ea4acf280bf6253ad7d641cb0970f230a19805acfed809e7a8ddcf62157d9f +certbot==0.8.1 \ + --hash=sha256:89805d9f70249ae859ec4d7a99c00b4bb7083ca90cd12d4d202b76dfc284f7c5 \ + --hash=sha256:6ca8df3d310ced6687d38aac17c0fb8c1b2ec7a3bea156a254e4cc2a1c132771 +certbot-apache==0.8.1 \ + --hash=sha256:c9e3fdc15e65589c2e39eb0e6b1f61f0c0a1db3c17b00bb337f0ff636cc61cb3 \ + --hash=sha256:0faf2879884d3b7a58b071902fba37d4b8b58a50e2c3b8ac262c0a74134045ed UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc index 0255229b0..5bb725c96 100644 --- a/letsencrypt-auto-source/certbot-auto.asc +++ b/letsencrypt-auto-source/certbot-auto.asc @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 -iQEcBAABAgAGBQJXUJvwAAoJEE0XyZXNl3XyvKsH/3qn7Xa/GQx3HvB6Io/Csn/E -v1nbUg5RPwvrTyyol8BJ6UrHiJw+gTbUgCAnBkZ7DYKaC8AQmQXVRcWXNALMMTzB -6LpBXjQQ2xrBYamGj70N7KnTM1QmxI96GUQouiHMJVugV4uihKJDjtR8/f2JWKok -ZSox6E4LqC45HzqLWiOqc13TrHbti32Mo8DyC63PBnSwMnypGLK6XcqM0L9Re62W -smoKu1VWKwWZYRYXIQr0dvK4JmVTrIsdASdZkhTC/vc8y4tGkdN0DcF2EHzci6OA -Tx0W+Ao+HM1ZcaaH3BJ1y3kYfT+mlt6o4OaK3UB/wtUzMmVih7l1UeiNkVL0oYk= -=t3L6 +iQEcBAABAgAGBQJXYJmBAAoJEE0XyZXNl3XyyIMH/jtYFb7rl5XXN8hjlKuK5frq +z7/jdK7fvI+mtYJ4i2Cy3yMz8T4wscXGkhxNtipbATWlpevPfjYzm4ZGC25coFZx +fDX44w0hBBgel7EISXGR1ABXb2rj24TZxIYXwaeClylsK9n5CxcWBocn8tDlfr8t +7VQUJEL3l1IlrnKnvpoL4Eq11sxlIPtitDPJ5c98ZM1293ZbWzIqyZKoXLIUkKHg +pkaa80j/QMmFumxzXFenU91JusLdeoblvjjg+kzjGonjslAYIuH4wEEjz2VJuUYe +P2+2ZyW4eLA6rRZhZ3CMtV79HzTPTWiELCYbXezb+yXJJEqzCYtIXkmbNQ3jUEY= +=86lB -----END PGP SIGNATURE----- diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1e3118848..80f39cf59 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.9.0.dev0" +LE_AUTO_VERSION="0.8.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -747,15 +747,15 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.8.0 \ - --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ - --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da -certbot==0.8.0 \ - --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ - --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 -certbot-apache==0.8.0 \ - --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ - --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 +acme==0.8.1 \ + --hash=sha256:ccd7883772efbf933f91713b8241455993834f3620c8fbd459d9ed5e50bbaaca \ + --hash=sha256:d3ea4acf280bf6253ad7d641cb0970f230a19805acfed809e7a8ddcf62157d9f +certbot==0.8.1 \ + --hash=sha256:89805d9f70249ae859ec4d7a99c00b4bb7083ca90cd12d4d202b76dfc284f7c5 \ + --hash=sha256:6ca8df3d310ced6687d38aac17c0fb8c1b2ec7a3bea156a254e4cc2a1c132771 +certbot-apache==0.8.1 \ + --hash=sha256:c9e3fdc15e65589c2e39eb0e6b1f61f0c0a1db3c17b00bb337f0ff636cc61cb3 \ + --hash=sha256:0faf2879884d3b7a58b071902fba37d4b8b58a50e2c3b8ac262c0a74134045ed UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/letsencrypt-auto.sig b/letsencrypt-auto-source/letsencrypt-auto.sig index f024577a34a42779e39755635eca4daf6f46ac2a..e3da0e0a35a6dafe26dbbe061f546aeb929dfcdb 100644 GIT binary patch literal 256 zcmV+b0ssDf@*{!ug8Wu1n(zcS_L8lFE=3`8xR7ru#Yq0;RMek)(d|5ow9N+eJQroy zYC^uLM9I-+sE5&5@?b;V8wXnSYWY@reJu{#UVlBrThxmxIb7 G&VdBMz>LuV literal 256 zcmV+b0ssE80bqRH{`qI)8kxNPxBYvrI}8PM??lS5W%Vrx#G#77ah$EmwK78hzI8fL zpFoy+Z$Ff?%2R#7_m4mldi$VK+OCedjDk7*K$j_4-%~DH(I7GKai+aBwofiSx4Q27 z;SV#~5cO^_zi`sHUA566Xqu@Q&d>p~uV#$A5kiL^Wt5QWl@grCRt$tN>*5-L&1i=@?vr?8a-~$mStKTr+dwJTPqN4;)GA0wY_jCnH7Wesi1I|l7M@y GRi#to9)G0( diff --git a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt index c33795ced..1291b2c96 100644 --- a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt +++ b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt @@ -181,12 +181,12 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.8.0 \ - --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ - --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da -certbot==0.8.0 \ - --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ - --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 -certbot-apache==0.8.0 \ - --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ - --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 +acme==0.8.1 \ + --hash=sha256:ccd7883772efbf933f91713b8241455993834f3620c8fbd459d9ed5e50bbaaca \ + --hash=sha256:d3ea4acf280bf6253ad7d641cb0970f230a19805acfed809e7a8ddcf62157d9f +certbot==0.8.1 \ + --hash=sha256:89805d9f70249ae859ec4d7a99c00b4bb7083ca90cd12d4d202b76dfc284f7c5 \ + --hash=sha256:6ca8df3d310ced6687d38aac17c0fb8c1b2ec7a3bea156a254e4cc2a1c132771 +certbot-apache==0.8.1 \ + --hash=sha256:c9e3fdc15e65589c2e39eb0e6b1f61f0c0a1db3c17b00bb337f0ff636cc61cb3 \ + --hash=sha256:0faf2879884d3b7a58b071902fba37d4b8b58a50e2c3b8ac262c0a74134045ed From 5c74e728b584e3750ba2b67d057339e8749faecd Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 14 Jun 2016 16:56:31 -0700 Subject: [PATCH 059/264] Bump version to 0.9.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-compatibility-test/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/__init__.py | 2 +- letsencrypt-auto-source/letsencrypt-auto | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 2bcec9128..ed133e128 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.8.1' +version = '0.9.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 87214d2e5..e3dbe4563 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.8.1' +version = '0.9.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index cd282af50..fb56be65f 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.8.1' +version = '0.9.0.dev0' install_requires = [ 'certbot', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index f76cbe596..62c705b4c 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.8.1' +version = '0.9.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index e5d5629b1..34358a5d9 100644 --- a/certbot/__init__.py +++ b/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '0.8.1' +__version__ = '0.9.0.dev0' diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 80f39cf59..80b81c898 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.8.1" +LE_AUTO_VERSION="0.9.0.dev0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates From 176751f4da939c88741c5438b0ec649e1e9cfbbf Mon Sep 17 00:00:00 2001 From: Jacob Sachs Date: Tue, 14 Jun 2016 23:15:55 -0400 Subject: [PATCH 060/264] Log new cert and cert renewal --- certbot/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certbot/main.py b/certbot/main.py index f68373998..7d6830b18 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -88,9 +88,11 @@ def _auth_from_domains(le_client, config, domains, lineage=None): hooks.pre_hook(config) try: if action == "renew": + logger.info("Renewing an existing certificate") renewal.renew_cert(config, domains, le_client, lineage) elif action == "newcert": # TREAT AS NEW REQUEST + logger.info("Obtaining a new certificate") lineage = le_client.obtain_and_enroll_certificate(domains) if lineage is False: raise errors.Error("Certificate could not be obtained") From 98a2e0c6d6a519b251f23735d83a40244eab3349 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 15 Jun 2016 16:02:33 -0700 Subject: [PATCH 061/264] Another waypoint --- certbot-nginx/certbot_nginx/nginxparser.py | 20 ++++++++++++-------- certbot-nginx/certbot_nginx/tls_sni_01.py | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 13498bee2..b30a71bea 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -18,8 +18,10 @@ class RawNginxParser(object): left_bracket = Literal("{").suppress() right_bracket = Literal("}").suppress() semicolon = Literal(";").suppress() - space = Optional(White()) key = Word(alphanums + "_/+-.") + space = Optional(White()) + nspace = Optional(Regex(r"[ \t]+")) + blankLine = ZeroOrMore(Regex(r"^\S$")) # Matches anything that is not a special character AND any chars in single # or double quotes value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+") @@ -31,23 +33,25 @@ class RawNginxParser(object): comment = space + Literal('#') + restOfLine() assignment = space + key + Optional(space + value, default=None) + semicolon - location_statement = space + Optional(modifier) + Optional(space + location) + location_statement = space + Optional(modifier) + Optional(space + location + space) if_statement = space + Literal("if") + space + Regex(r"\(.+\)") + space map_statement = space + Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space block = Forward() block << Group( # XXX could this "key" be Literal("location")? - (Group(key + location_statement) ^ Group(if_statement) ^ Group(map_statement)) + + # WIP: in order to allow this leaveWhitespace(), we're going to need an explicit + # "whitespaceline" construction... + (Group(space + key + location_statement) ^ Group(if_statement) ^ + Group(map_statement)).leaveWhitespace() + left_bracket + Group(ZeroOrMore(Group(comment | assignment) | block)) + - right_bracket) + space + right_bracket) script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd script.parseWithTabs() - def __init__(self, source): - self.source = source + def __init__(self, source): self.source = source def parse(self): """Returns the parsed tree.""" @@ -74,7 +78,7 @@ class RawNginxDumper(object): indentation = "" if spacey(b[0]): indentation = b.pop(0) - indentation = indentation.replace("\n", "", 1) + #indentation = indentation.replace("\n", "", 1) key = b.pop(0) values = b.pop(0) @@ -103,7 +107,7 @@ class RawNginxDumper(object): def __str__(self): """Return the parsed block as a string.""" print "Merging:\n", '\n'.join(self) - return '\n'.join(self) + '\n' + return ''.join(self) + '\n' diff --git a/certbot-nginx/certbot_nginx/tls_sni_01.py b/certbot-nginx/certbot_nginx/tls_sni_01.py index efb5d53e6..d24cb830d 100644 --- a/certbot-nginx/certbot_nginx/tls_sni_01.py +++ b/certbot-nginx/certbot_nginx/tls_sni_01.py @@ -124,9 +124,9 @@ class NginxTlsSni01(common.TLSSNI01): True, self.challenge_conf) with open(self.challenge_conf, "w") as new_conf: + out = nginxparser.dumps(config) if "mime" in self.challenge_conf: print "Weird" - out = nginxparser.dumps(config) print out #sys.exit(1) #nginxparser.dump(config, new_conf) From 5e59b8ad46872657f9a6fd0a12ae1f1dd8eceaf7 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 15 Jun 2016 16:42:47 -0700 Subject: [PATCH 062/264] Woohoo! it works --- certbot-nginx/certbot_nginx/nginxparser.py | 28 +++++++++++++++------- certbot-nginx/certbot_nginx/parser.py | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index b30a71bea..c8893f80a 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -15,12 +15,12 @@ class RawNginxParser(object): """A class that parses nginx configuration with pyparsing.""" # constants - left_bracket = Literal("{").suppress() - right_bracket = Literal("}").suppress() - semicolon = Literal(";").suppress() - key = Word(alphanums + "_/+-.") space = Optional(White()) nspace = Optional(Regex(r"[ \t]+")) + left_bracket = Literal("{").suppress() + right_bracket = space.leaveWhitespace() + Literal("}").suppress() + semicolon = Literal(";").suppress() + key = Word(alphanums + "_/+-.") blankLine = ZeroOrMore(Regex(r"^\S$")) # Matches anything that is not a special character AND any chars in single # or double quotes @@ -45,8 +45,8 @@ class RawNginxParser(object): (Group(space + key + location_statement) ^ Group(if_statement) ^ Group(map_statement)).leaveWhitespace() + left_bracket + - Group(ZeroOrMore(Group(comment | assignment) | block)) + - space + right_bracket) + Group(ZeroOrMore(Group(comment | assignment) | block) + space).leaveWhitespace() + + right_bracket) script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd script.parseWithTabs() @@ -76,11 +76,22 @@ class RawNginxDumper(object): b0 = b b = copy.deepcopy(b) indentation = "" + if isinstance(b, str): + yield b + continue if spacey(b[0]): - indentation = b.pop(0) + try: + indentation = b.pop(0) + except: + import ipdb + ipdb.set_trace() + #indentation = indentation.replace("\n", "", 1) key = b.pop(0) values = b.pop(0) + if "worker_processes" in str(b0) and False: + import ipdb + ipdb.set_trace() if isinstance(key, list): yield indentation + "".join(key) + '{' @@ -106,7 +117,8 @@ class RawNginxDumper(object): def __str__(self): """Return the parsed block as a string.""" - print "Merging:\n", '\n'.join(self) + x = ''.join(self) + print "Merging:\n", repr(x) return ''.join(self) + '\n' diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index 642702c9f..61f728d2f 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -219,7 +219,7 @@ class NginxParser(object): with open(filename, 'w') as _file: _file.write(out) - if "owncloud" in filename: + if True or "owncloud" in filename: print "Outputting", filename print out a = open("/tmp/nginx/sites-enabled/owncloud.conf").read() From 4f46289c1b9b582f6ad90db0a5651e39d1b2f929 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 15 Jun 2016 17:26:38 -0700 Subject: [PATCH 063/264] Start cleanup --- certbot-nginx/certbot_nginx/nginxparser.py | 44 +++------------------- certbot-nginx/certbot_nginx/parser.py | 17 +-------- certbot-nginx/certbot_nginx/tls_sni_01.py | 5 --- 3 files changed, 7 insertions(+), 59 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index c8893f80a..d1d17493a 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -16,12 +16,10 @@ class RawNginxParser(object): # constants space = Optional(White()) - nspace = Optional(Regex(r"[ \t]+")) left_bracket = Literal("{").suppress() right_bracket = space.leaveWhitespace() + Literal("}").suppress() semicolon = Literal(";").suppress() key = Word(alphanums + "_/+-.") - blankLine = ZeroOrMore(Regex(r"^\S$")) # Matches anything that is not a special character AND any chars in single # or double quotes value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+") @@ -40,8 +38,6 @@ class RawNginxParser(object): block << Group( # XXX could this "key" be Literal("location")? - # WIP: in order to allow this leaveWhitespace(), we're going to need an explicit - # "whitespaceline" construction... (Group(space + key + location_statement) ^ Group(if_statement) ^ Group(map_statement)).leaveWhitespace() + left_bracket + @@ -51,7 +47,8 @@ class RawNginxParser(object): script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd script.parseWithTabs() - def __init__(self, source): self.source = source + def __init__(self, source): + self.source = source def parse(self): """Returns the parsed tree.""" @@ -71,27 +68,16 @@ class RawNginxDumper(object): def __iter__(self, blocks=None): """Iterates the dumped nginx content.""" blocks = blocks or self.blocks - print "iterating", blocks for b in blocks: - b0 = b - b = copy.deepcopy(b) - indentation = "" if isinstance(b, str): yield b continue + b = copy.deepcopy(b) + indentation = "" if spacey(b[0]): - try: - indentation = b.pop(0) - except: - import ipdb - ipdb.set_trace() - - #indentation = indentation.replace("\n", "", 1) + indentation = b.pop(0) key = b.pop(0) values = b.pop(0) - if "worker_processes" in str(b0) and False: - import ipdb - ipdb.set_trace() if isinstance(key, list): yield indentation + "".join(key) + '{' @@ -117,14 +103,9 @@ class RawNginxDumper(object): def __str__(self): """Return the parsed block as a string.""" - x = ''.join(self) - print "Merging:\n", repr(x) return ''.join(self) + '\n' - - - # Shortcut functions to respect Python's serialization interface # (like pyyaml, picker or json) @@ -136,16 +117,7 @@ def loads(source): :rtype: list """ - new = UnspacedList(RawNginxParser(source).as_list()) - print "\nNew:" - print new - for entry in new: - print len(entry), " ", - print "\nNewspaced:" - for entry in new.spaced: - print str(len(entry))+ " ", - print "\ngo" - return new + return UnspacedList(RawNginxParser(source).as_list()) def load(_file): @@ -238,7 +210,3 @@ class UnspacedList(list): idx -= 1 pos += 1 return spaces - - def with_spaces(self): - return self.spaced - diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index 61f728d2f..18301de0e 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -215,25 +215,10 @@ class NginxParser(object): filename = filename + os.path.extsep + ext try: out = nginxparser.dumps(tree) - logger.debug('Dumping to %s:\n%s', filename, out) + #logger.debug('Writing nginx conf tree to %s:\n%s', filename, out) with open(filename, 'w') as _file: _file.write(out) - if True or "owncloud" in filename: - print "Outputting", filename - print out - a = open("/tmp/nginx/sites-enabled/owncloud.conf").read() - b = open(filename).read() - for linea, lineb in zip(a.split('\n'), b.split('\n')): - if linea != lineb: - print "a", repr(linea) - print "b", repr(lineb) - if a != b: - print "Mismatch!" - if a != out: - print "Double mismatch", len(a), len(out) - else: - print "Match!" except IOError: logger.error("Could not open file for writing: %s", filename) diff --git a/certbot-nginx/certbot_nginx/tls_sni_01.py b/certbot-nginx/certbot_nginx/tls_sni_01.py index d24cb830d..13ae2c358 100644 --- a/certbot-nginx/certbot_nginx/tls_sni_01.py +++ b/certbot-nginx/certbot_nginx/tls_sni_01.py @@ -125,11 +125,6 @@ class NginxTlsSni01(common.TLSSNI01): with open(self.challenge_conf, "w") as new_conf: out = nginxparser.dumps(config) - if "mime" in self.challenge_conf: - print "Weird" - print out - #sys.exit(1) - #nginxparser.dump(config, new_conf) new_conf.write(out) def _make_server_block(self, achall, addrs): From 2cbd680bd543c91f846c98d3bd9972c9d9105b4c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 15 Jun 2016 17:36:53 -0700 Subject: [PATCH 064/264] Hide .spaced from users outside nginxparser.py --- certbot-nginx/certbot_nginx/nginxparser.py | 2 +- certbot-nginx/certbot_nginx/parser.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index d1d17493a..272e39bbc 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -139,7 +139,7 @@ def dumps(blocks): :rtype: str """ - return str(RawNginxDumper(blocks)) + return str(RawNginxDumper(blocks.spaced)) def dump(blocks, _file): diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index 18301de0e..f2faadd58 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -210,7 +210,7 @@ class NginxParser(object): """ for filename in self.parsed: - tree = self.parsed[filename].spaced + tree = self.parsed[filename] if ext: filename = filename + os.path.extsep + ext try: From ff7addefb399ff5ef451a2590755c3976942f101 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 15 Jun 2016 17:57:24 -0700 Subject: [PATCH 065/264] Start fixing tests --- certbot-nginx/certbot_nginx/nginxparser.py | 4 ++-- .../certbot_nginx/tests/nginxparser_test.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 272e39bbc..b2f785d0e 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -22,7 +22,7 @@ class RawNginxParser(object): key = Word(alphanums + "_/+-.") # Matches anything that is not a special character AND any chars in single # or double quotes - value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+") + value = Regex(r"((\".*\")?(\'.*\')?[^\{\};, ]?)+") location = CharsNotIn("{};," + string.whitespace) # modifier for location uri [ = | ~ | ~* | ^~ ] modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~") @@ -30,7 +30,7 @@ class RawNginxParser(object): # rules comment = space + Literal('#') + restOfLine() - assignment = space + key + Optional(space + value, default=None) + semicolon + assignment = space + key + Optional(space + value, default=None) + space + semicolon location_statement = space + Optional(modifier) + Optional(space + location + space) if_statement = space + Literal("if") + space + Regex(r"\(.+\)") + space map_statement = space + Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 80e82c903..0a09b4a64 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -17,23 +17,23 @@ class TestRawNginxParser(unittest.TestCase): def test_assignments(self): parsed = RawNginxParser.assignment.parseString('root /test;').asList() - self.assertEqual(parsed, ['root', '/test']) + self.assertEqual(parsed, ['root', ' ', '/test']) parsed = RawNginxParser.assignment.parseString('root /test;' 'foo bar;').asList() self.assertEqual(parsed, ['root', '/test'], ['foo', 'bar']) def test_blocks(self): parsed = RawNginxParser.block.parseString('foo {}').asList() - self.assertEqual(parsed, [[['foo'], []]]) + self.assertEqual(parsed, [[['foo', ' '], []]]) parsed = RawNginxParser.block.parseString('location /foo{}').asList() - self.assertEqual(parsed, [[['location', '/foo'], []]]) - parsed = RawNginxParser.block.parseString('foo { bar foo; }').asList() - self.assertEqual(parsed, [[['foo'], [['bar', 'foo']]]]) + self.assertEqual(parsed, [[['location', ' ', '/foo'], []]]) + parsed = RawNginxParser.block.parseString('foo { bar foo ; }').asList() + self.assertEqual(parsed, [[['foo', ' '], [[' ', 'bar', ' ', 'foo', ' '], ' ']]]) def test_nested_blocks(self): parsed = RawNginxParser.block.parseString('foo { bar {} }').asList() block, content = FIRST(parsed) - self.assertEqual(FIRST(content), [['bar'], []]) + self.assertEqual(FIRST(content), [[' ', 'bar', ' '], []]) self.assertEqual(FIRST(block), 'foo') def test_dump_as_string(self): From 5a126a92772a451399b564d708f663def3d324cb Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 16 Jun 2016 12:00:43 -0700 Subject: [PATCH 066/264] ignore bad files in initial sweep --- certbot-apache/certbot_apache/configurator.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 9caa4a764..0d6669313 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -511,7 +511,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): """ addrs = set() - args = self.aug.match(path + "/arg") + try: + args = self.aug.match(path + "/arg") + except RuntimeError: + logger.warn("It looks like one of your paths has a character that your version of augeas can't parse") for arg in args: addrs.add(obj.Addr.fromstring(self.parser.get_arg(arg))) is_ssl = False From e5ce03b312c48b43136628b3fd4a756dc04d754c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 16 Jun 2016 12:24:36 -0700 Subject: [PATCH 067/264] More test wrangling --- certbot-nginx/certbot_nginx/nginxparser.py | 4 ++-- .../certbot_nginx/tests/nginxparser_test.py | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index b2f785d0e..272e39bbc 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -22,7 +22,7 @@ class RawNginxParser(object): key = Word(alphanums + "_/+-.") # Matches anything that is not a special character AND any chars in single # or double quotes - value = Regex(r"((\".*\")?(\'.*\')?[^\{\};, ]?)+") + value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+") location = CharsNotIn("{};," + string.whitespace) # modifier for location uri [ = | ~ | ~* | ^~ ] modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~") @@ -30,7 +30,7 @@ class RawNginxParser(object): # rules comment = space + Literal('#') + restOfLine() - assignment = space + key + Optional(space + value, default=None) + space + semicolon + assignment = space + key + Optional(space + value, default=None) + semicolon location_statement = space + Optional(modifier) + Optional(space + location + space) if_statement = space + Literal("if") + space + Regex(r"\(.+\)") + space map_statement = space + Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 0a09b4a64..2a8558bfb 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -5,7 +5,7 @@ import unittest from pyparsing import ParseException from certbot_nginx.nginxparser import ( - RawNginxParser, loads, load, dumps, dump) + RawNginxParser, loads, load, dumps, dump, UnspacedList) from certbot_nginx.tests import util @@ -18,9 +18,8 @@ class TestRawNginxParser(unittest.TestCase): def test_assignments(self): parsed = RawNginxParser.assignment.parseString('root /test;').asList() self.assertEqual(parsed, ['root', ' ', '/test']) - parsed = RawNginxParser.assignment.parseString('root /test;' - 'foo bar;').asList() - self.assertEqual(parsed, ['root', '/test'], ['foo', 'bar']) + parsed = RawNginxParser.assignment.parseString('root /test;foo bar;').asList() + self.assertEqual(parsed, ['root', ' ', '/test'], ['foo', ' ', 'bar']) def test_blocks(self): parsed = RawNginxParser.block.parseString('foo {}').asList() @@ -28,7 +27,7 @@ class TestRawNginxParser(unittest.TestCase): parsed = RawNginxParser.block.parseString('location /foo{}').asList() self.assertEqual(parsed, [[['location', ' ', '/foo'], []]]) parsed = RawNginxParser.block.parseString('foo { bar foo ; }').asList() - self.assertEqual(parsed, [[['foo', ' '], [[' ', 'bar', ' ', 'foo', ' '], ' ']]]) + self.assertEqual(parsed, [[['foo', ' '], [[' ', 'bar', ' ', 'foo '], ' ']]]) def test_nested_blocks(self): parsed = RawNginxParser.block.parseString('foo { bar {} }').asList() @@ -116,7 +115,13 @@ class TestRawNginxParser(unittest.TestCase): def test_dump_as_file(self): with open(util.get_data_filename('nginx.conf')) as handle: - parsed = util.filter_comments(load(handle)) + try: + parsed = load(handle) + except: + handle.seek(0) + print "Failed on", handle.read() + raise + #parsed = util.filter_comments(parsed) parsed[-1][-1].append([['server'], [['listen', '443 ssl'], ['server_name', 'localhost'], @@ -128,12 +133,15 @@ class TestRawNginxParser(unittest.TestCase): [['location', '/'], [['root', 'html'], ['index', 'index.html index.htm']]]]]) + 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) + parsed_new = load(handle) + self.maxDiff = None + self.assertEquals(parsed[0], parsed_new[0]) + self.assertEquals(parsed[1:], parsed_new[1:]) def test_comments(self): with open(util.get_data_filename('minimalistic_comments.conf')) as handle: From 72ba5b72cc2d11deb85385f9ca3813a4f0aecd2e Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 16 Jun 2016 12:25:11 -0700 Subject: [PATCH 068/264] Try to preserve the exact form of end-of-file whitespace --- certbot-nginx/certbot_nginx/nginxparser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 272e39bbc..c8131072c 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -44,7 +44,7 @@ class RawNginxParser(object): Group(ZeroOrMore(Group(comment | assignment) | block) + space).leaveWhitespace() + right_bracket) - script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd + script = OneOrMore(Group(comment | assignment) ^ block) + space + stringEnd script.parseWithTabs() def __init__(self, source): @@ -103,7 +103,7 @@ class RawNginxDumper(object): def __str__(self): """Return the parsed block as a string.""" - return ''.join(self) + '\n' + return ''.join(self) # Shortcut functions to respect Python's serialization interface From 48b03d91cfd6c662866d3d3f061521fae49e46e6 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 16 Jun 2016 12:30:48 -0700 Subject: [PATCH 069/264] return if error --- certbot-apache/certbot_apache/configurator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 0d6669313..647b84bdf 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -515,6 +515,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): args = self.aug.match(path + "/arg") except RuntimeError: logger.warn("It looks like one of your paths has a character that your version of augeas can't parse") + return None for arg in args: addrs.add(obj.Addr.fromstring(self.parser.get_arg(arg))) is_ssl = False @@ -563,7 +564,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): for path in paths: new_vhost = self._create_vhost(path) realpath = os.path.realpath(new_vhost.filep) - if realpath not in vhost_paths.keys(): + if realpath and realpath not in vhost_paths.keys(): vhs.append(new_vhost) vhost_paths[realpath] = new_vhost.filep elif realpath == new_vhost.filep: From 68dd7e9192a40ae7ea32450b2fb696f66ce8757b Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 16 Jun 2016 12:32:34 -0700 Subject: [PATCH 070/264] don't add empty vhosts --- certbot-apache/certbot_apache/configurator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 647b84bdf..57249eea5 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -563,8 +563,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): os.path.basename(path) == "VirtualHost"] for path in paths: new_vhost = self._create_vhost(path) + if not new_vhost: + continue realpath = os.path.realpath(new_vhost.filep) - if realpath and realpath not in vhost_paths.keys(): + if realpath not in vhost_paths.keys(): vhs.append(new_vhost) vhost_paths[realpath] = new_vhost.filep elif realpath == new_vhost.filep: From 50d900718ba0dd3d577edbc67ad4d026e21a7f04 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 16 Jun 2016 16:22:42 -0700 Subject: [PATCH 071/264] add invalid file for cover --- .../apache2/sites-available/old,default.conf | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/old,default.conf diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/old,default.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/old,default.conf new file mode 100644 index 000000000..2bd4e1fe9 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/old,default.conf @@ -0,0 +1,12 @@ + + + ServerName ip-172-30-0-17 + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet From b82ebd9180db60333e87ea55318fa9c48490f200 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 16 Jun 2016 17:17:13 -0700 Subject: [PATCH 072/264] Fix desyncronisation with .spaced when modifying sublists - we now actually write directives again! --- certbot-nginx/certbot_nginx/configurator.py | 18 ++++----- certbot-nginx/certbot_nginx/nginxparser.py | 42 +++++++++++++++++---- certbot-nginx/certbot_nginx/parser.py | 8 +++- 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/certbot-nginx/certbot_nginx/configurator.py b/certbot-nginx/certbot_nginx/configurator.py index 30928e56c..4f46b6a66 100644 --- a/certbot-nginx/certbot_nginx/configurator.py +++ b/certbot-nginx/certbot_nginx/configurator.py @@ -152,17 +152,17 @@ class NginxConfigurator(common.Plugin): "install a cert.") vhost = self.choose_vhost(domain) - cert_directives = [['ssl_certificate', fullchain_path], - ['ssl_certificate_key', key_path]] + cert_directives = [['\n', 'ssl_certificate', ' ', fullchain_path], + ['\n', 'ssl_certificate_key', ' ', key_path]] # OCSP stapling was introduced in Nginx 1.3.7. If we have that version # or greater, add config settings for it. stapling_directives = [] if self.version >= (1, 3, 7): stapling_directives = [ - ['ssl_trusted_certificate', chain_path], - ['ssl_stapling', 'on'], - ['ssl_stapling_verify', 'on']] + ['\n', 'ssl_trusted_certificate', ' ', chain_path], + ['\n', 'ssl_stapling', ' ', 'on'], + ['\n', 'ssl_stapling_verify', ' ', 'on'], ['\n']] if len(stapling_directives) != 0 and not chain_path: raise errors.PluginError( @@ -337,10 +337,10 @@ class NginxConfigurator(common.Plugin): """ snakeoil_cert, snakeoil_key = self._get_snakeoil_paths() - ssl_block = [['listen', '{0} ssl'.format(self.config.tls_sni_01_port)], - ['ssl_certificate', snakeoil_cert], - ['ssl_certificate_key', snakeoil_key], - ['include', self.parser.loc["ssl_options"]]] + ssl_block = [['\n', 'listen', ' ', '{0} ssl'.format(self.config.tls_sni_01_port)], + ['\n', 'ssl_certificate', ' ', snakeoil_cert], + ['\n', 'ssl_certificate_key', ' ', snakeoil_key], + ['\n', 'include', ' ', self.parser.loc["ssl_options"]]] self.parser.add_server_directives( vhost.filep, vhost.names, ssl_block, replace=False) vhost.ssl = True diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index c8131072c..856113f71 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -76,6 +76,9 @@ class RawNginxDumper(object): indentation = "" if spacey(b[0]): indentation = b.pop(0) + if not b: + yield indentation + continue key = b.pop(0) values = b.pop(0) @@ -154,36 +157,58 @@ def dump(blocks, _file): return _file.write(dumps(blocks)) -spacey = lambda x: isinstance(x, str) and x.isspace() +spacey = lambda x: (isinstance(x, str) and x.isspace()) or x == '' class UnspacedList(list): """Wrap a list [of lists], making any whitespace entries magically invisible""" - def __init__(self, list_source): + def __init__(self, list_source, top=False): self.spaced = copy.deepcopy(list(list_source)) # Turn self into a version of the source list that has spaces removed # and all sub-lists also UnspacedList()ed list.__init__(self, list_source) + self.top = self for i, entry in reversed(list(enumerate(self))): if isinstance(entry, list): - list.__setitem__(self, i, UnspacedList(entry)) + sublist = UnspacedList(entry, top=self.top) + list.__setitem__(self, i, sublist) + assert type(self.spaced) == list, "Type madness %r" % type(self.spaced) + self.spaced[i] = sublist.spaced elif spacey(entry): list.__delitem__(self, i) def insert(self, i, x): - self.spaced.insert(i + self._spaces_before(i), x) + if hasattr(x, "spaced"): + self.spaced.insert(i + self._spaces_before(i), x.spaced) + else: + self.spaced.insert(i + self._spaces_before(i), x) list.insert(self, i, x) def append(self, x): - self.spaced.append(x) + print "Unspaced append", x, self + if hasattr(x, "spaced"): + self.spaced.append(x.spaced) + else: + self.spaced.append(x) list.append(self, x) + print "After: aaaaaaaaaaaaaaaaa" + print self.top + print "Aftertop: bbbbbbbbbbbbbbbbb" + print self.top.spaced + #import ipdb + #ipdb.set_trace() def extend(self, x): - self.spaced.extend(x) + if hasattr(x, "spaced"): + self.spaced.extend(x.spaced) + else: + self.spaced.extend(x) + self.logger.debug("Weird, extending regular list %r to Unspaced %r", x, self) list.extend(self, x) def __add__(self, other): + print "Unspaced add", self, other if hasattr(other, "spaced"): # If the thing added to us is an UnspacedList, use its spaced form self.spaced.__add__(other.spaced) @@ -192,7 +217,10 @@ class UnspacedList(list): list.__add__(self, other) def __setitem__(self, i, value): - self.spaced.__setitem__(i + self._spaces_before(i), value) + if hasattr(value, "spaced"): + self.spaced.__setitem__(i + self._spaces_before(i), value.spaced) + else: + self.spaced.__setitem__(i + self._spaces_before(i), value) list.__setitem__(self, i, value) def __delitem__(self, i): diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index f2faadd58..61c719816 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -215,7 +215,7 @@ class NginxParser(object): filename = filename + os.path.extsep + ext try: out = nginxparser.dumps(tree) - #logger.debug('Writing nginx conf tree to %s:\n%s', filename, out) + logger.debug('Writing nginx conf tree to %s:\n%s', filename, out) with open(filename, 'w') as _file: _file.write(out) @@ -506,6 +506,12 @@ def _add_directive(block, directive, replace): See _add_directives for more documentation. """ + directive = nginxparser.UnspacedList(directive) + print "Unspacified", directive.spaced, directive + if len(directive) == 0: + # whitespace + block.append(directive) + return location = -1 # Find the index of a config line where the name of the directive matches # the name of the directive we want to add. From e76e3a953a81769ebdc1e9890dab6254cc48da96 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 16 Jun 2016 17:58:05 -0700 Subject: [PATCH 073/264] Fix test cases - but we're still mangling files in place... --- certbot-nginx/certbot_nginx/nginxparser.py | 37 ++++++------ .../certbot_nginx/tests/nginxparser_test.py | 57 +++++++++---------- 2 files changed, 43 insertions(+), 51 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 856113f71..d7248ad49 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -1,7 +1,6 @@ """Very low-level nginx config parser based on pyparsing.""" import copy import string -import sys from pyparsing import ( Literal, White, Word, alphanums, CharsNotIn, Forward, Group, @@ -68,11 +67,11 @@ class RawNginxDumper(object): def __iter__(self, blocks=None): """Iterates the dumped nginx content.""" blocks = blocks or self.blocks - for b in blocks: - if isinstance(b, str): - yield b + for b0 in blocks: + if isinstance(b0, str): + yield b0 continue - b = copy.deepcopy(b) + b = copy.deepcopy(b0) indentation = "" if spacey(b[0]): indentation = b.pop(0) @@ -96,13 +95,18 @@ class RawNginxDumper(object): gap = "" # Sometimes the parser has stuck some gap whitespace in here; # if so rotate it into gap - if spacey(values): + if values and spacey(values): gap = values - values = b.pop(0) - if values is None: - yield indentation + key + gap + ';' - else: - yield indentation + key + gap + values + ';' + try: + values = b.pop(0) + except: + import ipdb + ipdb.set_trace() + #if values is None: + # yield indentation + key + gap + ';' + #else: + # yield indentation + key + gap + values + ';' + yield indentation + key + gap + values + ';' def __str__(self): """Return the parsed block as a string.""" @@ -168,12 +172,11 @@ class UnspacedList(list): # Turn self into a version of the source list that has spaces removed # and all sub-lists also UnspacedList()ed list.__init__(self, list_source) - self.top = self + self.top = top if top else self for i, entry in reversed(list(enumerate(self))): if isinstance(entry, list): sublist = UnspacedList(entry, top=self.top) list.__setitem__(self, i, sublist) - assert type(self.spaced) == list, "Type madness %r" % type(self.spaced) self.spaced[i] = sublist.spaced elif spacey(entry): list.__delitem__(self, i) @@ -186,18 +189,11 @@ class UnspacedList(list): list.insert(self, i, x) def append(self, x): - print "Unspaced append", x, self if hasattr(x, "spaced"): self.spaced.append(x.spaced) else: self.spaced.append(x) list.append(self, x) - print "After: aaaaaaaaaaaaaaaaa" - print self.top - print "Aftertop: bbbbbbbbbbbbbbbbb" - print self.top.spaced - #import ipdb - #ipdb.set_trace() def extend(self, x): if hasattr(x, "spaced"): @@ -208,7 +204,6 @@ class UnspacedList(list): list.extend(self, x) def __add__(self, other): - print "Unspaced add", self, other if hasattr(other, "spaced"): # If the thing added to us is an UnspacedList, use its spaced form self.spaced.__add__(other.spaced) diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 2a8558bfb..2efacd940 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -36,19 +36,20 @@ class TestRawNginxParser(unittest.TestCase): self.assertEqual(FIRST(block), 'foo') def test_dump_as_string(self): - dumped = dumps([ - ['user', 'www-data'], - [['server'], [ - ['listen', '80'], - ['server_name', 'foo.com'], - ['root', '/home/ubuntu/sites/foo/'], - [['location', '/status'], [ - ['check_status', None], - [['types'], [['image/jpeg', 'jpg']]], + dumped = dumps(UnspacedList([ + ['user', ' ', 'www-data'], + [['\n', 'server', ' '], [ + ['\n ', 'listen', ' ', '80'], + ['\n ', 'server_name', ' ', 'foo.com'], + ['\n ', 'root', ' ', '/home/ubuntu/sites/foo/'], + [['\n\n ', 'location', ' ', '/status', ' '], [ + ['\n ', 'check_status', ''], + [['\n\n ', 'types', ' '], + [['\n ', 'image/jpeg', ' ', 'jpg']]], ]] - ]]]) + ]]])) - self.assertEqual(dumped, + self.assertEqual(dumped.split('\n'), 'user www-data;\n' 'server {\n' ' listen 80;\n' @@ -59,10 +60,7 @@ class TestRawNginxParser(unittest.TestCase): ' check_status;\n' '\n' ' types {\n' - ' image/jpeg jpg;\n' - ' }\n' - ' }\n' - '}\n') + ' image/jpeg jpg;}}}'.split('\n')) def test_parse_from_file(self): with open(util.get_data_filename('foo.conf')) as handle: @@ -122,18 +120,17 @@ class TestRawNginxParser(unittest.TestCase): print "Failed on", handle.read() raise #parsed = util.filter_comments(parsed) - parsed[-1][-1].append([['server'], - [['listen', '443 ssl'], - ['server_name', 'localhost'], - ['ssl_certificate', 'cert.pem'], - ['ssl_certificate_key', 'cert.key'], - ['ssl_session_cache', 'shared:SSL:1m'], - ['ssl_session_timeout', '5m'], - ['ssl_ciphers', 'HIGH:!aNULL:!MD5'], - [['location', '/'], - [['root', 'html'], - ['index', 'index.html index.htm']]]]]) - + parsed[-1][-1].append(UnspacedList([['server'], + [['listen', ' ', '443 ssl'], + ['server_name', ' ', 'localhost'], + ['ssl_certificate', ' ', 'cert.pem'], + ['ssl_certificate_key', ' ', 'cert.key'], + ['ssl_session_cache', ' ', 'shared:SSL:1m'], + ['ssl_session_timeout', ' ', '5m'], + ['ssl_ciphers', ' ', 'HIGH:!aNULL:!MD5'], + [['location', ' ', '/'], + [['root', ' ', 'html'], + ['index', ' ', 'index.html index.htm']]]]])) with open(util.get_data_filename('nginx.new.conf'), 'w') as handle: dump(parsed, handle) @@ -159,11 +156,11 @@ class TestRawNginxParser(unittest.TestCase): ['#', " Use bar.conf when it's a full moon!"], ['include', 'foo.conf'], ['#', ' Kilroy was here'], - ['check_status', None], + ['check_status'], [['server'], - [['#', ''], + [['#'], ['#', " Don't forget to open up your firewall!"], - ['#', ''], + ['#'], ['listen', '1234'], ['#', ' listen 80;']]], ]) From da250a4f4bfb5e8feb6efda25745a03cbcd23041 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 16 Jun 2016 17:59:49 -0700 Subject: [PATCH 074/264] Experimentally delete these output files --- .../etc_nginx/minimalistic_comments.new.conf | 11 --- .../tests/testdata/etc_nginx/nginx.new.conf | 83 ------------------- 2 files changed, 94 deletions(-) delete mode 100644 certbot-nginx/certbot_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf delete mode 100644 certbot-nginx/certbot_nginx/tests/testdata/etc_nginx/nginx.new.conf diff --git a/certbot-nginx/certbot_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf b/certbot-nginx/certbot_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf deleted file mode 100644 index d1b7be91e..000000000 --- a/certbot-nginx/certbot_nginx/tests/testdata/etc_nginx/minimalistic_comments.new.conf +++ /dev/null @@ -1,11 +0,0 @@ -# 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/certbot-nginx/certbot_nginx/tests/testdata/etc_nginx/nginx.new.conf b/certbot-nginx/certbot_nginx/tests/testdata/etc_nginx/nginx.new.conf deleted file mode 100644 index 59c1c968f..000000000 --- a/certbot-nginx/certbot_nginx/tests/testdata/etc_nginx/nginx.new.conf +++ /dev/null @@ -1,83 +0,0 @@ -user nobody; -worker_processes 1; -error_log logs/error.log; -error_log logs/error.log notice; -error_log logs/error.log info; -pid logs/nginx.pid; -events { - worker_connections 1024; -} -include foo.conf; -http { - include mime.types; - include sites-enabled/*; - default_type application/octet-stream; - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - access_log logs/access.log main; - sendfile on; - 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; - ssl_certificate cert.pem; - ssl_certificate_key cert.key; - ssl_session_cache shared:SSL:1m; - ssl_session_timeout 5m; - ssl_ciphers HIGH:!aNULL:!MD5; - - location / { - root html; - index index.html index.htm; - } - } -} From 9459daa6d03940f6c8fdfe169807a32df2a36b14 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 16 Jun 2016 18:04:13 -0700 Subject: [PATCH 075/264] Delete new.conf files after tests Not least, to prevent git conflicts with old branches --- .../certbot_nginx/tests/nginxparser_test.py | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 2efacd940..87c7a0430 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -136,9 +136,12 @@ class TestRawNginxParser(unittest.TestCase): dump(parsed, handle) with open(util.get_data_filename('nginx.new.conf')) as handle: parsed_new = load(handle) - self.maxDiff = None - self.assertEquals(parsed[0], parsed_new[0]) - self.assertEquals(parsed[1:], parsed_new[1:]) + try: + self.maxDiff = None + self.assertEquals(parsed[0], parsed_new[0]) + self.assertEquals(parsed[1:], parsed_new[1:]) + finally: + os.unlink(util.get_data_filename('nginx.new.conf')) def test_comments(self): with open(util.get_data_filename('minimalistic_comments.conf')) as handle: @@ -150,20 +153,23 @@ class TestRawNginxParser(unittest.TestCase): with open(util.get_data_filename('minimalistic_comments.new.conf')) as handle: parsed_new = load(handle) - self.assertEquals(parsed, parsed_new) + try: + 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'], - [['server'], - [['#'], - ['#', " Don't forget to open up your firewall!"], - ['#'], - ['listen', '1234'], - ['#', ' listen 80;']]], - ]) + self.assertEqual(parsed_new, [ + ['#', " 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;']]], + ]) + finally: + os.unlink(util.get_data_filename('minimalistic_comments.new.conf')) def test_issue_518(self): parsed = loads('if ($http_accept ~* "webp") { set $webp "true"; }') From efd1ff46c696294341f9f8537e25023c8d01f196 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 16 Jun 2016 18:18:33 -0700 Subject: [PATCH 076/264] Lint --- certbot-nginx/certbot_nginx/nginxparser.py | 10 ++++------ certbot-nginx/certbot_nginx/parser.py | 1 - certbot-nginx/certbot_nginx/tests/nginxparser_test.py | 1 + certbot-nginx/certbot_nginx/tls_sni_01.py | 4 +--- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index d7248ad49..1664f94cf 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -1,5 +1,6 @@ """Very low-level nginx config parser based on pyparsing.""" import copy +import logging import string from pyparsing import ( @@ -8,6 +9,7 @@ from pyparsing import ( from pyparsing import stringEnd from pyparsing import restOfLine +logger = logging.getLogger(__name__) class RawNginxParser(object): # pylint: disable=expression-not-assigned @@ -97,11 +99,7 @@ class RawNginxDumper(object): # if so rotate it into gap if values and spacey(values): gap = values - try: - values = b.pop(0) - except: - import ipdb - ipdb.set_trace() + values = b.pop(0) #if values is None: # yield indentation + key + gap + ';' #else: @@ -200,7 +198,7 @@ class UnspacedList(list): self.spaced.extend(x.spaced) else: self.spaced.extend(x) - self.logger.debug("Weird, extending regular list %r to Unspaced %r", x, self) + logger.debug("Weird, extending regular list %r to Unspaced %r", x, self) list.extend(self, x) def __add__(self, other): diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index 61c719816..21127bc08 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -4,7 +4,6 @@ import logging import os import pyparsing import re -import sys from certbot import errors diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 87c7a0430..7354c118c 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -1,5 +1,6 @@ """Test for certbot_nginx.nginxparser.""" import operator +import os import unittest from pyparsing import ParseException diff --git a/certbot-nginx/certbot_nginx/tls_sni_01.py b/certbot-nginx/certbot_nginx/tls_sni_01.py index 13ae2c358..e4c5d31a6 100644 --- a/certbot-nginx/certbot_nginx/tls_sni_01.py +++ b/certbot-nginx/certbot_nginx/tls_sni_01.py @@ -3,7 +3,6 @@ import itertools import logging import os -import sys from certbot import errors from certbot.plugins import common @@ -124,8 +123,7 @@ class NginxTlsSni01(common.TLSSNI01): True, self.challenge_conf) with open(self.challenge_conf, "w") as new_conf: - out = nginxparser.dumps(config) - new_conf.write(out) + nginxparser.dump(config, new_conf) def _make_server_block(self, achall, addrs): """Creates a server block for a challenge. From 6666ff25d49deb74c7976dd12a9a384ddde39083 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 17 Jun 2016 03:57:49 +0200 Subject: [PATCH 077/264] Moving import dialog to the top of the file --- certbot/tests/cli_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 9a2009e43..9c81c070b 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -2,6 +2,7 @@ from __future__ import print_function import argparse +import dialog import functools import itertools import os @@ -923,8 +924,6 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods traceback.format_exception_only(KeyboardInterrupt, interrupt))) # Test dialog errors - - import dialog exception = dialog.error(message="test message") main._handle_exception( dialog.DialogError, exc_value=exception, trace=None, config=None) From 31d9fc7d865c4567f56b3991c90e915a620aaa2e Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 17 Jun 2016 04:13:44 +0200 Subject: [PATCH 078/264] Adding --skip-missing-interpreters to constributing.rst "Submitting a pull request" section --- docs/contributing.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 9ceb0fbdd..633af19c6 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -317,7 +317,9 @@ Steps: 3. Run ``./pep8.travis.sh`` to do a cursory check of your code style. Fix any errors. 4. Run ``tox -e lint`` to check for pylint errors. Fix any errors. -5. Run ``tox`` to run the entire test suite including coverage. Fix any errors. +5. Run ``tox --skip-missing-interpreters`` to run the entire test suite + including coverage. The ``--skip-missing-interpreters`` argument ignores + missing versions of Python needed for running the tests. Fix any errors. 6. If your code touches communication with an ACME server/Boulder, you should run the integration tests, see `integration`_. See `Known Issues`_ for some common failures that have nothing to do with your code. From f5282ed2de63342d09e593cb1a9338383ab2b9b1 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 17 Jun 2016 10:48:54 -0700 Subject: [PATCH 079/264] Show lines missing test coverage in test output --- .coveragerc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..087900105 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +[report] +# show lines missing coverage in output +show_missing = True From 340e4dc0f27f5a2db86e2e639f5392723bf1204e Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 17 Jun 2016 10:50:02 -0700 Subject: [PATCH 080/264] Remove unused nosexcover dependency --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 53fde5282..21cda901a 100644 --- a/setup.py +++ b/setup.py @@ -69,7 +69,6 @@ dev_extras = [ 'astroid==1.3.5', 'coverage', 'nose', - 'nosexcover', 'pep8', 'pylint==1.4.2', # upstream #248 'tox', From ba0a0e9c2664ffade3bc916cf5fc10d8c5d57a53 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 17 Jun 2016 14:32:24 -0700 Subject: [PATCH 081/264] Tests for UnspacedList --- certbot-nginx/certbot_nginx/nginxparser.py | 20 +++---- .../certbot_nginx/tests/nginxparser_test.py | 54 +++++++++++++++++++ 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 1664f94cf..caf6fe725 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -164,16 +164,15 @@ spacey = lambda x: (isinstance(x, str) and x.isspace()) or x == '' class UnspacedList(list): """Wrap a list [of lists], making any whitespace entries magically invisible""" - def __init__(self, list_source, top=False): + def __init__(self, list_source): self.spaced = copy.deepcopy(list(list_source)) # Turn self into a version of the source list that has spaces removed # and all sub-lists also UnspacedList()ed list.__init__(self, list_source) - self.top = top if top else self for i, entry in reversed(list(enumerate(self))): if isinstance(entry, list): - sublist = UnspacedList(entry, top=self.top) + sublist = UnspacedList(entry) list.__setitem__(self, i, sublist) self.spaced[i] = sublist.spaced elif spacey(entry): @@ -202,12 +201,9 @@ class UnspacedList(list): list.extend(self, x) def __add__(self, other): - if hasattr(other, "spaced"): - # If the thing added to us is an UnspacedList, use its spaced form - self.spaced.__add__(other.spaced) - else: - self.spaced.__add__(other) - list.__add__(self, other) + l = copy.deepcopy(self) + l.extend(other) + return l def __setitem__(self, i, value): if hasattr(value, "spaced"): @@ -220,6 +216,12 @@ class UnspacedList(list): self.spaced.__delitem__(i + self._spaces_before(i)) list.__delitem__(self, i) + def __deepcopy__(self, memo): + l = UnspacedList(self[:]) + l.spaced = copy.deepcopy(self.spaced) + return l + + def _spaces_before(self, idx): "Count the number of spaces in the spaced list before pos idx in the spaceless one" spaces = 0 diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 7354c118c..e78adfac1 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -1,4 +1,5 @@ """Test for certbot_nginx.nginxparser.""" +import copy import operator import os import unittest @@ -180,5 +181,58 @@ class TestRawNginxParser(unittest.TestCase): [['set', '$webp "true"']]] ]) +class TestUnspacedList(unittest.TestCase): + """Test the raw low-level Nginx config parser.""" + def setUp(self): + self.a = ["\n ", "things", " ", "quirk"] + self.b = ["y", " "] + self.l = self.a[:] + self.l2 = self.b[:] + self.ul = UnspacedList(self.l) + self.ul2 = UnspacedList(self.l2) + + def test_construction(self): + self.assertEqual(self.ul, ["things", "quirk"]) + self.assertEqual(self.ul2, ["y"]) + + def test_append(self): + ul3 = copy.deepcopy(self.ul) + ul3.append("wise") + self.assertEqual(ul3, ["things", "quirk", "wise"]) + self.assertEqual(ul3.spaced, self.a + ["wise"]) + + def test_add(self): + ul3 = self.ul + self.ul2 + self.assertEqual(ul3, ["things", "quirk", "y"]) + self.assertEqual(ul3.spaced, self.a + self.b) + self.assertEqual(self.ul.spaced, self.a) + ul3 = self.ul + self.l2 + self.assertEqual(ul3, ["things", "quirk", "y", " "]) + self.assertEqual(ul3.spaced, self.a + self.b) + + def test_extend(self): + ul3 = copy.deepcopy(self.ul) + ul3.extend(self.ul2) + self.assertEqual(ul3, ["things", "quirk", "y"]) + self.assertEqual(ul3.spaced, self.a + self.b) + self.assertEqual(self.ul.spaced, self.a) + + def test_set(self): + ul3 = copy.deepcopy(self.ul) + ul3[0] = "zither" + l = ["\n ", "zather", "zest"] + ul3[1] = UnspacedList(l) + self.assertEqual(ul3, ["zither", ["zather", "zest"]]) + self.assertEqual(ul3.spaced, [self.a[0], "zither", " ", l]) + + def test_rawlists(self): + ul3 = copy.deepcopy(self.ul) + ul3.insert(0, "some") + ul3.append("why") + ul3.extend(["did", "whether"]) + del ul3[2] + self.assertEqual(ul3, ["some", "things", "why", "did", "whether"]) + + if __name__ == '__main__': unittest.main() # pragma: no cover From b2c36f85274176a31ed16bfe7b210793165d3fac Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 17 Jun 2016 14:39:55 -0700 Subject: [PATCH 082/264] Lint & test fix --- certbot-nginx/certbot_nginx/nginxparser.py | 2 +- certbot-nginx/certbot_nginx/tests/parser_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index caf6fe725..765194806 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -216,7 +216,7 @@ class UnspacedList(list): self.spaced.__delitem__(i + self._spaces_before(i)) list.__delitem__(self, i) - def __deepcopy__(self, memo): + def __deepcopy__(self, unused_memo): l = UnspacedList(self[:]) l.spaced = copy.deepcopy(self.spaced) return l diff --git a/certbot-nginx/certbot_nginx/tests/parser_test.py b/certbot-nginx/certbot_nginx/tests/parser_test.py index 8ac995dfc..6d046178a 100644 --- a/certbot-nginx/certbot_nginx/tests/parser_test.py +++ b/certbot-nginx/certbot_nginx/tests/parser_test.py @@ -126,7 +126,7 @@ class NginxParserTest(util.NginxTest): nparser.add_server_directives(nparser.abs_path('nginx.conf'), set(['localhost', r'~^(www\.)?(example|bar)\.']), - [['foo', 'bar'], ['ssl_certificate', + [['foo', 'bar'], ['\n ', 'ssl_certificate', ' ', '/etc/ssl/cert.pem']], replace=False) ssl_re = re.compile(r'\n\s+ssl_certificate /etc/ssl/cert.pem') From 6156b452bcf7c924f12c334e7094ff5a9049ee37 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 24 May 2016 14:04:55 -0500 Subject: [PATCH 083/264] Fix FQDN checks. --- certbot/util.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/certbot/util.py b/certbot/util.py index 35c599737..9739e8d2f 100644 --- a/certbot/util.py +++ b/certbot/util.py @@ -423,14 +423,17 @@ def enforce_domain_sanity(domain): # It wasn't an IP address, so that's good pass - # FQDN checks from - # http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/ - # Characters used, domain parts < 63 chars, tld > 1 < 64 chars - # first and last char is not "-" - fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(? 256: + raise errors.ConfigurationError(msg + "it is too long.") + return domain From a7a2049d69debf457cec637ddf4e5c9ca9848c9f Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 24 May 2016 14:14:44 -0500 Subject: [PATCH 084/264] Fix FQDN tests. --- certbot/tests/cli_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 9c81c070b..896550837 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -342,11 +342,11 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods # FQDN self.assertRaises(errors.ConfigurationError, self._call, - ['-d', 'comma,gotwrong.tld']) + ['-d', 'a' * 64]) # FQDN 2 self.assertRaises(errors.ConfigurationError, self._call, - ['-d', 'illegal.character=.tld']) + ['-d', (('a' * 50) + '.') * 10]) # Wildcard self.assertRaises(errors.ConfigurationError, self._call, From 2625daad75a9233ee0f2d57576adff23e6db1779 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 24 May 2016 14:25:29 -0500 Subject: [PATCH 085/264] Fix more FQDN tests in ops_test.py --- certbot/tests/display/ops_test.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/certbot/tests/display/ops_test.py b/certbot/tests/display/ops_test.py index 3aff37d86..26f67b69f 100644 --- a/certbot/tests/display/ops_test.py +++ b/certbot/tests/display/ops_test.py @@ -248,9 +248,9 @@ class ChooseNamesTest(unittest.TestCase): def test_get_valid_domains(self): from certbot.display.ops import get_valid_domains all_valid = ["example.com", "second.example.com", - "also.example.com"] - all_invalid = ["xn--ls8h.tld", "*.wildcard.com", "notFQDN", - "uniçodé.com"] + "also.example.com", "under_score.example.com", + "justtld"] + all_invalid = ["xn--ls8h.tld", "*.wildcard.com", "uniçodé.com"] two_valid = ["example.com", "xn--ls8h.tld", "also.example.com"] self.assertEqual(get_valid_domains(all_valid), all_valid) self.assertEqual(get_valid_domains(all_invalid), []) @@ -276,19 +276,18 @@ class ChooseNamesTest(unittest.TestCase): mock_util().input.return_value = (display_util.OK, "xn--ls8h.tld") self.assertEqual(_choose_names_manually(), []) - # non-FQDN and no retry - mock_util().input.return_value = (display_util.OK, - "notFQDN") - self.assertEqual(_choose_names_manually(), []) - # Two valid domains + # Valid domains mock_util().input.return_value = (display_util.OK, ("example.com," + "under_score.example.com," + "justtld," "valid.example.com")) self.assertEqual(_choose_names_manually(), - ["example.com", "valid.example.com"]) + ["example.com", "under_score.example.com", + "justtld", "valid.example.com"]) # Three iterations mock_util().input.return_value = (display_util.OK, - "notFQDN") + "uniçodé.com") yn = mock.MagicMock() yn.side_effect = [True, True, False] mock_util().yesno = yn From a148d2ddfa60206f1a648dd7c9851e5921ea1805 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Fri, 17 Jun 2016 18:58:48 -0500 Subject: [PATCH 086/264] Limit domains to 255 octets. --- certbot/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/util.py b/certbot/util.py index 9739e8d2f..301fc669b 100644 --- a/certbot/util.py +++ b/certbot/util.py @@ -431,7 +431,7 @@ def enforce_domain_sanity(domain): for l in labels: if not 0 < len(l) < 64: raise errors.ConfigurationError(msg + "label {0} is too long.".format(l)) - if len(domain) > 256: + if len(domain) > 255: raise errors.ConfigurationError(msg + "it is too long.") return domain From 679101cfb0659eba484a625bc244a595d86edf93 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 17 Jun 2016 18:29:45 -0700 Subject: [PATCH 087/264] Object printing improvements --- certbot-nginx/certbot_nginx/obj.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/certbot-nginx/certbot_nginx/obj.py b/certbot-nginx/certbot_nginx/obj.py index 0d1151f39..20f9f0a6f 100644 --- a/certbot-nginx/certbot_nginx/obj.py +++ b/certbot-nginx/certbot_nginx/obj.py @@ -85,6 +85,9 @@ class Addr(common.Addr): return parts + def __repr__(self): + return "Addr(" + self.__str__() + ")" + def __eq__(self, other): if isinstance(other, self.__class__): return (self.tup == other.tup and @@ -126,6 +129,9 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods "enabled: %s" % (self.filep, addr_str, self.names, self.ssl, self.enabled)) + def __repr__(self): + return "VirtualHost(" + self.__str__().replace("\n",",") + ")\n" + def __eq__(self, other): if isinstance(other, self.__class__): return (self.filep == other.filep and From 7bcc23d9f54fea226538dc3d6d4e7f2d37232977 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 17 Jun 2016 18:30:12 -0700 Subject: [PATCH 088/264] Debugging --- certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py b/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py index 3264d6ed3..19d22365d 100644 --- a/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py +++ b/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py @@ -12,6 +12,7 @@ from certbot import errors from certbot.plugins import common_test from certbot.tests import acme_util +from certbot_nginx import nginxparser from certbot_nginx import obj from certbot_nginx.tests import util @@ -132,16 +133,21 @@ class TlsSniPerformTest(util.NginxTest): http = self.sni.configurator.parser.parsed[ self.sni.configurator.parser.loc["root"]][-1] + print "http", http + #print "SPACED\n", http.spaced self.assertTrue(['include', self.sni.challenge_conf] in http[1]) vhosts = self.sni.configurator.parser.get_vhosts() + print "Got", vhosts vhs = [vh for vh in vhosts if vh.filep == self.sni.challenge_conf] + print "And now", vhs for vhost in vhs: if vhost.addrs == set(v_addr1): response = self.achalls[0].response(self.account_key) else: response = self.achalls[2].response(self.account_key) + print vhost.addrs, set(v_addr2) self.assertEqual(vhost.addrs, set(v_addr2)) self.assertEqual(vhost.names, set([response.z_domain])) From 3c9f4d5fc73204ce9aa840e4eabd8b3dbd01cf74 Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Sat, 18 Jun 2016 23:50:30 +0300 Subject: [PATCH 089/264] If port is set for any IP, do not attempt to autoconfigure --- certbot-apache/certbot_apache/configurator.py | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index e4c06ba7e..392670985 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -624,11 +624,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): # Note: This could be made to also look for ip:443 combo listens = [self.parser.get_arg(x).split()[0] for x in self.parser.find_dir("Listen")] + # In case no Listens are set (which really is a broken apache config) if not listens: listens = ["80"] - if port in listens: + + # Listen already in place + if self._has_port_already(listens, port): return + for listen in listens: # For any listen statement, check if the machine also listens on # Port 443. If not, add such a listen statement. @@ -664,6 +668,23 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): self.parser.loc["listen"]) listens.append("%s:%s" % (ip, port)) + def _has_port_already(self, listens, port): + """Helper method for prepare_server_https to find out if user + already has an active Listen statement for the port we need + + :param list listens: List of listen variables + :param string port: Port in question + """ + + if port in listens: + return True + # Check if Apache is already listening on a specific IP + for listen in listens: + if len(listen.split(":")) > 1: + # Ugly but takes care of protocol def, eg: 1.1.1.1:443 https + if listen.split(":")[-1].split(" ")[0] == port: + return True + def prepare_https_modules(self, temp): """Helper method for prepare_server_https, taking care of enabling needed modules From e4f88506cc84b852b6bc339cede9ed8abfebc2db Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 18 Jun 2016 14:52:07 -0700 Subject: [PATCH 090/264] Fix TLS_SNI & associated tests --- certbot-nginx/certbot_nginx/nginxparser.py | 20 +++++++++++++----- certbot-nginx/certbot_nginx/obj.py | 2 +- certbot-nginx/certbot_nginx/parser.py | 7 +++++-- .../certbot_nginx/tests/configurator_test.py | 2 +- .../certbot_nginx/tests/nginxparser_test.py | 4 ++-- .../certbot_nginx/tests/tls_sni_01_test.py | 5 ----- certbot-nginx/certbot_nginx/tests/util.py | 11 +++++++--- certbot-nginx/certbot_nginx/tls_sni_01.py | 21 ++++++++++--------- 8 files changed, 43 insertions(+), 29 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 765194806..6b3896fd9 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -165,6 +165,7 @@ class UnspacedList(list): """Wrap a list [of lists], making any whitespace entries magically invisible""" def __init__(self, list_source): + # ensure our argument is not a generator, and duplicate any sublists self.spaced = copy.deepcopy(list(list_source)) # Turn self into a version of the source list that has spaces removed @@ -173,16 +174,25 @@ class UnspacedList(list): for i, entry in reversed(list(enumerate(self))): if isinstance(entry, list): sublist = UnspacedList(entry) - list.__setitem__(self, i, sublist) + if sublist != [] or sublist.spaced == []: + list.__setitem__(self, i, sublist) + else: + # if a sublist is exclusively spacey entries, it might + # choke the high level parser, so make it disappear + list.__delitem__(self, i) self.spaced[i] = sublist.spaced elif spacey(entry): - list.__delitem__(self, i) + # don't delete comments + if "#" not in self[:i]: + list.__delitem__(self, i) def insert(self, i, x): - if hasattr(x, "spaced"): - self.spaced.insert(i + self._spaces_before(i), x.spaced) - else: + if not isinstance(x, list): # str or None self.spaced.insert(i + self._spaces_before(i), x) + else: + if not hasattr(x, "spaced"): + x = UnspacedList(x) + self.spaced.insert(i + self._spaces_before(i), x.spaced) list.insert(self, i, x) def append(self, x): diff --git a/certbot-nginx/certbot_nginx/obj.py b/certbot-nginx/certbot_nginx/obj.py index 20f9f0a6f..a559b5e02 100644 --- a/certbot-nginx/certbot_nginx/obj.py +++ b/certbot-nginx/certbot_nginx/obj.py @@ -130,7 +130,7 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods self.names, self.ssl, self.enabled)) def __repr__(self): - return "VirtualHost(" + self.__str__().replace("\n",",") + ")\n" + return "VirtualHost(" + self.__str__().replace("\n",", ") + ")\n" def __eq__(self, other): if isinstance(other, self.__class__): diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index 21127bc08..31595d56d 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -1,4 +1,5 @@ """NginxParser is a member object of the NginxConfigurator class.""" +import copy import glob import logging import os @@ -113,6 +114,7 @@ class NginxParser(object): for filename in servers: for server in servers[filename]: # Parse the server block into a VirtualHost object + parsed_server = parse_server(server) vhost = obj.VirtualHost(filename, parsed_server['addrs'], @@ -132,7 +134,7 @@ class NginxParser(object): :rtype: list """ - result = list(block) # Copy the list to keep self.parsed idempotent + result = copy.deepcopy(block) # Copy the list to keep self.parsed idempotent for directive in block: if _is_include_directive(directive): included_files = glob.glob( @@ -465,6 +467,8 @@ def parse_server(server): 'names': set()} for directive in server: + if not directive: + continue if directive[0] == 'listen': addr = obj.Addr.fromstring(directive[1]) parsed_server['addrs'].add(addr) @@ -506,7 +510,6 @@ def _add_directive(block, directive, replace): """ directive = nginxparser.UnspacedList(directive) - print "Unspacified", directive.spaced, directive if len(directive) == 0: # whitespace block.append(directive) diff --git a/certbot-nginx/certbot_nginx/tests/configurator_test.py b/certbot-nginx/certbot_nginx/tests/configurator_test.py index 30f287249..a1d0e75cc 100644 --- a/certbot-nginx/certbot_nginx/tests/configurator_test.py +++ b/certbot-nginx/certbot_nginx/tests/configurator_test.py @@ -83,7 +83,7 @@ class NginxConfiguratorTest(util.NginxTest): filep = self.config.parser.abs_path('sites-enabled/example.com') self.config.parser.add_server_directives( filep, set(['.example.com', 'example.*']), - [['listen', '5001 ssl']], + [['listen', ' ', '5001 ssl']], replace=False) self.config.save() diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index e78adfac1..2e8011443 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -164,9 +164,9 @@ class TestRawNginxParser(unittest.TestCase): ['#', ' Kilroy was here'], ['check_status'], [['server'], - [['#'], + [['#', ''], ['#', " Don't forget to open up your firewall!"], - ['#'], + ['#', ''], ['listen', '1234'], ['#', ' listen 80;']]], ]) diff --git a/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py b/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py index 19d22365d..51301145c 100644 --- a/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py +++ b/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py @@ -133,21 +133,16 @@ class TlsSniPerformTest(util.NginxTest): http = self.sni.configurator.parser.parsed[ self.sni.configurator.parser.loc["root"]][-1] - print "http", http - #print "SPACED\n", http.spaced self.assertTrue(['include', self.sni.challenge_conf] in http[1]) vhosts = self.sni.configurator.parser.get_vhosts() - print "Got", vhosts vhs = [vh for vh in vhosts if vh.filep == self.sni.challenge_conf] - print "And now", vhs for vhost in vhs: if vhost.addrs == set(v_addr1): response = self.achalls[0].response(self.account_key) else: response = self.achalls[2].response(self.account_key) - print vhost.addrs, set(v_addr2) self.assertEqual(vhost.addrs, set(v_addr2)) self.assertEqual(vhost.names, set([response.z_domain])) diff --git a/certbot-nginx/certbot_nginx/tests/util.py b/certbot-nginx/certbot_nginx/tests/util.py index ddacd041b..4ea4a03a7 100644 --- a/certbot-nginx/certbot_nginx/tests/util.py +++ b/certbot-nginx/certbot_nginx/tests/util.py @@ -1,4 +1,5 @@ """Common utilities for certbot_nginx.""" +import copy import os import pkg_resources import unittest @@ -16,6 +17,7 @@ from certbot.plugins import common from certbot_nginx import constants from certbot_nginx import configurator +from certbot_nginx import nginxparser class NginxTest(unittest.TestCase): # pylint: disable=too-few-public-methods @@ -82,12 +84,15 @@ def filter_comments(tree): def traverse(tree): """Generator dropping comment nodes""" - for key, values in tree: + for entry in tree: + key, values = entry if isinstance(key, list): - yield [key, filter_comments(values)] + new = copy.deepcopy(entry) + new[1] = filter_comments(values) + yield new else: if key != '#': - yield [key, values] + yield entry return list(traverse(tree)) diff --git a/certbot-nginx/certbot_nginx/tls_sni_01.py b/certbot-nginx/certbot_nginx/tls_sni_01.py index e4c5d31a6..a9f31b84a 100644 --- a/certbot-nginx/certbot_nginx/tls_sni_01.py +++ b/certbot-nginx/certbot_nginx/tls_sni_01.py @@ -93,10 +93,10 @@ class NginxTlsSni01(common.TLSSNI01): # Add the 'include' statement for the challenges if it doesn't exist # already in the main config included = False - include_directive = ['include', self.challenge_conf] + include_directive = ['include', ' ', self.challenge_conf] root = self.configurator.parser.loc["root"] - bucket_directive = ['server_names_hash_bucket_size', '128'] + bucket_directive = ['server_names_hash_bucket_size', ' ', '128'] main = self.configurator.parser.parsed[root] for key, body in main: @@ -118,6 +118,7 @@ class NginxTlsSni01(common.TLSSNI01): config = [self._make_server_block(pair[0], pair[1]) for pair in itertools.izip(self.achalls, ll_addrs)] + config = nginxparser.UnspacedList(config) self.configurator.reverter.register_file_creation( True, self.challenge_conf) @@ -142,19 +143,19 @@ class NginxTlsSni01(common.TLSSNI01): document_root = os.path.join( self.configurator.config.work_dir, "tls_sni_01_page") - block = [['listen', str(addr)] for addr in addrs] + block = [['listen', ' ', str(addr)] for addr in addrs] - block.extend([['server_name', + block.extend([['server_name', ' ', achall.response(achall.account_key).z_domain], - ['include', self.configurator.parser.loc["ssl_options"]], + ['include', ' ', self.configurator.parser.loc["ssl_options"]], # access and error logs necessary for # integration testing (non-root) - ['access_log', os.path.join( + ['access_log', ' ', os.path.join( self.configurator.config.work_dir, 'access.log')], - ['error_log', os.path.join( + ['error_log', ' ', os.path.join( self.configurator.config.work_dir, 'error.log')], - ['ssl_certificate', self.get_cert_path(achall)], - ['ssl_certificate_key', self.get_key_path(achall)], - [['location', '/'], [['root', document_root]]]]) + ['ssl_certificate', ' ', self.get_cert_path(achall)], + ['ssl_certificate_key', ' ', self.get_key_path(achall)], + [['location', ' ', '/'], [['root', ' ', document_root]]]]) return [['server'], block] From 1e59bf81123df94210f5a4627e1af7e444b1eff2 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 18 Jun 2016 14:53:17 -0700 Subject: [PATCH 091/264] fixup --- certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py b/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py index 51301145c..3264d6ed3 100644 --- a/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py +++ b/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py @@ -12,7 +12,6 @@ from certbot import errors from certbot.plugins import common_test from certbot.tests import acme_util -from certbot_nginx import nginxparser from certbot_nginx import obj from certbot_nginx.tests import util From b663ec039ed41012f89d2dcac950be323a7d3a19 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 18 Jun 2016 15:05:48 -0700 Subject: [PATCH 092/264] lint --- certbot-nginx/certbot_nginx/obj.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-nginx/certbot_nginx/obj.py b/certbot-nginx/certbot_nginx/obj.py index a559b5e02..f5ac88f6c 100644 --- a/certbot-nginx/certbot_nginx/obj.py +++ b/certbot-nginx/certbot_nginx/obj.py @@ -130,7 +130,7 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods self.names, self.ssl, self.enabled)) def __repr__(self): - return "VirtualHost(" + self.__str__().replace("\n",", ") + ")\n" + return "VirtualHost(" + self.__str__().replace("\n", ", ") + ")\n" def __eq__(self, other): if isinstance(other, self.__class__): From d2b4ae57404486f5d5b34aeaea6fc3637c263a75 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 18 Jun 2016 15:17:59 -0700 Subject: [PATCH 093/264] Consistently coerce inbound data to Unspacines --- certbot-nginx/certbot_nginx/nginxparser.py | 48 ++++++++++++---------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 6b3896fd9..d0f53e1a8 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -186,29 +186,37 @@ class UnspacedList(list): if "#" not in self[:i]: list.__delitem__(self, i) - def insert(self, i, x): - if not isinstance(x, list): # str or None - self.spaced.insert(i + self._spaces_before(i), x) + def _coerce(self, inbound): + """ + Coerce some inbound object to be appropriately usable in this object + + :param inbound: string or None or list or UnspacedList + :returns: (coerced UnspacedList or string or None, spaced equivalent) + :rtype: tuple + + """ + if not isinstance(inbound, list): # str or None + return (inbound, inbound) else: if not hasattr(x, "spaced"): - x = UnspacedList(x) - self.spaced.insert(i + self._spaces_before(i), x.spaced) - list.insert(self, i, x) + inbound = UnspacedList(inbound) + return (inbound, inbound.spaced) + + + def insert(self, i, x): + item, spaced_item = self._coerce(x) + self.spaced.insert(i + self._spaces_before(i), spaced_item) + list.insert(self, i, item) def append(self, x): - if hasattr(x, "spaced"): - self.spaced.append(x.spaced) - else: - self.spaced.append(x) - list.append(self, x) + item, spaced_item = self._coerce(x) + self.spaced.append(spaced_item) + list.append(self, item) def extend(self, x): - if hasattr(x, "spaced"): - self.spaced.extend(x.spaced) - else: - self.spaced.extend(x) - logger.debug("Weird, extending regular list %r to Unspaced %r", x, self) - list.extend(self, x) + item, spaced_item = self._coerce(x) + self.spaced.extend(spaced_item) + list.extend(self, item) def __add__(self, other): l = copy.deepcopy(self) @@ -216,10 +224,8 @@ class UnspacedList(list): return l def __setitem__(self, i, value): - if hasattr(value, "spaced"): - self.spaced.__setitem__(i + self._spaces_before(i), value.spaced) - else: - self.spaced.__setitem__(i + self._spaces_before(i), value) + item, spaced_item = self._coerce(x) + self.spaced.__setitem__(i + self._spaces_before(i), value) list.__setitem__(self, i, value) def __delitem__(self, i): From 5a872b829dfb774dd66d8a769c767534a183aae5 Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Mon, 20 Jun 2016 08:57:51 +0300 Subject: [PATCH 094/264] Added tests --- .../certbot_apache/tests/configurator_test.py | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index e5c09fd1d..9a034c3e0 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -497,13 +497,8 @@ class MultipleVhostsTest(util.ApacheTest): # Test Listen statements with specific ip listeed self.config.prepare_server_https("443") - # Should only be 2 here, as the third interface - # already listens to the correct port - self.assertEqual(mock_add_dir.call_count, 2) - - # Check argument to new Listen statements - self.assertEqual(mock_add_dir.call_args_list[0][0][2], ["1.2.3.4:443"]) - self.assertEqual(mock_add_dir.call_args_list[1][0][2], ["[::1]:443"]) + # Should be 0 as one interface already listens to 443 + self.assertEqual(mock_add_dir.call_count, 0) # Reset return lists and inputs mock_add_dir.reset_mock() @@ -519,6 +514,28 @@ class MultipleVhostsTest(util.ApacheTest): self.assertEqual(mock_add_dir.call_args_list[2][0][2], ["1.1.1.1:8080", "https"]) + # mock_get.side_effect = ["1.2.3.4:80", "[::1]:80"] + # mock_find.return_value = ["test1", "test2", "test3"] + # self.config.parser.get_arg = mock_get + # self.config.prepare_server_https("8080", temp=True) + # self.assertEqual(self.listens, 0) + + def test_prepare_server_https_needed_listen(self): + mock_find = mock.Mock() + mock_find.return_value = ["test1", "test2"] + mock_get = mock.Mock() + mock_get.side_effect = ["1.2.3.4:8080", "80"] + mock_add_dir = mock.Mock() + mock_enable = mock.Mock() + + self.config.parser.find_dir = mock_find + self.config.parser.get_arg = mock_get + self.config.parser.add_dir_to_ifmodssl = mock_add_dir + self.config.enable_mod = mock_enable + + self.config.prepare_server_https("443") + self.assertEqual(mock_add_dir.call_count, 1) + def test_prepare_server_https_mixed_listen(self): mock_find = mock.Mock() From 418a5d501f8d18fc3b2dbfc48bb2643aab1dd728 Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Mon, 20 Jun 2016 08:58:22 +0300 Subject: [PATCH 095/264] Refactored adding of listen statements --- certbot-apache/certbot_apache/configurator.py | 72 ++++++++++++------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 2a7064190..9e404177a 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -625,6 +625,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): """ + # If nonstandard port, add service definition for matching + if port != "443": + port_service = "%s %s" % (port, "https") + else: + port_service = port + self.prepare_https_modules(temp) # Check for Listen # Note: This could be made to also look for ip:443 combo @@ -639,40 +645,56 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if self._has_port_already(listens, port): return + listen_dirs = set(listens) + for listen in listens: # For any listen statement, check if the machine also listens on # Port 443. If not, add such a listen statement. if len(listen.split(":")) == 1: # Its listening to all interfaces - if port not in listens: - if port == "443": - args = [port] - else: - # Non-standard ports should specify https protocol - args = [port, "https"] - self.parser.add_dir_to_ifmodssl( - parser.get_aug_path( - self.parser.loc["listen"]), "Listen", args) - self.save_notes += "Added Listen %s directive to %s\n" % ( - port, self.parser.loc["listen"]) - listens.append(port) + if port not in listen_dirs and port_service not in listen_dirs: + listen_dirs.add(port_service) else: # The Listen statement specifies an ip _, ip = listen[::-1].split(":", 1) ip = ip[::-1] - if "%s:%s" % (ip, port) not in listens: - if port == "443": - args = ["%s:%s" % (ip, port)] - else: - # Non-standard ports should specify https protocol - args = ["%s:%s" % (ip, port), "https"] - self.parser.add_dir_to_ifmodssl( - parser.get_aug_path( - self.parser.loc["listen"]), "Listen", args) - self.save_notes += ("Added Listen %s:%s directive to " - "%s\n") % (ip, port, - self.parser.loc["listen"]) - listens.append("%s:%s" % (ip, port)) + if "%s:%s" % (ip, port_service) not in listen_dirs and ( + "%s:%s" % (ip, port_service) not in listen_dirs): + listen_dirs.add("%s:%s" % (ip, port_service)) + self._add_listens(listen_dirs, listens, port) + + def _add_listens(self, listens, listens_orig, port): + """Helper method for prepare_server_https to figure out which new + listen statements need adding + + :param set listens: Set of all needed Listen statements + :param list listens_orig: List of existing listen statements + :param string port: Port number we're adding + """ + + # Add service definition for non-standard ports + if port != "443": + port_service = "%s %s" % (port, "https") + else: + port_service = port + + new_listens = listens.difference(listens_orig) + + if port in new_listens or port_service in new_listens: + # We have wildcard, skip the rest + self.parser.add_dir_to_ifmodssl( + parser.get_aug_path(self.parser.loc["listen"]), + "Listen", port_service.split(" ")) + self.save_notes += "Added Listen %s directive to %s\n" % ( + port_service, self.parser.loc["listen"]) + else: + for listen in new_listens: + self.parser.add_dir_to_ifmodssl( + parser.get_aug_path(self.parser.loc["listen"]), + "Listen", listen.split(" ")) + self.save_notes += ("Added Listen %s directive to " + "%s\n") % (listen, + self.parser.loc["listen"]) def _has_port_already(self, listens, port): """Helper method for prepare_server_https to find out if user From 0bfdea86d634109d63b12ac4ad593c76c04f1d80 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 20 Jun 2016 14:32:21 -0700 Subject: [PATCH 096/264] Bump cryptography version --- letsencrypt-auto-source/letsencrypt-auto | 45 ++++++++++--------- .../pieces/letsencrypt-auto-requirements.txt | 45 ++++++++++--------- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 80b81c898..fa3996e9e 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -598,28 +598,29 @@ ConfigArgParse==0.10.0 \ --hash=sha256:3b50a83dd58149dfcee98cb6565265d10b53e9c0a2bca7eeef7fb5f5524890a7 configobj==5.0.6 \ --hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902 -cryptography==1.2.3 \ - --hash=sha256:031938f73a5c5eb3e809e18ff7caeb6865351871417be6050cb8c86a9a202b9a \ - --hash=sha256:a179a38d50f8d68b491d7a313db78f8cabe290842cecddddc7b34d408e59db0a \ - --hash=sha256:906c88b2aadcf99cfabb24098263d1bf65ab0c8688acde10dae1f09d865920f1 \ - --hash=sha256:6e706c5c6088770b1d1b634e959e21963e315b0255f5f4777125ad3d54082977 \ - --hash=sha256:f5ebf8e31c48f8707921dca0e994de77813a9c9b9bf03c119c5ddf97bdcffe73 \ - --hash=sha256:c7b89e42288cc7fbee3812e99ef5c744f22452e11d6822f6807afc6d6b3be83e \ - --hash=sha256:8408d29865947109d8b68f1837a7cde1aa4dc86e0f79ca3ba58c0c44e443d6a5 \ - --hash=sha256:c7e76cf3c3d925dd31fa238cfb806cffba718c0f08707d77a538768477969956 \ - --hash=sha256:7d8de35380f31702758b7753bb5c40723832c73006dedb2f9099bf61a37f7287 \ - --hash=sha256:5edbee71fae5469ee83fe0a37866b9398c8ce3a46325c24fcedfbf097bb48a19 \ - --hash=sha256:594edafe4801c13bdc1cc305e7704a90c19617e95936f6ab457ee4ffe000ba50 \ - --hash=sha256:b7fdb16a0a7f481be42da744bfe1ea2163025de21f90f2c688a316f3c354da9c \ - --hash=sha256:207b8bf0fe0907336df38b733b487521cf9e138189aba9234ad54fe545dd0db8 \ - --hash=sha256:509a2f05386270cf783993c90d49ffefb3dd62aee45bf1ea8ce3d2cde7271c21 \ - --hash=sha256:ac69b65dd1af0179ede40c9f15788c88f73e628ea6c0519de3838e279bb388c6 \ - --hash=sha256:8df6fad6c6ae12fd7004ea29357f0a2b4d3774eaeca7656530d08d2d90cd41aa \ - --hash=sha256:0b8b96dd81cc1533a04f30382c0fe21c1972e189f794d0c4261a18cec08fd9b5 \ - --hash=sha256:cae8fca1883f23c50ea78d89de6fe4fefdb4cea83177760f47177559414ded93 \ - --hash=sha256:1a471ca576a9cdce1b1cd9f3a22b1d09ee44d46862037557de17919c0db44425 \ - --hash=sha256:8ec4e8e3d453b3a1b63b5f57737a434dcf1ee4a2f26f6ff7c5a37c3f679104d2 \ - --hash=sha256:8eb11c77dd8e73f48df6b2f7a7e16173fe0fe8fdfe266232832e88477e08454e +cryptography==1.3.4 \ + --hash=sha256:bede00edd11a2a62c8c98c271cc103fa3a3d72acf64f6e5e4eaf251128897b17 \ + --hash=sha256:53b39e687b744bb548a98f40736cc529d9f60959b4e6cc551322cf9505d35eb3 \ + --hash=sha256:474b73ad1139b4e423e46bbd818efd0d5c0df1c65d9f7c957d64c9215d77afde \ + --hash=sha256:aaddf9592d5b99e32dd518bb4a25b147c124f9d6b4ad64b94f01b15d1666b8c8 \ + --hash=sha256:6dcad2f407db8c3cd6ecd78361439c449a4f94786b46c54507e7e68f51e1709d \ + --hash=sha256:475c153fc622e656f1f10a9c9941d0ac7ab18df7c38d35d563a437c1c0e34f24 \ + --hash=sha256:86dd61df581cba04e89e45081efbc531faff1c9d99c77b1ce97f87216c356353 \ + --hash=sha256:75cc697e4ef5fdd0102ca749114c6370dbd11db0c9132a18834858c2566247e3 \ + --hash=sha256:ea03ad5b9df6d79fc9fc1ab23729e01e1c920d2974c5e3c634ccf45a5c378452 \ + --hash=sha256:c8872b8fe4f3416d6338ab99612f49ab314f7856cb43bffab2a32d28a6267be8 \ + --hash=sha256:468fc6e16eaec6ceaa6bc341273e6e9912d01b42b740f8cf896ace7fcd6a321d \ + --hash=sha256:d6fea3c6502735011c5d61a62aef1c1d770fc6a2def45d9e6c0d94c9651e3317 \ + --hash=sha256:3cf95f179f4bead3d5649b91860ef4cf60ad4244209190fc405908272576d961 \ + --hash=sha256:141f77e60a5b9158309b2b60288c7f81d37faa15c22a69b94c190ceefaaa6236 \ + --hash=sha256:87b7a1fe703c6424451f3372d1879dae91c7fe5e13375441a72833db76fee30e \ + --hash=sha256:f5ee3cb0cf1a6550bf483ccffa6608db267a377b45f7e3a8201a86d1d8feb19f \ + --hash=sha256:4e097286651ea318300af3251375d48b71b8228481c56cd617ddd4459a1ff261 \ + --hash=sha256:1e3d3ae3f22f22d50d340f47f25227511326f3f1396c6d2446a5b45b516c4313 \ + --hash=sha256:6a057941cb64d79834ea3cf99093fcc4787c2a5d44f686c4f297361ddc419bcd \ + --hash=sha256:68b3d5390b92559ddd3353c73ab2dfcff758f9c4ec4f5d5226ccede0e5d779f4 \ + --hash=sha256:545dc003b4b6081f9c3e452da15d819b04b696f49484aff64c0a2aedf766bef8 \ + --hash=sha256:423ff890c01be7c70dbfeaa967eeef5146f1a43a5f810ffdc07b178e48a105a9 enum34==1.1.2 \ --hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \ --hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501 diff --git a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt index 1291b2c96..2485491da 100644 --- a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt +++ b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt @@ -32,28 +32,29 @@ ConfigArgParse==0.10.0 \ --hash=sha256:3b50a83dd58149dfcee98cb6565265d10b53e9c0a2bca7eeef7fb5f5524890a7 configobj==5.0.6 \ --hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902 -cryptography==1.2.3 \ - --hash=sha256:031938f73a5c5eb3e809e18ff7caeb6865351871417be6050cb8c86a9a202b9a \ - --hash=sha256:a179a38d50f8d68b491d7a313db78f8cabe290842cecddddc7b34d408e59db0a \ - --hash=sha256:906c88b2aadcf99cfabb24098263d1bf65ab0c8688acde10dae1f09d865920f1 \ - --hash=sha256:6e706c5c6088770b1d1b634e959e21963e315b0255f5f4777125ad3d54082977 \ - --hash=sha256:f5ebf8e31c48f8707921dca0e994de77813a9c9b9bf03c119c5ddf97bdcffe73 \ - --hash=sha256:c7b89e42288cc7fbee3812e99ef5c744f22452e11d6822f6807afc6d6b3be83e \ - --hash=sha256:8408d29865947109d8b68f1837a7cde1aa4dc86e0f79ca3ba58c0c44e443d6a5 \ - --hash=sha256:c7e76cf3c3d925dd31fa238cfb806cffba718c0f08707d77a538768477969956 \ - --hash=sha256:7d8de35380f31702758b7753bb5c40723832c73006dedb2f9099bf61a37f7287 \ - --hash=sha256:5edbee71fae5469ee83fe0a37866b9398c8ce3a46325c24fcedfbf097bb48a19 \ - --hash=sha256:594edafe4801c13bdc1cc305e7704a90c19617e95936f6ab457ee4ffe000ba50 \ - --hash=sha256:b7fdb16a0a7f481be42da744bfe1ea2163025de21f90f2c688a316f3c354da9c \ - --hash=sha256:207b8bf0fe0907336df38b733b487521cf9e138189aba9234ad54fe545dd0db8 \ - --hash=sha256:509a2f05386270cf783993c90d49ffefb3dd62aee45bf1ea8ce3d2cde7271c21 \ - --hash=sha256:ac69b65dd1af0179ede40c9f15788c88f73e628ea6c0519de3838e279bb388c6 \ - --hash=sha256:8df6fad6c6ae12fd7004ea29357f0a2b4d3774eaeca7656530d08d2d90cd41aa \ - --hash=sha256:0b8b96dd81cc1533a04f30382c0fe21c1972e189f794d0c4261a18cec08fd9b5 \ - --hash=sha256:cae8fca1883f23c50ea78d89de6fe4fefdb4cea83177760f47177559414ded93 \ - --hash=sha256:1a471ca576a9cdce1b1cd9f3a22b1d09ee44d46862037557de17919c0db44425 \ - --hash=sha256:8ec4e8e3d453b3a1b63b5f57737a434dcf1ee4a2f26f6ff7c5a37c3f679104d2 \ - --hash=sha256:8eb11c77dd8e73f48df6b2f7a7e16173fe0fe8fdfe266232832e88477e08454e +cryptography==1.3.4 \ + --hash=sha256:bede00edd11a2a62c8c98c271cc103fa3a3d72acf64f6e5e4eaf251128897b17 \ + --hash=sha256:53b39e687b744bb548a98f40736cc529d9f60959b4e6cc551322cf9505d35eb3 \ + --hash=sha256:474b73ad1139b4e423e46bbd818efd0d5c0df1c65d9f7c957d64c9215d77afde \ + --hash=sha256:aaddf9592d5b99e32dd518bb4a25b147c124f9d6b4ad64b94f01b15d1666b8c8 \ + --hash=sha256:6dcad2f407db8c3cd6ecd78361439c449a4f94786b46c54507e7e68f51e1709d \ + --hash=sha256:475c153fc622e656f1f10a9c9941d0ac7ab18df7c38d35d563a437c1c0e34f24 \ + --hash=sha256:86dd61df581cba04e89e45081efbc531faff1c9d99c77b1ce97f87216c356353 \ + --hash=sha256:75cc697e4ef5fdd0102ca749114c6370dbd11db0c9132a18834858c2566247e3 \ + --hash=sha256:ea03ad5b9df6d79fc9fc1ab23729e01e1c920d2974c5e3c634ccf45a5c378452 \ + --hash=sha256:c8872b8fe4f3416d6338ab99612f49ab314f7856cb43bffab2a32d28a6267be8 \ + --hash=sha256:468fc6e16eaec6ceaa6bc341273e6e9912d01b42b740f8cf896ace7fcd6a321d \ + --hash=sha256:d6fea3c6502735011c5d61a62aef1c1d770fc6a2def45d9e6c0d94c9651e3317 \ + --hash=sha256:3cf95f179f4bead3d5649b91860ef4cf60ad4244209190fc405908272576d961 \ + --hash=sha256:141f77e60a5b9158309b2b60288c7f81d37faa15c22a69b94c190ceefaaa6236 \ + --hash=sha256:87b7a1fe703c6424451f3372d1879dae91c7fe5e13375441a72833db76fee30e \ + --hash=sha256:f5ee3cb0cf1a6550bf483ccffa6608db267a377b45f7e3a8201a86d1d8feb19f \ + --hash=sha256:4e097286651ea318300af3251375d48b71b8228481c56cd617ddd4459a1ff261 \ + --hash=sha256:1e3d3ae3f22f22d50d340f47f25227511326f3f1396c6d2446a5b45b516c4313 \ + --hash=sha256:6a057941cb64d79834ea3cf99093fcc4787c2a5d44f686c4f297361ddc419bcd \ + --hash=sha256:68b3d5390b92559ddd3353c73ab2dfcff758f9c4ec4f5d5226ccede0e5d779f4 \ + --hash=sha256:545dc003b4b6081f9c3e452da15d819b04b696f49484aff64c0a2aedf766bef8 \ + --hash=sha256:423ff890c01be7c70dbfeaa967eeef5146f1a43a5f810ffdc07b178e48a105a9 enum34==1.1.2 \ --hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \ --hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501 From 8b3528969d4c0939e6f5cd4b4f77d873b2d50283 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 20 Jun 2016 14:33:00 -0700 Subject: [PATCH 097/264] Bump pyopenssl version --- letsencrypt-auto-source/letsencrypt-auto | 6 +++--- .../pieces/letsencrypt-auto-requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index fa3996e9e..a25b3a70e 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -680,9 +680,9 @@ pyasn1==0.1.9 \ --hash=sha256:5191ff6b9126d2c039dd87f8ff025bed274baf07fa78afa46f556b1ad7265d6e \ --hash=sha256:8323e03637b2d072cc7041300bac6ec448c3c28950ab40376036788e9a1af629 \ --hash=sha256:853cacd96d1f701ddd67aa03ecc05f51890135b7262e922710112f12a2ed2a7f -pyOpenSSL==0.15.1 \ - --hash=sha256:88e45e6bb25dfed272a1ef2e728461d44b634c2cd689e989b6e56a349c5a3ae5 \ - --hash=sha256:f0a26070d6db0881de8bcc7846934b7c3c930d8f9c79d45883ee48984bc0d672 +pyopenssl==16.0.0 \ + --hash=sha256:5add70cf00273bf957ca31fdb0df9b0ae4639e081897d5f86a0ae1f104901230 \ + --hash=sha256:363d10ee43d062285facf4e465f4f5163f9f702f9134f0a5896f134cbb92d17d pyRFC3339==1.0 \ --hash=sha256:eea31835c56e2096af4363a5745a784878a61d043e247d3a6d6a0a32a9741f56 \ --hash=sha256:8dfbc6c458b8daba1c0f3620a8c78008b323a268b27b7359e92a4ae41325f535 diff --git a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt index 2485491da..0c642a33e 100644 --- a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt +++ b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt @@ -114,9 +114,9 @@ pyasn1==0.1.9 \ --hash=sha256:5191ff6b9126d2c039dd87f8ff025bed274baf07fa78afa46f556b1ad7265d6e \ --hash=sha256:8323e03637b2d072cc7041300bac6ec448c3c28950ab40376036788e9a1af629 \ --hash=sha256:853cacd96d1f701ddd67aa03ecc05f51890135b7262e922710112f12a2ed2a7f -pyOpenSSL==0.15.1 \ - --hash=sha256:88e45e6bb25dfed272a1ef2e728461d44b634c2cd689e989b6e56a349c5a3ae5 \ - --hash=sha256:f0a26070d6db0881de8bcc7846934b7c3c930d8f9c79d45883ee48984bc0d672 +pyopenssl==16.0.0 \ + --hash=sha256:5add70cf00273bf957ca31fdb0df9b0ae4639e081897d5f86a0ae1f104901230 \ + --hash=sha256:363d10ee43d062285facf4e465f4f5163f9f702f9134f0a5896f134cbb92d17d pyRFC3339==1.0 \ --hash=sha256:eea31835c56e2096af4363a5745a784878a61d043e247d3a6d6a0a32a9741f56 \ --hash=sha256:8dfbc6c458b8daba1c0f3620a8c78008b323a268b27b7359e92a4ae41325f535 From ef31a837f7242691e8c6ae83f6a92a3cf6dc5792 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 20 Jun 2016 15:56:19 -0700 Subject: [PATCH 098/264] Lint --- certbot-nginx/certbot_nginx/nginxparser.py | 8 ++++---- certbot-nginx/certbot_nginx/tests/util.py | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index d0f53e1a8..f74f3066e 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -198,7 +198,7 @@ class UnspacedList(list): if not isinstance(inbound, list): # str or None return (inbound, inbound) else: - if not hasattr(x, "spaced"): + if not hasattr(inbound, "spaced"): inbound = UnspacedList(inbound) return (inbound, inbound.spaced) @@ -224,9 +224,9 @@ class UnspacedList(list): return l def __setitem__(self, i, value): - item, spaced_item = self._coerce(x) - self.spaced.__setitem__(i + self._spaces_before(i), value) - list.__setitem__(self, i, value) + item, spaced_item = self._coerce(value) + self.spaced.__setitem__(i + self._spaces_before(i), spaced_item) + list.__setitem__(self, i, item) def __delitem__(self, i): self.spaced.__delitem__(i + self._spaces_before(i)) diff --git a/certbot-nginx/certbot_nginx/tests/util.py b/certbot-nginx/certbot_nginx/tests/util.py index 4ea4a03a7..866e5a9c7 100644 --- a/certbot-nginx/certbot_nginx/tests/util.py +++ b/certbot-nginx/certbot_nginx/tests/util.py @@ -17,7 +17,6 @@ from certbot.plugins import common from certbot_nginx import constants from certbot_nginx import configurator -from certbot_nginx import nginxparser class NginxTest(unittest.TestCase): # pylint: disable=too-few-public-methods From e2fd1369f33dc8e8adbbf40562f5e90e3811bcb2 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 20 Jun 2016 16:08:40 -0700 Subject: [PATCH 099/264] Update test for fancier semantics --- certbot-nginx/certbot_nginx/tests/nginxparser_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 2e8011443..1b1073de0 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -207,7 +207,7 @@ class TestUnspacedList(unittest.TestCase): self.assertEqual(ul3.spaced, self.a + self.b) self.assertEqual(self.ul.spaced, self.a) ul3 = self.ul + self.l2 - self.assertEqual(ul3, ["things", "quirk", "y", " "]) + self.assertEqual(ul3, ["things", "quirk", "y"]) self.assertEqual(ul3.spaced, self.a + self.b) def test_extend(self): From 02844904f0bd4a11f2d5f24e69033bbb580b0a9f Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 20 Jun 2016 16:11:32 -0700 Subject: [PATCH 100/264] Improve coverage --- certbot-nginx/certbot_nginx/tests/nginxparser_test.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 1b1073de0..4c239ac10 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -115,13 +115,7 @@ class TestRawNginxParser(unittest.TestCase): def test_dump_as_file(self): with open(util.get_data_filename('nginx.conf')) as handle: - try: - parsed = load(handle) - except: - handle.seek(0) - print "Failed on", handle.read() - raise - #parsed = util.filter_comments(parsed) + parsed = load(handle) parsed[-1][-1].append(UnspacedList([['server'], [['listen', ' ', '443 ssl'], ['server_name', ' ', 'localhost'], From 14ea8d8cdf8a63870b741886af3da21b946d9775 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 20 Jun 2016 17:45:02 -0700 Subject: [PATCH 101/264] Fix server_name spaciness --- certbot-nginx/certbot_nginx/configurator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-nginx/certbot_nginx/configurator.py b/certbot-nginx/certbot_nginx/configurator.py index 4f46b6a66..dd9a44aad 100644 --- a/certbot-nginx/certbot_nginx/configurator.py +++ b/certbot-nginx/certbot_nginx/configurator.py @@ -225,7 +225,7 @@ class NginxConfigurator(common.Plugin): if not matches: # No matches. Create a new vhost with this name in nginx.conf. filep = self.parser.loc["root"] - new_block = [['server'], [['server_name', target_name]]] + new_block = [['server'], [['\n', 'server_name', ' ', target_name]]] self.parser.add_http_directives(filep, new_block) vhost = obj.VirtualHost(filep, set([]), False, True, set([target_name]), list(new_block[1])) From 5960376d36f4ccec38814c87bf972c01a23f10b0 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 20 Jun 2016 18:17:47 -0700 Subject: [PATCH 102/264] Cleanups --- certbot-nginx/certbot_nginx/nginxparser.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index f74f3066e..5c2bec577 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -62,9 +62,8 @@ class RawNginxParser(object): class RawNginxDumper(object): # pylint: disable=too-few-public-methods """A class that dumps nginx configuration from the provided tree.""" - def __init__(self, blocks, indentation=0): + def __init__(self, blocks): self.blocks = blocks - self.indentation = indentation def __iter__(self, blocks=None): """Iterates the dumped nginx content.""" @@ -100,10 +99,6 @@ class RawNginxDumper(object): if values and spacey(values): gap = values values = b.pop(0) - #if values is None: - # yield indentation + key + gap + ';' - #else: - # yield indentation + key + gap + values + ';' yield indentation + key + gap + values + ';' def __str__(self): From 56488b189901c2d9f760e241586cab7517f75d07 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 20 Jun 2016 18:18:25 -0700 Subject: [PATCH 103/264] Explain the most likely cause of a missing replay nonce error --- acme/acme/errors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme/errors.py b/acme/acme/errors.py index 77d47c522..ca2ab1874 100644 --- a/acme/acme/errors.py +++ b/acme/acme/errors.py @@ -49,7 +49,7 @@ class MissingNonce(NonceError): def __str__(self): return ('Server {0} response did not include a replay ' - 'nonce, headers: {1}'.format( + 'nonce, headers: {1}\n(This may be a service outage)'.format( self.response.request.method, self.response.headers)) From 884b21ffbe3b577eb82f2da58793b31e7d5dd6b8 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 21 Jun 2016 15:11:32 -0700 Subject: [PATCH 104/264] fix docstring typo --- certbot-nginx/certbot_nginx/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index 31595d56d..3c3942d22 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -18,7 +18,7 @@ logger = logging.getLogger(__name__) class NginxParser(object): """Class handles the fine details of parsing the Nginx Configuration. - :ivar str root: Normalized abosulte path to the server root + :ivar str root: Normalized absolute path to the server root directory. Without trailing slash. :ivar dict parsed: Mapping of file paths to parsed trees From 098d23ac984d9c242dcaf3436ac1d13dac579769 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 21 Jun 2016 15:33:57 -0700 Subject: [PATCH 105/264] Comment a couple of things --- certbot-nginx/certbot_nginx/parser.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index 3c3942d22..a0c29fc59 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -155,7 +155,9 @@ class NginxParser(object): :rtype: list """ - files = glob.glob(filepath) + files = glob.glob(filepath) # nginx on unix calls glob(3) for this + # XXX Windows nginx uses FindFirstFile, and + # should have a narrower call here trees = [] for item in files: if item in self.parsed and not override: @@ -210,6 +212,8 @@ class NginxParser(object): empty, this overrides the existing conf files. """ + # XXX probably this should be modified to perform atomic write + # operations and/or to defer control-c until completed for filename in self.parsed: tree = self.parsed[filename] if ext: From 7ea0ce5a1774bf3fadf1e5e2313bd3190a25a80f Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 21 Jun 2016 15:34:26 -0700 Subject: [PATCH 106/264] Remove warning about nginx options file - This would be a security issue if we ran as setuid root at the request of non-privileged users, but we don't --- certbot-nginx/certbot_nginx/configurator.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/certbot-nginx/certbot_nginx/configurator.py b/certbot-nginx/certbot_nginx/configurator.py index 30928e56c..26640a527 100644 --- a/certbot-nginx/certbot_nginx/configurator.py +++ b/certbot-nginx/certbot_nginx/configurator.py @@ -689,11 +689,6 @@ def nginx_restart(nginx_ctl, nginx_conf="/etc/nginx.conf"): def temp_install(options_ssl): """Temporary install for convenience.""" - # WARNING: THIS IS A POTENTIAL SECURITY VULNERABILITY - # THIS SHOULD BE HANDLED BY THE PACKAGE MANAGER - # AND TAKEN OUT BEFORE RELEASE, INSTEAD - # SHOWING A NICE ERROR MESSAGE ABOUT THE PROBLEM. - # Check to make sure options-ssl.conf is installed if not os.path.isfile(options_ssl): shutil.copyfile(constants.MOD_SSL_CONF_SRC, options_ssl) From 1caf3e993517554d2cde2fdc4ab071bccf923c4b Mon Sep 17 00:00:00 2001 From: Dominic Cleal Date: Wed, 22 Jun 2016 09:29:37 +0100 Subject: [PATCH 107/264] Merge Augeas fix for comment line continuations From https://github.com/hercules-team/augeas/commit/64189250e2c49442a0875fa46dfb1d76a4371bde Fixes #2050 --- .../certbot_apache/augeas_lens/httpd.aug | 5 +- .../passing/comment-continuations-2050.conf | 428 ++++++++++++++++++ 2 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 certbot-apache/certbot_apache/tests/apache-conf-files/passing/comment-continuations-2050.conf diff --git a/certbot-apache/certbot_apache/augeas_lens/httpd.aug b/certbot-apache/certbot_apache/augeas_lens/httpd.aug index 7a5129b56..2729f4b60 100644 --- a/certbot-apache/certbot_apache/augeas_lens/httpd.aug +++ b/certbot-apache/certbot_apache/augeas_lens/httpd.aug @@ -52,11 +52,14 @@ let sep_eq = del /[ \t]*=[ \t]*/ "=" let nmtoken = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/ let word = /[a-z][a-z0-9._-]*/i -let comment = Util.comment let eol = Util.doseol let empty = Util.empty_dos let indent = Util.indent +let comment_val_re = /([^ \t\r\n](.|\\\\\r?\n)*[^ \\\t\r\n]|[^ \t\r\n])/ +let comment = [ label "#comment" . del /[ \t]*#[ \t]*/ "# " + . store comment_val_re . eol ] + (* borrowed from shellvars.aug *) let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'|\\\\ / let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'|\\\\ / diff --git a/certbot-apache/certbot_apache/tests/apache-conf-files/passing/comment-continuations-2050.conf b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/comment-continuations-2050.conf new file mode 100644 index 000000000..48b344d8a --- /dev/null +++ b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/comment-continuations-2050.conf @@ -0,0 +1,428 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.2.6 +# Copyright (C) 2006-2012 Trustwave All rights reserved. +# +# The OWASP ModSecurity Core Rule Set is distributed under +# Apache Software License (ASL) version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# -- [[ Recommended Base Configuration ]] ------------------------------------------------- +# +# The configuration directives/settings in this file are used to control +# the OWASP ModSecurity CRS. These settings do **NOT** configure the main +# ModSecurity settings such as: +# +# - SecRuleEngine +# - SecRequestBodyAccess +# - SecAuditEngine +# - SecDebugLog +# +# You should use the modsecurity.conf-recommended file that comes with the +# ModSecurity source code archive. +# +# Ref: http://mod-security.svn.sourceforge.net/viewvc/mod-security/m2/trunk/modsecurity.conf-recommended +# + + +# +# -- [[ Rule Version ]] ------------------------------------------------------------------- +# +# Rule version data is added to the "Producer" line of Section H of the Audit log: +# +# - Producer: ModSecurity for Apache/2.7.0-rc1 (http://www.modsecurity.org/); OWASP_CRS/2.2.4. +# +# Ref: https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#SecComponentSignature +# +#SecComponentSignature "OWASP_CRS/2.2.6" + + +# +# -- [[ Modes of Operation: Self-Contained vs. Collaborative Detection ]] ----------------- +# +# Each detection rule uses the "block" action which will inherit the SecDefaultAction +# specified below. Your settings here will determine which mode of operation you use. +# +# -- [[ Self-Contained Mode ]] -- +# Rules inherit the "deny" disruptive action. The first rule that matches will block. +# +# -- [[ Collaborative Detection Mode ]] -- +# This is a "delayed blocking" mode of operation where each matching rule will inherit +# the "pass" action and will only contribute to anomaly scores. Transactional blocking +# can be applied +# +# -- [[ Alert Logging Control ]] -- +# You have three options - +# +# - To log to both the Apache error_log and ModSecurity audit_log file use: "log" +# - To log *only* to the ModSecurity audit_log file use: "nolog,auditlog" +# - To log *only* to the Apache error_log file use: "log,noauditlog" +# +# Ref: http://blog.spiderlabs.com/2010/11/advanced-topic-of-the-week-traditional-vs-anomaly-scoring-detection-modes.html +# Ref: https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#SecDefaultAction +# +#SecDefaultAction "phase:1,deny,log" + + +# +# -- [[ Collaborative Detection Severity Levels ]] ---------------------------------------- +# +# These are the default scoring points for each severity level. You may +# adjust these to you liking. These settings will be used in macro expansion +# in the rules to increment the anomaly scores when rules match. +# +# These are the default Severity ratings (with anomaly scores) of the individual rules - +# +# - 2: Critical - Anomaly Score of 5. +# Is the highest severity level possible without correlation. It is +# normally generated by the web attack rules (40 level files). +# - 3: Error - Anomaly Score of 4. +# Is generated mostly from outbound leakage rules (50 level files). +# - 4: Warning - Anomaly Score of 3. +# Is generated by malicious client rules (35 level files). +# - 5: Notice - Anomaly Score of 2. +# Is generated by the Protocol policy and anomaly files. +# +#SecAction \ + "id:'900001', \ + phase:1, \ + t:none, \ + setvar:tx.critical_anomaly_score=5, \ + setvar:tx.error_anomaly_score=4, \ + setvar:tx.warning_anomaly_score=3, \ + setvar:tx.notice_anomaly_score=2, \ + nolog, \ + pass" + + +# +# -- [[ Collaborative Detection Scoring Threshold Levels ]] ------------------------------ +# +# These variables are used in macro expansion in the 49 inbound blocking and 59 +# outbound blocking files. +# +# **MUST HAVE** ModSecurity v2.5.12 or higher to use macro expansion in numeric +# operators. If you have an earlier version, edit the 49/59 files directly to +# set the appropriate anomaly score levels. +# +# You should set the score to the proper threshold you would prefer. If set to "5" +# it will work similarly to previous Mod CRS rules and will create an event in the error_log +# file if there are any rules that match. If you would like to lessen the number of events +# generated in the error_log file, you should increase the anomaly score threshold to +# something like "20". This would only generate an event in the error_log file if +# there are multiple lower severity rule matches or if any 1 higher severity item matches. +# +#SecAction \ + "id:'900002', \ + phase:1, \ + t:none, \ + setvar:tx.inbound_anomaly_score_level=5, \ + nolog, \ + pass" + + +#SecAction \ + "id:'900003', \ + phase:1, \ + t:none, \ + setvar:tx.outbound_anomaly_score_level=4, \ + nolog, \ + pass" + + +# +# -- [[ Collaborative Detection Blocking ]] ----------------------------------------------- +# +# This is a collaborative detection mode where each rule will increment an overall +# anomaly score for the transaction. The scores are then evaluated in the following files: +# +# Inbound anomaly score - checked in the modsecurity_crs_49_inbound_blocking.conf file +# Outbound anomaly score - checked in the modsecurity_crs_59_outbound_blocking.conf file +# +# If you want to use anomaly scoring mode, then uncomment this line. +# +#SecAction \ + "id:'900004', \ + phase:1, \ + t:none, \ + setvar:tx.anomaly_score_blocking=on, \ + nolog, \ + pass" + + +# +# -- [[ GeoIP Database ]] ----------------------------------------------------------------- +# +# There are some rulesets that need to inspect the GEO data of the REMOTE_ADDR data. +# +# You must first download the MaxMind GeoIP Lite City DB - +# +# http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz +# +# You then need to define the proper path for the SecGeoLookupDb directive +# +# Ref: http://blog.spiderlabs.com/2010/10/detecting-malice-with-modsecurity-geolocation-data.html +# Ref: http://blog.spiderlabs.com/2010/11/detecting-malice-with-modsecurity-ip-forensics.html +# +#SecGeoLookupDb /opt/modsecurity/lib/GeoLiteCity.dat + +# +# -- [[ Regression Testing Mode ]] -------------------------------------------------------- +# +# If you are going to run the regression testing mode, you should uncomment the +# following rule. It will enable DetectionOnly mode for the SecRuleEngine and +# will enable Response Header tagging so that the client testing script can see +# which rule IDs have matched. +# +# You must specify the your source IP address where you will be running the tests +# from. +# +#SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" \ + "id:'900005', \ + phase:1, \ + t:none, \ + ctl:ruleEngine=DetectionOnly, \ + setvar:tx.regression_testing=1, \ + nolog, \ + pass" + + +# +# -- [[ HTTP Policy Settings ]] ---------------------------------------------------------- +# +# Set the following policy settings here and they will be propagated to the 23 rules +# file (modsecurity_common_23_request_limits.conf) by using macro expansion. +# If you run into false positives, you can adjust the settings here. +# +# Only the max number of args is uncommented by default as there are a high rate +# of false positives. Uncomment the items you wish to set. +# +# +# -- Maximum number of arguments in request limited +#SecAction \ + "id:'900006', \ + phase:1, \ + t:none, \ + setvar:tx.max_num_args=255, \ + nolog, \ + pass" + +# +# -- Limit argument name length +#SecAction \ + "id:'900007', \ + phase:1, \ + t:none, \ + setvar:tx.arg_name_length=100, \ + nolog, \ + pass" + +# +# -- Limit value name length +#SecAction \ + "id:'900008', \ + phase:1, \ + t:none, \ + setvar:tx.arg_length=400, \ + nolog, \ + pass" + +# +# -- Limit arguments total length +#SecAction \ + "id:'900009', \ + phase:1, \ + t:none, \ + setvar:tx.total_arg_length=64000, \ + nolog, \ + pass" + +# +# -- Individual file size is limited +#SecAction \ + "id:'900010', \ + phase:1, \ + t:none, \ + setvar:tx.max_file_size=1048576, \ + nolog, \ + pass" + +# +# -- Combined file size is limited +#SecAction \ + "id:'900011', \ + phase:1, \ + t:none, \ + setvar:tx.combined_file_sizes=1048576, \ + nolog, \ + pass" + + +# +# Set the following policy settings here and they will be propagated to the 30 rules +# file (modsecurity_crs_30_http_policy.conf) by using macro expansion. +# If you run into false positves, you can adjust the settings here. +# +#SecAction \ + "id:'900012', \ + phase:1, \ + t:none, \ + setvar:'tx.allowed_methods=GET HEAD POST OPTIONS', \ + setvar:'tx.allowed_request_content_type=application/x-www-form-urlencoded|multipart/form-data|text/xml|application/xml|application/x-amf', \ + setvar:'tx.allowed_http_versions=HTTP/0.9 HTTP/1.0 HTTP/1.1', \ + setvar:'tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .resources/ .resx/ .sql/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/', \ + setvar:'tx.restricted_headers=/Proxy-Connection/ /Lock-Token/ /Content-Range/ /Translate/ /via/ /if/', \ + nolog, \ + pass" + + +# +# -- [[ Content Security Policy (CSP) Settings ]] ----------------------------------------- +# +# The purpose of these settings is to send CSP response headers to +# Mozilla FireFox users so that you can enforce how dynamic content +# is used. CSP usage helps to prevent XSS attacks against your users. +# +# Reference Link: +# +# https://developer.mozilla.org/en/Security/CSP +# +# Uncomment this SecAction line if you want use CSP enforcement. +# You need to set the appropriate directives and settings for your site/domain and +# and activate the CSP file in the experimental_rules directory. +# +# Ref: http://blog.spiderlabs.com/2011/04/modsecurity-advanced-topic-of-the-week-integrating-content-security-policy-csp.html +# +#SecAction \ + "id:'900013', \ + phase:1, \ + t:none, \ + setvar:tx.csp_report_only=1, \ + setvar:tx.csp_report_uri=/csp_violation_report, \ + setenv:'csp_policy=allow \'self\'; img-src *.yoursite.com; media-src *.yoursite.com; style-src *.yoursite.com; frame-ancestors *.yoursite.com; script-src *.yoursite.com; report-uri %{tx.csp_report_uri}', \ + nolog, \ + pass" + + +# +# -- [[ Brute Force Protection ]] --------------------------------------------------------- +# +# If you are using the Brute Force Protection rule set, then uncomment the following +# lines and set the following variables: +# - Protected URLs: resources to protect (e.g. login pages) - set to your login page +# - Burst Time Slice Interval: time interval window to monitor for bursts +# - Request Threshold: request # threshold to trigger a burst +# - Block Period: temporary block timeout +# +#SecAction \ + "id:'900014', \ + phase:1, \ + t:none, \ + setvar:'tx.brute_force_protected_urls=/login.jsp /partner_login.php', \ + setvar:'tx.brute_force_burst_time_slice=60', \ + setvar:'tx.brute_force_counter_threshold=10', \ + setvar:'tx.brute_force_block_timeout=300', \ + nolog, \ + pass" + + +# +# -- [[ DoS Protection ]] ---------------------------------------------------------------- +# +# If you are using the DoS Protection rule set, then uncomment the following +# lines and set the following variables: +# - Burst Time Slice Interval: time interval window to monitor for bursts +# - Request Threshold: request # threshold to trigger a burst +# - Block Period: temporary block timeout +# +#SecAction \ + "id:'900015', \ + phase:1, \ + t:none, \ + setvar:'tx.dos_burst_time_slice=60', \ + setvar:'tx.dos_counter_threshold=100', \ + setvar:'tx.dos_block_timeout=600', \ + nolog, \ + pass" + + +# +# -- [[ Check UTF enconding ]] ----------------------------------------------------------- +# +# We only want to apply this check if UTF-8 encoding is actually used by the site, otherwise +# it will result in false positives. +# +# Uncomment this line if your site uses UTF8 encoding +#SecAction \ + "id:'900016', \ + phase:1, \ + t:none, \ + setvar:tx.crs_validate_utf8_encoding=1, \ + nolog, \ + pass" + + +# +# -- [[ Enable XML Body Parsing ]] ------------------------------------------------------- +# +# The rules in this file will trigger the XML parser upon an XML request +# +# Initiate XML Processor in case of xml content-type +# +#SecRule REQUEST_HEADERS:Content-Type "text/xml" \ + "id:'900017', \ + phase:1, \ + t:none,t:lowercase, \ + nolog, \ + pass, \ + chain" + #SecRule REQBODY_PROCESSOR "!@streq XML" \ + "ctl:requestBodyProcessor=XML" + + +# +# -- [[ Global and IP Collections ]] ----------------------------------------------------- +# +# Create both Global and IP collections for rules to use +# There are some CRS rules that assume that these two collections +# have already been initiated. +# +#SecRule REQUEST_HEADERS:User-Agent "^(.*)$" \ + "id:'900018', \ + phase:1, \ + t:none,t:sha1,t:hexEncode, \ + setvar:tx.ua_hash=%{matched_var}, \ + nolog, \ + pass" + + +#SecRule REQUEST_HEADERS:x-forwarded-for "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" \ + "id:'900019', \ + phase:1, \ + t:none, \ + capture, \ + setvar:tx.real_ip=%{tx.1}, \ + nolog, \ + pass" + + +#SecRule &TX:REAL_IP "!@eq 0" \ + "id:'900020', \ + phase:1, \ + t:none, \ + initcol:global=global, \ + initcol:ip=%{tx.real_ip}_%{tx.ua_hash}, \ + nolog, \ + pass" + + +#SecRule &TX:REAL_IP "@eq 0" \ + "id:'900021', \ + phase:1, \ + t:none, \ + initcol:global=global, \ + initcol:ip=%{remote_addr}_%{tx.ua_hash}, \ + nolog, \ + pass" From 24cc6b208ae7fb869d3b93ef9d06c68f07a3e848 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 22 Jun 2016 15:24:33 -0700 Subject: [PATCH 108/264] Avoid newline --- acme/acme/errors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme/errors.py b/acme/acme/errors.py index ca2ab1874..70894a808 100644 --- a/acme/acme/errors.py +++ b/acme/acme/errors.py @@ -49,7 +49,7 @@ class MissingNonce(NonceError): def __str__(self): return ('Server {0} response did not include a replay ' - 'nonce, headers: {1}\n(This may be a service outage)'.format( + 'nonce, headers: {1} (This may be a service outage)'.format( self.response.request.method, self.response.headers)) From 8a28cb7352eb5d534e79cdd213ede8fd8283dedb Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 22 Jun 2016 15:50:21 -0700 Subject: [PATCH 109/264] Implement Brad's more systematic solution for this --- certbot/display/util.py | 33 ++++++++++++++++++++++-------- certbot/tests/display/util_test.py | 1 + 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/certbot/display/util.py b/certbot/display/util.py index 683dbc037..c998f78f3 100644 --- a/certbot/display/util.py +++ b/certbot/display/util.py @@ -29,7 +29,6 @@ CANCEL = "cancel" HELP = "help" """Display exit code when for when the user requests more help.""" - def _wrap_lines(msg): """Format lines nicely to 80 chars. @@ -51,6 +50,21 @@ def _wrap_lines(msg): return os.linesep.join(fixed_l) + +def _clean(dialog_result): + """Work around inconsistent return codes from python-dialog. + + :param tuple dialog_result: (code, result) + :returns: the argument but with unknown codes set to -1 (Error) + :rtype: tuple + """ + code, result = dialog_result + if code in (OK, HELP): + return dialog_result + else: + return (CANCEL, result) + + @zope.interface.implementer(interfaces.IDisplay) class NcursesDisplay(object): """Ncurses-based display.""" @@ -92,7 +106,7 @@ class NcursesDisplay(object): :param dict unused_kwargs: absorbs default / cli_args :returns: tuple of the form (`code`, `index`) where - `code` - int display exit code + `code` - display exit code `int` - index of the selected item :rtype: tuple @@ -111,7 +125,7 @@ class NcursesDisplay(object): # Can accept either tuples or just the actual choices if choices and isinstance(choices[0], tuple): # pylint: disable=star-args - code, selection = self.dialog.menu(message, **menu_options) + code, selection = _clean(self.dialog.menu(message, **menu_options)) # Return the selection index for i, choice in enumerate(choices): @@ -126,7 +140,7 @@ class NcursesDisplay(object): (str(i), choice) for i, choice in enumerate(choices, 1) ] # pylint: disable=star-args - code, index = self.dialog.menu(message, **menu_options) + code, index = _clean(self.dialog.menu(message, **menu_options)) if code == CANCEL or index == "": return code, -1 @@ -140,7 +154,7 @@ class NcursesDisplay(object): :param dict _kwargs: absorbs default / cli_args :returns: tuple of the form (`code`, `string`) where - `code` - int display exit code + `code` - display exit code `string` - input entered by the user """ @@ -148,7 +162,7 @@ class NcursesDisplay(object): # each section takes at least one line, plus extras if it's longer than self.width wordlines = [1 + (len(section) / self.width) for section in sections] height = 6 + sum(wordlines) + len(sections) - return self.dialog.inputbox(message, width=self.width, height=height) + return _clean(self.dialog.inputbox(message, width=self.width, height=height)) def yesno(self, message, yes_label="Yes", no_label="No", **unused_kwargs): """Display a Yes/No dialog box. @@ -164,6 +178,7 @@ class NcursesDisplay(object): :rtype: bool """ + assert OK == self.dialog.DIALOG_OK, "What kind of absurdity is this?" return self.dialog.DIALOG_OK == self.dialog.yesno( message, self.height, self.width, yes_label=yes_label, no_label=no_label) @@ -179,7 +194,7 @@ class NcursesDisplay(object): :returns: tuple of the form (`code`, `list_tags`) where - `code` - int display exit code + `code` - display exit code `list_tags` - list of str tags selected by the user """ @@ -193,7 +208,7 @@ class NcursesDisplay(object): :param str message: prompt to give the user :returns: tuple of the form (`code`, `string`) where - `code` - int display exit code + `code` - display exit code `string` - input entered by the user """ @@ -355,7 +370,7 @@ class FileDisplay(object): :param str message: prompt to give the user :returns: tuple of the form (`code`, `string`) where - `code` - int display exit code + `code` - display exit code `string` - input entered by the user """ diff --git a/certbot/tests/display/util_test.py b/certbot/tests/display/util_test.py index 4a38803d1..94338118d 100644 --- a/certbot/tests/display/util_test.py +++ b/certbot/tests/display/util_test.py @@ -96,6 +96,7 @@ class NcursesDisplayTest(unittest.TestCase): @mock.patch("certbot.display.util." "dialog.Dialog.inputbox") def test_input(self, mock_input): + mock_input.return_value = (mock.MagicMock(), mock.MagicMock()) self.displayer.input("message") self.assertEqual(mock_input.call_count, 1) From 975599e9ca359586990c21a23f999eb93c243d51 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 22 Jun 2016 18:25:09 -0700 Subject: [PATCH 110/264] Remove bad save in nginx perform --- certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py | 2 +- certbot-nginx/certbot_nginx/tls_sni_01.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py b/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py index 3264d6ed3..a92caf788 100644 --- a/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py +++ b/certbot-nginx/certbot_nginx/tests/tls_sni_01_test.py @@ -80,7 +80,7 @@ class TlsSniPerformTest(util.NginxTest): mock_setup_cert.assert_called_once_with(self.achalls[0]) self.assertEqual([response], responses) - self.assertEqual(mock_save.call_count, 2) + self.assertEqual(mock_save.call_count, 1) # Make sure challenge config is included in main config http = self.sni.configurator.parser.parsed[ diff --git a/certbot-nginx/certbot_nginx/tls_sni_01.py b/certbot-nginx/certbot_nginx/tls_sni_01.py index e4c5d31a6..478810475 100644 --- a/certbot-nginx/certbot_nginx/tls_sni_01.py +++ b/certbot-nginx/certbot_nginx/tls_sni_01.py @@ -46,8 +46,6 @@ class NginxTlsSni01(common.TLSSNI01): if not self.achalls: return [] - self.configurator.save() - addresses = [] default_addr = "{0} default_server ssl".format( self.configurator.config.tls_sni_01_port) From 230b09bb15f5ba264b894b55634140e3c7002f4f Mon Sep 17 00:00:00 2001 From: Jacob Sachs Date: Thu, 23 Jun 2016 08:23:27 -0400 Subject: [PATCH 111/264] add logging for keeping existing cert --- certbot/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/certbot/main.py b/certbot/main.py index 7d6830b18..90fa62fad 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -83,6 +83,7 @@ def _auth_from_domains(le_client, config, domains, lineage=None): if action == "reinstall": # The lineage already exists; allow the caller to try installing # it without getting a new certificate at all. + logger.info("Keeping the existing certificate") return lineage, "reinstall" hooks.pre_hook(config) From 4ef7131a4b6868aa32370a27dd8f722a5ae2e429 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 23 Jun 2016 11:05:49 -0700 Subject: [PATCH 112/264] Name all of nginxparser's magic regexps --- certbot-nginx/certbot_nginx/nginxparser.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 5c2bec577..ab57089b9 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -4,7 +4,7 @@ import logging import string from pyparsing import ( - Literal, White, Word, alphanums, CharsNotIn, Forward, Group, + Literal, White, Word, alphanums, CharsNotIn, Combine, Forward, Group, Optional, OneOrMore, Regex, ZeroOrMore) from pyparsing import stringEnd from pyparsing import restOfLine @@ -17,10 +17,13 @@ class RawNginxParser(object): # constants space = Optional(White()) + nonspace = Regex(r"\S+") left_bracket = Literal("{").suppress() right_bracket = space.leaveWhitespace() + Literal("}").suppress() semicolon = Literal(";").suppress() key = Word(alphanums + "_/+-.") + dollar_var = Combine(Literal('$') + nonspace) + condition = Regex(r"\(.+\)") # Matches anything that is not a special character AND any chars in single # or double quotes value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+") @@ -33,8 +36,8 @@ class RawNginxParser(object): assignment = space + key + Optional(space + value, default=None) + semicolon location_statement = space + Optional(modifier) + Optional(space + location + space) - if_statement = space + Literal("if") + space + Regex(r"\(.+\)") + space - map_statement = space + Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space + if_statement = space + Literal("if") + space + condition + space + map_statement = space + Literal("map") + space + nonspace + space + dollar_var + space block = Forward() block << Group( From db66050a7ae3048f4daf0a06ba6e87231abddcfb Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 23 Jun 2016 11:39:51 -0700 Subject: [PATCH 113/264] Make atomicity comment more accurate --- certbot-nginx/certbot_nginx/parser.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index a0c29fc59..f2c10ab70 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -212,8 +212,7 @@ class NginxParser(object): empty, this overrides the existing conf files. """ - # XXX probably this should be modified to perform atomic write - # operations and/or to defer control-c until completed + # Best-effort atomicity is enforced above us by reverter.py for filename in self.parsed: tree = self.parsed[filename] if ext: From a29c6e3102ca1d093b7ffbaed93e88f635907e8d Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 23 Jun 2016 14:06:32 -0700 Subject: [PATCH 114/264] Try simplifying handling of spacey sublists - this was causing test failures but they may all have been fixed by other changes... --- certbot-nginx/certbot_nginx/nginxparser.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index ab57089b9..efcdf94ef 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -172,12 +172,7 @@ class UnspacedList(list): for i, entry in reversed(list(enumerate(self))): if isinstance(entry, list): sublist = UnspacedList(entry) - if sublist != [] or sublist.spaced == []: - list.__setitem__(self, i, sublist) - else: - # if a sublist is exclusively spacey entries, it might - # choke the high level parser, so make it disappear - list.__delitem__(self, i) + list.__setitem__(self, i, sublist) self.spaced[i] = sublist.spaced elif spacey(entry): # don't delete comments From 3178a9f0f3365ef4665474a50ccab20b02ec8d91 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 24 Jun 2016 00:24:53 +0200 Subject: [PATCH 115/264] cli-help: fix spelling --- docs/cli-help.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli-help.txt b/docs/cli-help.txt index e5f1fdcb4..749983d0e 100644 --- a/docs/cli-help.txt +++ b/docs/cli-help.txt @@ -147,7 +147,7 @@ security: HTTPS for the newly authenticated vhost. (default: None) --hsts Add the Strict-Transport-Security header to every HTTP - response. Forcing browser to use always use SSL for + response. Forcing browser to always use SSL for the domain. Defends against SSL Stripping. (default: False) --no-hsts Do not automatically add the Strict-Transport-Security From cb441606d52fe3fd67fe8b3f2fd1672cd645ba49 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 23 Jun 2016 16:14:34 -0700 Subject: [PATCH 116/264] Explictly state assumptions made by certbot --- certbot/interfaces.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/certbot/interfaces.py b/certbot/interfaces.py index 37835462e..a6f0b9735 100644 --- a/certbot/interfaces.py +++ b/certbot/interfaces.py @@ -180,6 +180,9 @@ class IAuthenticator(IPlugin): def cleanup(achalls): """Revert changes and shutdown after challenges complete. + This method should be able to revert all changes made by + perform, even if perform exited abnormally. + :param list achalls: Non-empty (guaranteed) list of :class:`~certbot.achallenges.AnnotatedChallenge` instances, a subset of those previously passed to :func:`perform`. @@ -304,8 +307,11 @@ class IInstaller(IPlugin): Both title and temporary are needed because a save may be intended to be permanent, but the save is not ready to be a full - checkpoint. If an exception is raised, it is assumed a new - checkpoint was not created. + checkpoint. + + It is assumed that at most one checkpoint is finalized by this + method. Additionally, if an exception is raised, it is assumed a + new checkpoint was not finalized. :param str title: The title of the save. If a title is given, the configuration will be saved as a new checkpoint and put in a From 38feb37d3ee0f9b0db689b0db2a2a9df1facd207 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 23 Jun 2016 17:03:01 -0700 Subject: [PATCH 117/264] Further document reverter --- certbot/reverter.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/certbot/reverter.py b/certbot/reverter.py index f8140d60d..c7eab1690 100644 --- a/certbot/reverter.py +++ b/certbot/reverter.py @@ -24,6 +24,39 @@ logger = logging.getLogger(__name__) class Reverter(object): """Reverter Class - save and revert configuration checkpoints. + This class can be used by the plugins, especially installers, to + undo changes made to the user's system. Modifications to files and + commands to do undo actions taken by the plugin should be registered + with this class before the action is taken. + + Once a change has been registered with this class, there are three + states the change can be in. First, the change can be a temporary + change. This should be used for changes that will soon be reverted, + such as config changes for the purpose of solving a challenge. + Changes are added to this state through calls to + :func:`~add_to_temp_checkpoint` and reverted when + :func:`~revert_temporary_config` or :func:`~recovery_routine` is + called. + + The second state a change can be in is in progress. These changes + are not temporary, however, they also have not been finalized in a + checkpoint. A change must become in progress before it can be + finalized. Changes are added to this state through calls to + :func:`~add_to_checkpoint` and reverted when + :func:`~recovery_routine` is called. + + The last state a change can be in is finalized in a checkpoint. A + change is put into this state by first becoming an in progress + change and then calling :func:`~finalize_checkpoint`. Changes + in this state can be reverted through calls to + :func:`~rollback_checkpoints`. + + As a final note, creating new files and registering undo commands + are handled specially and use the methods + :func:`~register_file_creation` and :func:`~register_undo_command` + respectively. Both of these methods can be used to create either + temporary or in progress changes. + .. note:: Consider moving everything over to CSV format. :param config: Configuration. From 7e5e016982a0852f4151c434890102d733eedeba Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 23 Jun 2016 17:10:03 -0700 Subject: [PATCH 118/264] Document that only save should make checkpoints --- certbot/interfaces.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certbot/interfaces.py b/certbot/interfaces.py index a6f0b9735..2bc25723c 100644 --- a/certbot/interfaces.py +++ b/certbot/interfaces.py @@ -241,6 +241,11 @@ class IInstaller(IPlugin): Represents any server that an X509 certificate can be placed. + It is assumed that :func:`save` is the only method that finalizes a + checkpoint. This is important to ensure that checkpoints are + restored in a consistent manner if requested by the user or in case + of an error. + """ def get_all_names(): From 7aa6becc5bffa19e85108b0286b08aa29aaf50aa Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 23 Jun 2016 17:16:58 -0700 Subject: [PATCH 119/264] Suggest reverter for installers --- certbot/interfaces.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/certbot/interfaces.py b/certbot/interfaces.py index 2bc25723c..e4e62e0a2 100644 --- a/certbot/interfaces.py +++ b/certbot/interfaces.py @@ -246,6 +246,9 @@ class IInstaller(IPlugin): restored in a consistent manner if requested by the user or in case of an error. + Using :class:`certbot.reverter.Reverter` to implement checkpoints, + rollback, and recovery can dramatically simplify plugin development. + """ def get_all_names(): From 02c61cffb713ef3609b2dffd8e2465a95cd4fcfe Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 23 Jun 2016 17:17:17 -0700 Subject: [PATCH 120/264] Consistent capitialization with installer --- certbot/reverter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/reverter.py b/certbot/reverter.py index c7eab1690..6dde05077 100644 --- a/certbot/reverter.py +++ b/certbot/reverter.py @@ -24,7 +24,7 @@ logger = logging.getLogger(__name__) class Reverter(object): """Reverter Class - save and revert configuration checkpoints. - This class can be used by the plugins, especially installers, to + This class can be used by the plugins, especially Installers, to undo changes made to the user's system. Modifications to files and commands to do undo actions taken by the plugin should be registered with this class before the action is taken. From bac988a4042537a2f6429e43b18553b1d0d9f710 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 23 Jun 2016 17:24:05 -0700 Subject: [PATCH 121/264] Fix typo --- certbot/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/cli.py b/certbot/cli.py index ba1f23708..35b3b74ae 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -773,7 +773,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis helpful.add( "security", "--hsts", action="store_true", help="Add the Strict-Transport-Security header to every HTTP response." - " Forcing browser to use always use SSL for the domain." + " Forcing browser to always use SSL for the domain." " Defends against SSL Stripping.", dest="hsts", default=False) helpful.add( "security", "--no-hsts", action="store_false", From 6930523c1469be5b9254405d045e897dfb85ee56 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 23 Jun 2016 17:59:26 -0700 Subject: [PATCH 122/264] Refactor to simplify indenation handling --- certbot-nginx/certbot_nginx/nginxparser.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index efcdf94ef..0ec1aeefb 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -41,7 +41,7 @@ class RawNginxParser(object): block = Forward() block << Group( - # XXX could this "key" be Literal("location")? + # key could for instance be "server" or "http" (Group(space + key + location_statement) ^ Group(if_statement) ^ Group(map_statement)).leaveWhitespace() + left_bracket + @@ -78,15 +78,14 @@ class RawNginxDumper(object): b = copy.deepcopy(b0) indentation = "" if spacey(b[0]): - indentation = b.pop(0) + yield b.pop(0) # indentation if not b: - yield indentation continue key = b.pop(0) values = b.pop(0) if isinstance(key, list): - yield indentation + "".join(key) + '{' + yield "".join(key) + '{' for parameter in values: dumped = self.__iter__([parameter]) for line in dumped: @@ -94,7 +93,7 @@ class RawNginxDumper(object): yield '}' else: if isinstance(key, str) and key.strip() == '#': - yield indentation + key + values + yield key + values else: gap = "" # Sometimes the parser has stuck some gap whitespace in here; @@ -102,7 +101,7 @@ class RawNginxDumper(object): if values and spacey(values): gap = values values = b.pop(0) - yield indentation + key + gap + values + ';' + yield key + gap + values + ';' def __str__(self): """Return the parsed block as a string.""" From ad13b525b28542378a8f506732b8ac1146d69b3e Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 14:35:42 -0700 Subject: [PATCH 123/264] For reference, a buggy attempt to implement slicing but slice assignment seems to mangle the .spaced list in some cases --- certbot-nginx/certbot_nginx/nginxparser.py | 31 +++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 0ec1aeefb..3db6ff501 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -76,7 +76,6 @@ class RawNginxDumper(object): yield b0 continue b = copy.deepcopy(b0) - indentation = "" if spacey(b[0]): yield b.pop(0) # indentation if not b: @@ -197,7 +196,7 @@ class UnspacedList(list): def insert(self, i, x): item, spaced_item = self._coerce(x) - self.spaced.insert(i + self._spaces_before(i), spaced_item) + self.spaced.insert(self._spaced_position(i), spaced_item) list.insert(self, i, item) def append(self, x): @@ -215,13 +214,28 @@ class UnspacedList(list): l.extend(other) return l + def __setslice__(self, i, j, newslice): + for idx in reversed(range(self._spaced_position(i), self._spaced_position(j))): + print "delspace", idx + del self.spaced[idx] + for idx in reversed(range(i,j)): + print "del", idx + list.__delitem__(self, idx) + for idx, item in enumerate(newslice): + self.insert(i + idx, item) + def __setitem__(self, i, value): + if isinstance(i, slice): + #raise NotImplementedError("Slice operations on UnspacedLists not yet implemented") + for pos in xrange(i.start or 0, i.stop or len(self), i.step or 1): + self.__setitem__(pos, value) + return item, spaced_item = self._coerce(value) - self.spaced.__setitem__(i + self._spaces_before(i), spaced_item) + self.spaced.__setitem__(self._spaced_position(i), spaced_item) list.__setitem__(self, i, item) def __delitem__(self, i): - self.spaced.__delitem__(i + self._spaces_before(i)) + self.spaced.__delitem__(self._spaced_position(i)) list.__delitem__(self, i) def __deepcopy__(self, unused_memo): @@ -230,14 +244,17 @@ class UnspacedList(list): return l - def _spaces_before(self, idx): - "Count the number of spaces in the spaced list before pos idx in the spaceless one" + def _spaced_position(self, idx): + "Convert from indexes in the unspaced list to positions in the spaced one" + print "lookup", idx spaces = 0 pos = 0 + if idx < 0: + idx = len(self) + idx while idx != -1: if spacey(self.spaced[pos]): spaces += 1 else: idx -= 1 pos += 1 - return spaces + return idx + spaces From e415a4d402d73af1f71171bae844ed435363cacd Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 14:36:23 -0700 Subject: [PATCH 124/264] For now, instead, consider this NotImplemented --- certbot-nginx/certbot_nginx/nginxparser.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 3db6ff501..8a423848c 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -215,21 +215,11 @@ class UnspacedList(list): return l def __setslice__(self, i, j, newslice): - for idx in reversed(range(self._spaced_position(i), self._spaced_position(j))): - print "delspace", idx - del self.spaced[idx] - for idx in reversed(range(i,j)): - print "del", idx - list.__delitem__(self, idx) - for idx, item in enumerate(newslice): - self.insert(i + idx, item) + raise NotImplementedError("Slice operations on UnspacedLists not yet implemented") def __setitem__(self, i, value): if isinstance(i, slice): - #raise NotImplementedError("Slice operations on UnspacedLists not yet implemented") - for pos in xrange(i.start or 0, i.stop or len(self), i.step or 1): - self.__setitem__(pos, value) - return + raise NotImplementedError("Slice operations on UnspacedLists not yet implemented") item, spaced_item = self._coerce(value) self.spaced.__setitem__(self._spaced_position(i), spaced_item) list.__setitem__(self, i, item) From 07fb5dd9cc2895799b370d5d25c56b9fca692e3a Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Fri, 24 Jun 2016 15:55:51 -0700 Subject: [PATCH 125/264] escape and unescape augeas --- certbot-apache/certbot_apache/configurator.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 57249eea5..33d79fadb 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -514,7 +514,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): try: args = self.aug.match(path + "/arg") except RuntimeError: - logger.warn("It looks like one of your paths has a character that your version of augeas can't parse") + logger.warn("Encountered a problem while parsing file: %s, skipping", path) return None for arg in args: addrs.add(obj.Addr.fromstring(self.parser.get_arg(arg))) @@ -529,7 +529,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if addr.get_port() == "443": is_ssl = True - filename = get_file_path(path) + filename = _unescape(get_file_path(path)) if self.conf("handle-sites"): is_enabled = self.is_site_enabled(filename) else: @@ -727,7 +727,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): """ avail_fp = nonssl_vhost.filep - ssl_fp = self._get_ssl_vhost_path(avail_fp) + ssl_fp = _escape(self._get_ssl_vhost_path(avail_fp)) self._copy_create_ssl_vhost_skeleton(avail_fp, ssl_fp) @@ -901,7 +901,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): self.parser.add_dir(vh_path, "Include", self.mod_ssl_conf) def _add_servername_alias(self, target_name, vhost): - fp = vhost.filep + fp = _escape(vhost.filep) vh_p = self.aug.match("/files%s//* [label()=~regexp('%s')]" % (fp, parser.case_i("VirtualHost"))) if not vh_p: @@ -953,6 +953,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if need_to_save: self.save() + def _unescape(fp): + return fp.replace("\\", "") + + def _escape(fp): + return fp.replace(",", "\\,") ###################################################################### # Enhancements From 9da533d92e432d6ad365de9dbed7e2810491f577 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 16:13:12 -0700 Subject: [PATCH 126/264] Be more succinct --- certbot-nginx/certbot_nginx/nginxparser.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 8a423848c..f65864df4 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -86,8 +86,7 @@ class RawNginxDumper(object): if isinstance(key, list): yield "".join(key) + '{' for parameter in values: - dumped = self.__iter__([parameter]) - for line in dumped: + for line in self.__iter__([parameter]): # negate "for b0 in blocks" yield line yield '}' else: From d67bc676813a0d67e73c23fd5f74b670d510db31 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Fri, 24 Jun 2016 16:17:09 -0700 Subject: [PATCH 127/264] add self --- certbot-apache/certbot_apache/configurator.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 33d79fadb..f7d37cc40 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -529,7 +529,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if addr.get_port() == "443": is_ssl = True - filename = _unescape(get_file_path(path)) + filename = self._unescape(get_file_path(path)) if self.conf("handle-sites"): is_enabled = self.is_site_enabled(filename) else: @@ -727,7 +727,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): """ avail_fp = nonssl_vhost.filep - ssl_fp = _escape(self._get_ssl_vhost_path(avail_fp)) + ssl_fp = self._escape(self._get_ssl_vhost_path(avail_fp)) self._copy_create_ssl_vhost_skeleton(avail_fp, ssl_fp) @@ -901,7 +901,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): self.parser.add_dir(vh_path, "Include", self.mod_ssl_conf) def _add_servername_alias(self, target_name, vhost): - fp = _escape(vhost.filep) + fp = self._escape(vhost.filep) vh_p = self.aug.match("/files%s//* [label()=~regexp('%s')]" % (fp, parser.case_i("VirtualHost"))) if not vh_p: @@ -953,10 +953,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if need_to_save: self.save() - def _unescape(fp): + + def _unescape(self, fp): return fp.replace("\\", "") - def _escape(fp): + def _escape(self, fp): return fp.replace(",", "\\,") ###################################################################### From 20b92a3c1fba3a922ea3063954b3691d4ed462d7 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 16:48:22 -0700 Subject: [PATCH 128/264] Add some test coverage --- certbot-nginx/certbot_nginx/tests/configurator_test.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/certbot-nginx/certbot_nginx/tests/configurator_test.py b/certbot-nginx/certbot_nginx/tests/configurator_test.py index a1d0e75cc..7529bc10b 100644 --- a/certbot-nginx/certbot_nginx/tests/configurator_test.py +++ b/certbot-nginx/certbot_nginx/tests/configurator_test.py @@ -265,7 +265,8 @@ class NginxConfiguratorTest(util.NginxTest): @mock.patch("certbot_nginx.configurator.tls_sni_01.NginxTlsSni01.perform") @mock.patch("certbot_nginx.configurator.NginxConfigurator.restart") - def test_perform(self, mock_restart, mock_perform): + @mock.patch("certbot_nginx.configurator.NginxConfigurator.revert_challenge_config") + def test_perform_and_cleanup(self, mock_revert, mock_restart, mock_perform): # Only tests functionality specific to configurator.perform # Note: As more challenges are offered this will have to be expanded achall1 = achallenges.KeyAuthorizationAnnotatedChallenge( @@ -291,7 +292,11 @@ class NginxConfiguratorTest(util.NginxTest): self.assertEqual(mock_perform.call_count, 1) self.assertEqual(responses, expected) - self.assertEqual(mock_restart.call_count, 1) + + self.config.cleanup([achall1, achall2]) + self.assertEqual(0, self.config._chall_out) # pylint: disable=protected-access + self.assertEqual(mock_revert.call_count, 1) + self.assertEqual(mock_restart.call_count, 2) @mock.patch("certbot_nginx.configurator.subprocess.Popen") def test_get_version(self, mock_popen): From 8f0a5fdc66f6b72d210a2edff32c27636bc3ecd7 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 16:48:30 -0700 Subject: [PATCH 129/264] Fix a bug in the new index calculations --- certbot-nginx/certbot_nginx/nginxparser.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index f65864df4..412268d22 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -235,15 +235,16 @@ class UnspacedList(list): def _spaced_position(self, idx): "Convert from indexes in the unspaced list to positions in the spaced one" - print "lookup", idx - spaces = 0 - pos = 0 + pos = spaces = 0 + # Normalize indexes like list[-1] etc, and save the result if idx < 0: idx = len(self) + idx + idx0 = idx + # Count the number of spaces in the spaced list before idx in the unspaced one while idx != -1: if spacey(self.spaced[pos]): spaces += 1 else: idx -= 1 pos += 1 - return idx + spaces + return idx0 + spaces From 6a938f2ee7ba48e891a783b0dd8880e0faa55883 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 16:52:02 -0700 Subject: [PATCH 130/264] Fix docstring nit --- certbot-nginx/certbot_nginx/tests/nginxparser_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 4c239ac10..1707bc6d6 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -176,7 +176,7 @@ class TestRawNginxParser(unittest.TestCase): ]) class TestUnspacedList(unittest.TestCase): - """Test the raw low-level Nginx config parser.""" + """Test the UnspacedList data structure""" def setUp(self): self.a = ["\n ", "things", " ", "quirk"] self.b = ["y", " "] From 880cb0319164d63ee6fed7a1e6cabcd4e46fd18c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 18:50:18 -0700 Subject: [PATCH 131/264] Make assertions about index policing --- certbot-nginx/certbot_nginx/tests/nginxparser_test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index 1707bc6d6..a0ef82cd5 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -219,6 +219,10 @@ class TestUnspacedList(unittest.TestCase): self.assertEqual(ul3, ["zither", ["zather", "zest"]]) self.assertEqual(ul3.spaced, [self.a[0], "zither", " ", l]) + def test_get(self): + self.assertRaises(IndexError, self.ul2.__getitem__, 2) + self.assertRaises(IndexError, self.ul2.__getitem__, -3) + def test_rawlists(self): ul3 = copy.deepcopy(self.ul) ul3.insert(0, "some") From 0dc4639cbffe023520c18af375d2e909cdab0137 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 18:56:30 -0700 Subject: [PATCH 132/264] Be more explicit about range policing (rather than doing it in some roundabout crazy way) --- certbot-nginx/certbot_nginx/nginxparser.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 412268d22..1de079cab 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -239,6 +239,8 @@ class UnspacedList(list): # Normalize indexes like list[-1] etc, and save the result if idx < 0: idx = len(self) + idx + if not 0 <= idx < len(self): + raise IndexError("list index out of range") idx0 = idx # Count the number of spaces in the spaced list before idx in the unspaced one while idx != -1: From 98d261596c554e31346f4aec69fd8356167e851c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 19:03:46 -0700 Subject: [PATCH 133/264] Raise NotImplemented for all problematic list methods --- certbot-nginx/certbot_nginx/nginxparser.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 1de079cab..065858797 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -213,6 +213,16 @@ class UnspacedList(list): l.extend(other) return l + def index(self, _, _j=0, _k=0): + raise NotImplementedError("UnspacedList.index() not yet implemented") + def pop(self, _): + raise NotImplementedError("UnspacedList.pop() not yet implemented") + def remove(self, _): + raise NotImplementedError("UnspacedList.remove() not yet implemented") + def reverse(self, _): + raise NotImplementedError("UnspacedList.reverse() not yet implemented") + def sort(self, _cmp=None, _key=None, _Rev=None): + raise NotImplementedError("UnspacedList.sort() not yet implemented") def __setslice__(self, i, j, newslice): raise NotImplementedError("Slice operations on UnspacedLists not yet implemented") From 797d0a066072189c0745319bc8c4d524534e1d31 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Wed, 15 Jun 2016 13:39:42 +0200 Subject: [PATCH 134/264] Printing pip output to terminal when -v is used Signed-off-by: Amjad Mashaal --- letsencrypt-auto-source/letsencrypt-auto.template | 12 +++++++++--- letsencrypt-auto-source/tests/auto_test.py | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index e8f313208..d838e976d 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -247,13 +247,19 @@ UNLIKELY_EOF # Set PATH so pipstrap upgrades the right (v)env: PATH="$VENV_BIN:$PATH" "$VENV_BIN/python" "$TEMP_DIR/pipstrap.py" set +e - PIP_OUT=`"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1` + if [ "$VERBOSE" = 1 ]; then + "$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1 + else + PIP_OUT=`"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1` + fi PIP_STATUS=$? set -e if [ "$PIP_STATUS" != 0 ]; then # Report error. (Otherwise, be quiet.) - echo "Had a problem while installing Python packages:" - echo "$PIP_OUT" + echo "Had a problem while installing Python packages." + if [ "$VERBOSE" != 1 ]; then + echo "$PIP_OUT" + fi rm -rf "$VENV_PATH" exit 1 fi diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index 56023bc6f..8aea6603a 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -201,7 +201,7 @@ iQIDAQAB **kwargs) env.update(d) return out_and_err( - join(venv_dir, 'letsencrypt-auto') + ' --version', + join(venv_dir, 'letsencrypt-auto') + ' --verbose --version', shell=True, env=env) From f6069c2297364dbed088265745f9fd7ede7c4402 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 18:23:09 -0700 Subject: [PATCH 135/264] Explain what is happening when the user cancels vhost selection --- certbot-apache/certbot_apache/obj.py | 4 ++++ certbot-apache/certbot_apache/tls_sni_01.py | 1 + 2 files changed, 5 insertions(+) diff --git a/certbot-apache/certbot_apache/obj.py b/certbot-apache/certbot_apache/obj.py index b88b22428..c1af352cb 100644 --- a/certbot-apache/certbot_apache/obj.py +++ b/certbot-apache/certbot_apache/obj.py @@ -6,6 +6,7 @@ from certbot.plugins import common class Addr(common.Addr): """Represents an Apache address.""" + def __eq__(self, other): """This is defined as equalivalent within Apache. @@ -18,6 +19,9 @@ class Addr(common.Addr): self.is_wildcard() and other.is_wildcard())) return False + def __repr__(self): + return "certbot_apache.obj.Addr(" + repr(self.tup) + ")" + def __ne__(self, other): return not self.__eq__(other) diff --git a/certbot-apache/certbot_apache/tls_sni_01.py b/certbot-apache/certbot_apache/tls_sni_01.py index f14f7be0f..187ecd279 100644 --- a/certbot-apache/certbot_apache/tls_sni_01.py +++ b/certbot-apache/certbot_apache/tls_sni_01.py @@ -129,6 +129,7 @@ class ApacheTlsSni01(common.TLSSNI01): # because it's a new vhost that's not configured yet (GH #677), # or perhaps because there were multiple sections # in the config file (GH #1042). See also GH #2600. + logger.warn("Attempting to fall back to default vhost %s...", default_addr) addrs.add(default_addr) return addrs From e0691ede2c25ed361bee9cd7ae4e76515e65f564 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 18:43:29 -0700 Subject: [PATCH 136/264] Provide clear log messages when Apache tries a default vhost --- certbot-apache/certbot_apache/configurator.py | 9 ++++++--- certbot-apache/certbot_apache/display_ops.py | 9 +++++---- certbot-apache/certbot_apache/tls_sni_01.py | 4 ++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 9e404177a..c51778ce5 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -327,9 +327,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): vhost = display_ops.select_vhost(target_name, self.vhosts) if vhost is None: logger.error( - "No vhost exists with servername or alias of: %s. " - "No vhost was selected. Please specify servernames " - "in the Apache config", target_name) + "No vhost exists with servername or alias of: %s " + "(or it's in a file with multiple files, which Certbot " + "can't parse yet). " + "No vhost was selected. Please specify ServerName or ServerAlias " + "in the Apache config, or split vhosts into separate files.", + target_name) raise errors.PluginError("No vhost selected") elif temp: return vhost diff --git a/certbot-apache/certbot_apache/display_ops.py b/certbot-apache/certbot_apache/display_ops.py index c9359e7d3..6b2964426 100644 --- a/certbot-apache/certbot_apache/display_ops.py +++ b/certbot-apache/certbot_apache/display_ops.py @@ -87,10 +87,11 @@ def _vhost_menu(domain, vhosts): "vhosts are not yet supported)".format(domain, os.linesep), choices, help_label="More Info", ok_label="Select") except errors.MissingCommandlineFlag as e: - msg = ("Failed to run Apache plugin non-interactively{1}{0}{1}" - "(The best solution is to add ServerName or ServerAlias " - "entries to the VirtualHost directives of your apache " - "configuration files.)".format(e, os.linesep)) + msg = ("Encountered vhost ambiguity but unable to ask for user guidance in " + "non-interactive mode. Currently Certbot needs each vhost to be " + "in its own conf file, and may need vhosts to be explicitly " + "labelled with ServerName or ServerAlias directories.") + logger.warn(msg) raise errors.MissingCommandlineFlag(msg) return code, tag diff --git a/certbot-apache/certbot_apache/tls_sni_01.py b/certbot-apache/certbot_apache/tls_sni_01.py index 187ecd279..32529485b 100644 --- a/certbot-apache/certbot_apache/tls_sni_01.py +++ b/certbot-apache/certbot_apache/tls_sni_01.py @@ -124,12 +124,12 @@ class ApacheTlsSni01(common.TLSSNI01): try: vhost = self.configurator.choose_vhost(achall.domain, temp=True) - except (PluginError, MissingCommandlineFlag): + except (PluginError, MissingCommandlineFlag), e: # We couldn't find the virtualhost for this domain, possibly # because it's a new vhost that's not configured yet (GH #677), # or perhaps because there were multiple sections # in the config file (GH #1042). See also GH #2600. - logger.warn("Attempting to fall back to default vhost %s...", default_addr) + logger.warn("Falling back to default vhost %s...", default_addr) addrs.add(default_addr) return addrs From e93ace79cc58063f34cc665c96cbcaa951478ebd Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 25 Jun 2016 10:51:14 -0700 Subject: [PATCH 137/264] Test coverage & fix --- certbot-apache/certbot_apache/display_ops.py | 2 +- certbot-apache/certbot_apache/tests/display_ops_test.py | 2 +- certbot-apache/certbot_apache/tests/obj_test.py | 3 +++ certbot-apache/certbot_apache/tls_sni_01.py | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/certbot-apache/certbot_apache/display_ops.py b/certbot-apache/certbot_apache/display_ops.py index 6b2964426..24aabaed4 100644 --- a/certbot-apache/certbot_apache/display_ops.py +++ b/certbot-apache/certbot_apache/display_ops.py @@ -86,7 +86,7 @@ def _vhost_menu(domain, vhosts): "like to choose?\n(note: conf files with multiple " "vhosts are not yet supported)".format(domain, os.linesep), choices, help_label="More Info", ok_label="Select") - except errors.MissingCommandlineFlag as e: + except errors.MissingCommandlineFlag: msg = ("Encountered vhost ambiguity but unable to ask for user guidance in " "non-interactive mode. Currently Certbot needs each vhost to be " "in its own conf file, and may need vhosts to be explicitly " diff --git a/certbot-apache/certbot_apache/tests/display_ops_test.py b/certbot-apache/certbot_apache/tests/display_ops_test.py index fd1e52fde..585661c7f 100644 --- a/certbot-apache/certbot_apache/tests/display_ops_test.py +++ b/certbot-apache/certbot_apache/tests/display_ops_test.py @@ -38,7 +38,7 @@ class SelectVhostTest(unittest.TestCase): try: self._call(self.vhosts) except errors.MissingCommandlineFlag as e: - self.assertTrue("VirtualHost directives" in e.message) + self.assertTrue("vhost ambiguity" in e.message) @mock.patch("certbot_apache.display_ops.zope.component.getUtility") def test_more_info_cancel(self, mock_util): diff --git a/certbot-apache/certbot_apache/tests/obj_test.py b/certbot-apache/certbot_apache/tests/obj_test.py index 4c3d331be..10dba18bc 100644 --- a/certbot-apache/certbot_apache/tests/obj_test.py +++ b/certbot-apache/certbot_apache/tests/obj_test.py @@ -22,6 +22,9 @@ class VirtualHostTest(unittest.TestCase): self.vhost2 = VirtualHost( "fp", "vhp", set([self.addr2]), False, False, "localhost") + def test_repr(self): + self.assertEqual(repr(self.addr2), "certbot_apache.obj.Addr(('127.0.0.1', '443'))") + def test_eq(self): self.assertTrue(self.vhost1b == self.vhost1) self.assertFalse(self.vhost1 == self.vhost2) diff --git a/certbot-apache/certbot_apache/tls_sni_01.py b/certbot-apache/certbot_apache/tls_sni_01.py index 32529485b..06d9e9ebd 100644 --- a/certbot-apache/certbot_apache/tls_sni_01.py +++ b/certbot-apache/certbot_apache/tls_sni_01.py @@ -124,7 +124,7 @@ class ApacheTlsSni01(common.TLSSNI01): try: vhost = self.configurator.choose_vhost(achall.domain, temp=True) - except (PluginError, MissingCommandlineFlag), e: + except (PluginError, MissingCommandlineFlag): # We couldn't find the virtualhost for this domain, possibly # because it's a new vhost that's not configured yet (GH #677), # or perhaps because there were multiple sections From 23f0ccbc8ee7f03b094c96fd2f776919b4f72d7c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 25 Jun 2016 12:22:45 -0700 Subject: [PATCH 138/264] Address review issues --- certbot/display/util.py | 21 ++++++++++++++++----- certbot/tests/display/util_test.py | 2 ++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/certbot/display/util.py b/certbot/display/util.py index c998f78f3..4e7d45741 100644 --- a/certbot/display/util.py +++ b/certbot/display/util.py @@ -1,4 +1,5 @@ """Certbot display.""" +import logging import os import textwrap @@ -9,6 +10,9 @@ from certbot import interfaces from certbot import errors from certbot.display import completer + +logger = logging.getLogger(__name__) + WIDTH = 72 HEIGHT = 20 @@ -29,6 +33,10 @@ CANCEL = "cancel" HELP = "help" """Display exit code when for when the user requests more help.""" +ESC = "esc" +"""Display exit code when the user hits Escape""" + + def _wrap_lines(msg): """Format lines nicely to 80 chars. @@ -52,7 +60,7 @@ def _wrap_lines(msg): def _clean(dialog_result): - """Work around inconsistent return codes from python-dialog. + """Treat sundy python-dialog return codes as CANCEL :param tuple dialog_result: (code, result) :returns: the argument but with unknown codes set to -1 (Error) @@ -61,7 +69,10 @@ def _clean(dialog_result): code, result = dialog_result if code in (OK, HELP): return dialog_result + elif code in (CANCEL, ESC): + return (CANCEL, result) else: + logger.info("Surprising dialog return code %s", code) return (CANCEL, result) @@ -199,8 +210,8 @@ class NcursesDisplay(object): """ choices = [(tag, "", default_status) for tag in tags] - return self.dialog.checklist( - message, width=self.width, height=self.height, choices=choices) + return _clean(self.dialog.checklist( + message, width=self.width, height=self.height, choices=choices)) def directory_select(self, message, **unused_kwargs): """Display a directory selection screen. @@ -213,9 +224,9 @@ class NcursesDisplay(object): """ root_directory = os.path.abspath(os.sep) - return self.dialog.dselect( + return _clean(self.dialog.dselect( filepath=root_directory, width=self.width, - height=self.height, help_button=True, title=message) + height=self.height, help_button=True, title=message)) @zope.interface.implementer(interfaces.IDisplay) diff --git a/certbot/tests/display/util_test.py b/certbot/tests/display/util_test.py index 94338118d..a6ced90ab 100644 --- a/certbot/tests/display/util_test.py +++ b/certbot/tests/display/util_test.py @@ -113,6 +113,7 @@ class NcursesDisplayTest(unittest.TestCase): @mock.patch("certbot.display.util." "dialog.Dialog.checklist") def test_checklist(self, mock_checklist): + mock_checklist.return_value = (mock.MagicMock(), mock.MagicMock()) self.displayer.checklist("message", TAGS) choices = [ @@ -126,6 +127,7 @@ class NcursesDisplayTest(unittest.TestCase): @mock.patch("certbot.display.util.dialog.Dialog.dselect") def test_directory_select(self, mock_dselect): + mock_dselect.return_value = (mock.MagicMock(), mock.MagicMock()) self.displayer.directory_select("message") self.assertEqual(mock_dselect.call_count, 1) From 6f7ed85844c8842743228a5afb9163c7642225aa Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Wed, 25 May 2016 00:17:47 +0200 Subject: [PATCH 139/264] -v implies --text --- certbot/cli.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certbot/cli.py b/certbot/cli.py index 35b3b74ae..244d321d8 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -392,6 +392,11 @@ class HelpfulArgumentParser(object): ("Conflicting values for displayer." " {0} conflicts with dialog_mode").format(arg) ) + else: + # -v should imply --text + if (parsed_args.verbose_count > flag_default("verbose_count") and + not parsed_args.dialog_mode): + parsed_args.text_mode = True if parsed_args.validate_hooks: hooks.validate_hooks(parsed_args) From fdbb69930b53e8032dcb390b7c8c94e7f35408ec Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 27 Jun 2016 12:00:41 -0700 Subject: [PATCH 140/264] Tweak the NotImplementedError cases --- certbot-nginx/certbot_nginx/nginxparser.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 065858797..1f0569651 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -213,17 +213,15 @@ class UnspacedList(list): l.extend(other) return l - def index(self, _, _j=0, _k=0): - raise NotImplementedError("UnspacedList.index() not yet implemented") - def pop(self, _): + def pop(self, _i=0): raise NotImplementedError("UnspacedList.pop() not yet implemented") def remove(self, _): raise NotImplementedError("UnspacedList.remove() not yet implemented") - def reverse(self, _): + def reverse(self): raise NotImplementedError("UnspacedList.reverse() not yet implemented") def sort(self, _cmp=None, _key=None, _Rev=None): raise NotImplementedError("UnspacedList.sort() not yet implemented") - def __setslice__(self, i, j, newslice): + def __setslice__(self, _i, _j, _newslice): raise NotImplementedError("Slice operations on UnspacedLists not yet implemented") def __setitem__(self, i, value): From 184f54cbc799039276ad2c7eb17a307b363ca9ac Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 27 Jun 2016 12:36:28 -0700 Subject: [PATCH 141/264] cosmetic improvements --- certbot-nginx/certbot_nginx/nginxparser.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 1f0569651..ccf680dfc 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -41,7 +41,8 @@ class RawNginxParser(object): block = Forward() block << Group( - # key could for instance be "server" or "http" + # key could for instance be "server" or "http", or "location" (in which case + # location_statement needs to have a non-empty location) (Group(space + key + location_statement) ^ Group(if_statement) ^ Group(map_statement)).leaveWhitespace() + left_bracket + @@ -213,7 +214,7 @@ class UnspacedList(list): l.extend(other) return l - def pop(self, _i=0): + def pop(self, _i=None): raise NotImplementedError("UnspacedList.pop() not yet implemented") def remove(self, _): raise NotImplementedError("UnspacedList.remove() not yet implemented") From 6017a6cb6daca4a0eddd7a85b874f66e26d9d78c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 24 Jun 2016 17:14:14 -0700 Subject: [PATCH 142/264] Only write nginx config files if we've modified them --- certbot-nginx/certbot_nginx/nginxparser.py | 17 +++++++++++++++-- certbot-nginx/certbot_nginx/parser.py | 5 ++++- .../certbot_nginx/tests/parser_test.py | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index ccf680dfc..816507738 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -163,6 +163,7 @@ class UnspacedList(list): def __init__(self, list_source): # ensure our argument is not a generator, and duplicate any sublists self.spaced = copy.deepcopy(list(list_source)) + self.dirty = False # Turn self into a version of the source list that has spaces removed # and all sub-lists also UnspacedList()ed @@ -198,20 +199,24 @@ class UnspacedList(list): item, spaced_item = self._coerce(x) self.spaced.insert(self._spaced_position(i), spaced_item) list.insert(self, i, item) + self.dirty = True def append(self, x): item, spaced_item = self._coerce(x) self.spaced.append(spaced_item) list.append(self, item) + self.dirty = True def extend(self, x): item, spaced_item = self._coerce(x) self.spaced.extend(spaced_item) list.extend(self, item) + self.dirty = True def __add__(self, other): l = copy.deepcopy(self) l.extend(other) + l.dirty = True return l def pop(self, _i=None): @@ -231,16 +236,24 @@ class UnspacedList(list): item, spaced_item = self._coerce(value) self.spaced.__setitem__(self._spaced_position(i), spaced_item) list.__setitem__(self, i, item) + self.dirty = True def __delitem__(self, i): self.spaced.__delitem__(self._spaced_position(i)) list.__delitem__(self, i) + self.dirty = True - def __deepcopy__(self, unused_memo): + def __deepcopy__(self, memo): l = UnspacedList(self[:]) - l.spaced = copy.deepcopy(self.spaced) + l.spaced = copy.deepcopy(self.spaced, memo=memo) + l.dirty = self.dirty return l + def is_dirty(self): + """Recurse through the parse tree to figure out if any sublists are dirty""" + if self.dirty: + return True + return any((isinstance(x, list) and x.is_dirty() for x in self)) def _spaced_position(self, idx): "Convert from indexes in the unspaced list to positions in the spaced one" diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index f2c10ab70..e7992810a 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -205,11 +205,12 @@ class NginxParser(object): raise errors.NoInstallationError( "Could not find configuration root") - def filedump(self, ext='tmp'): + def filedump(self, ext='tmp', lazy=True): """Dumps parsed configurations into files. :param str ext: The file extension to use for the dumped files. If empty, this overrides the existing conf files. + :param bool lazy: Only write files that have been modified """ # Best-effort atomicity is enforced above us by reverter.py @@ -218,6 +219,8 @@ class NginxParser(object): if ext: filename = filename + os.path.extsep + ext try: + if lazy and not tree.is_dirty(): + continue out = nginxparser.dumps(tree) logger.debug('Writing nginx conf tree to %s:\n%s', filename, out) with open(filename, 'w') as _file: diff --git a/certbot-nginx/certbot_nginx/tests/parser_test.py b/certbot-nginx/certbot_nginx/tests/parser_test.py index 6d046178a..464d717ed 100644 --- a/certbot-nginx/certbot_nginx/tests/parser_test.py +++ b/certbot-nginx/certbot_nginx/tests/parser_test.py @@ -66,7 +66,7 @@ class NginxParserTest(util.NginxTest): def test_filedump(self): nparser = parser.NginxParser(self.config_path, self.ssl_options) - nparser.filedump('test') + nparser.filedump('test', lazy=False) # pylint: disable=protected-access parsed = nparser._parse_files(nparser.abs_path( 'sites-enabled/example.com.test')) From 3e9bf2f35f6fc91e7b56109d3ee81685970b2271 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 23 Jun 2016 14:03:28 -0700 Subject: [PATCH 143/264] Tests for UnspacedList.is_dirty() --- certbot-nginx/certbot_nginx/tests/nginxparser_test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py index a0ef82cd5..a0a0736a5 100644 --- a/certbot-nginx/certbot_nginx/tests/nginxparser_test.py +++ b/certbot-nginx/certbot_nginx/tests/nginxparser_test.py @@ -231,6 +231,17 @@ class TestUnspacedList(unittest.TestCase): del ul3[2] self.assertEqual(ul3, ["some", "things", "why", "did", "whether"]) + def test_is_dirty(self): + self.assertEqual(False, self.ul2.is_dirty()) + ul3 = UnspacedList([]) + ul3.append(self.ul) + self.assertEqual(False, self.ul.is_dirty()) + self.assertEqual(True, ul3.is_dirty()) + ul4 = UnspacedList([[1], [2, 3, 4]]) + self.assertEqual(False, ul4.is_dirty()) + ul4[1][2] = 5 + self.assertEqual(True, ul4.is_dirty()) + if __name__ == '__main__': unittest.main() # pragma: no cover From bdbdd826de3ec8cecf3834e7b44848faa93b3721 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 27 Jun 2016 12:44:53 -0700 Subject: [PATCH 144/264] Extra comment & concision --- certbot-nginx/certbot_nginx/nginxparser.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 816507738..d6c352296 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -1,4 +1,5 @@ """Very low-level nginx config parser based on pyparsing.""" +# Forked from https://github.com/fatiherikli/nginxparser (MIT Licensed) import copy import logging import string @@ -81,8 +82,7 @@ class RawNginxDumper(object): yield b.pop(0) # indentation if not b: continue - key = b.pop(0) - values = b.pop(0) + key, values = b.pop(0), b.pop(0) if isinstance(key, list): yield "".join(key) + '{' @@ -91,9 +91,9 @@ class RawNginxDumper(object): yield line yield '}' else: - if isinstance(key, str) and key.strip() == '#': + if isinstance(key, str) and key.strip() == '#': # comment yield key + values - else: + else: # assignment gap = "" # Sometimes the parser has stuck some gap whitespace in here; # if so rotate it into gap From bbd5ce45e90ba6bb0aaf3d55dcf87c9f2ad7552d Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 28 Jun 2016 13:49:44 -0500 Subject: [PATCH 145/264] Defer signals in ErrorHandler. --- certbot/error_handler.py | 46 ++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index 431e677a1..5b9220583 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -19,6 +19,14 @@ _SIGNALS = ([signal.SIGTERM] if os.name == "nt" else signal.SIGXCPU, signal.SIGXFSZ]) +class SignalExit(Exception): + """This exception is used stop of execution of the code in the body of the + ErrorHandler context manager. + + """ + pass + + class ErrorHandler(object): """Registers functions to be called if an exception or signal occurs. @@ -34,16 +42,17 @@ class ErrorHandler(object): if a signal is encountered, cleanup_func is called followed by the previously registered signal handler. - Every registered function is attempted to be run to completion - exactly once. If a registered function raises an exception, it is - logged and the next function is called. If a (different) handled - signal occurs while calling a registered function, it is attempted - to be called again by the next signal handler. + Each registered cleanup function is called exactly once. If a registered + function raises an exception, it is logged and the next function is called. + Signals received while the registered functions are executing are + deferred until they finish. """ def __init__(self, func=None, *args, **kwargs): + self.body_executed = False self.funcs = [] self.prev_handlers = {} + self.received_signals = [] if func is not None: self.register(func, *args, **kwargs) @@ -51,12 +60,22 @@ class ErrorHandler(object): self.set_signal_handlers() def __exit__(self, exec_type, exec_value, trace): + self.body_executed = True + retval = False + if exec_type is SignalExit: + logger.debug("Encountered signals: %s", self.received_signals) + self.call_registered() + for signum in self.received_signals: + self.call_signal(signum) + retval = True # SystemExit is ignored to properly handle forks that don't exec - if exec_type not in (None, SystemExit): + elif exec_type not in (None, SystemExit): logger.debug("Encountered exception:\n%s", "".join( traceback.format_exception(exec_type, exec_value, trace))) self.call_registered() + self.reset_signal_handlers() + return retval def register(self, func, *args, **kwargs): """Sets func to be called with *args and **kwargs during cleanup @@ -93,12 +112,21 @@ class ErrorHandler(object): self.prev_handlers.clear() def _signal_handler(self, signum, unused_frame): - """Calls registered functions and the previous signal handler. + """Stores the recieved signal. :param int signum: number of current signal """ - logger.debug("Singal %s encountered", signum) - self.call_registered() + self.received_signals.append(signum) + if not self.body_executed: + raise SignalExit + + def call_signal(self, signum): + """Calls the signal given by signum. + + :param int signum: signal number + + """ + logger.debug("Calling signal %s", signum) signal.signal(signum, self.prev_handlers[signum]) os.kill(os.getpid(), signum) From 1356941f9760c4cda79097716c6cf86d0d179e07 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 28 Jun 2016 13:58:26 -0500 Subject: [PATCH 146/264] Test signal handling in error handler. --- certbot/tests/error_handler_test.py | 61 +++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index 5434b36be..c2551195a 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -1,11 +1,33 @@ """Tests for certbot.error_handler.""" +import os import signal import sys import unittest +from contextlib import contextmanager import mock +@contextmanager +def signal_receiver(signums): + """Context manager to catch signals""" + def receiver(signum, unused_frame): + signals.append(signum) + signals = [] + prev_handlers = {} + for signum in signums: + prev_handlers[signum] = signal.getsignal(signum) + signal.signal(signum, receiver) + yield signals + for signum in signums: + signal.signal(signum, prev_handlers[signum]) + + +def send_signal(signum): + """Send the given signal""" + os.kill(os.getpid(), signum) + + class ErrorHandlerTest(unittest.TestCase): """Tests for certbot.error_handler.""" @@ -30,25 +52,20 @@ class ErrorHandlerTest(unittest.TestCase): self.init_func.assert_called_once_with(*self.init_args, **self.init_kwargs) - @mock.patch('certbot.error_handler.os') - @mock.patch('certbot.error_handler.signal') - def test_signal_handler(self, mock_signal, mock_os): - # pylint: disable=protected-access - mock_signal.getsignal.return_value = signal.SIG_DFL - self.handler.set_signal_handlers() - signal_handler = self.handler._signal_handler - for signum in self.signals: - mock_signal.signal.assert_any_call(signum, signal_handler) + def test_context_manager_with_signal(self): + with signal_receiver(self.signals) as signals_received: + with self.handler: + should_be_42 = 42 + send_signal(signal.SIGTERM) + should_be_42 *= 10 - signum = self.signals[0] - signal_handler(signum, None) + # check exectuion stoped when the signal was sent + assert 42 == should_be_42 + # assert signals were caught + assert [signal.SIGTERM] == signals_received + # assert the error handling function was just called once self.init_func.assert_called_once_with(*self.init_args, **self.init_kwargs) - mock_os.kill.assert_called_once_with(mock_os.getpid(), signum) - - self.handler.reset_signal_handlers() - for signum in self.signals: - mock_signal.signal.assert_any_call(signum, signal.SIG_DFL) def test_bad_recovery(self): bad_func = mock.MagicMock(side_effect=[ValueError]) @@ -58,6 +75,18 @@ class ErrorHandlerTest(unittest.TestCase): **self.init_kwargs) bad_func.assert_called_once_with() + def test_bad_recovery_with_signal(self): + bad_func = mock.MagicMock( + side_effect=lambda: send_signal(signal.SIGHUP)) + self.handler.register(bad_func) + with signal_receiver(self.signals) as signals_received: + with self.handler: + send_signal(signal.SIGTERM) + assert [signal.SIGTERM, signal.SIGHUP] == signals_received + self.init_func.assert_called_once_with(*self.init_args, + **self.init_kwargs) + bad_func.assert_called_once_with() + def test_sysexit_ignored(self): try: with self.handler: From e6521414499247570e8e252ad5bc1d32fbdf33c3 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 28 Jun 2016 16:55:46 -0500 Subject: [PATCH 147/264] Use lambda instead of closure. --- certbot/tests/error_handler_test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index c2551195a..f8ac0718b 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -11,13 +11,11 @@ import mock @contextmanager def signal_receiver(signums): """Context manager to catch signals""" - def receiver(signum, unused_frame): - signals.append(signum) signals = [] prev_handlers = {} for signum in signums: prev_handlers[signum] = signal.getsignal(signum) - signal.signal(signum, receiver) + signal.signal(signum, lambda signum, _: signals.append(signum)) yield signals for signum in signums: signal.signal(signum, prev_handlers[signum]) From 78b30539faa87fbeb6edea99d5685173a2439505 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Tue, 28 Jun 2016 17:56:31 -0700 Subject: [PATCH 148/264] augeas tests --- .../certbot_apache/tests/configurator_test.py | 33 +++ .../augeas_vhosts/apache2/apache2.conf | 196 ++++++++++++++++++ .../apache2/conf-available/bad_conf_file.conf | 3 + .../other-vhosts-access-log.conf | 4 + .../apache2/conf-available/security.conf | 35 ++++ .../apache2/conf-available/serve-cgi-bin.conf | 20 ++ .../conf-enabled/other-vhosts-access-log.conf | 1 + .../apache2/conf-enabled/security.conf | 1 + .../apache2/conf-enabled/serve-cgi-bin.conf | 1 + .../augeas_vhosts/apache2/envvars | 29 +++ .../apache2/mods-available/authz_svn.load | 5 + .../apache2/mods-available/dav.load | 3 + .../apache2/mods-available/dav_svn.conf | 56 +++++ .../apache2/mods-available/dav_svn.load | 7 + .../apache2/mods-available/rewrite.load | 1 + .../apache2/mods-available/ssl.conf | 89 ++++++++ .../apache2/mods-available/ssl.load | 2 + .../apache2/mods-enabled/.gitignore | 0 .../apache2/mods-enabled/authz_svn.load | 1 + .../apache2/mods-enabled/dav.load | 1 + .../apache2/mods-enabled/dav_svn.conf | 1 + .../apache2/mods-enabled/dav_svn.load | 1 + .../augeas_vhosts/apache2/ports.conf | 15 ++ .../apache2/sites-available/000-default.conf | 12 ++ .../apache2/sites-available/certbot.conf | 42 ++++ .../default-ssl-port-only.conf | 36 ++++ .../apache2/sites-available/default-ssl.conf | 40 ++++ .../sites-available/encryption-example.conf | 42 ++++ .../sites-available/mod_macro-example.conf | 15 ++ .../apache2/sites-available/ocsp-ssl.conf | 36 ++++ .../apache2/sites-available/old,default.conf | 12 ++ .../apache2/sites-available/wildcard.conf | 13 ++ .../apache2/sites-enabled/000-default.conf | 1 + .../apache2/sites-enabled/certbot.conf | 1 + .../sites-enabled/encryption-example.conf | 1 + .../sites-enabled/mod_macro-example.conf | 1 + .../apache2/sites-enabled/ocsp-ssl.conf | 1 + .../debian_apache_2_4/augeas_vhosts/sites | 3 + 38 files changed, 761 insertions(+) create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/apache2.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/bad_conf_file.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/other-vhosts-access-log.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/security.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/serve-cgi-bin.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/other-vhosts-access-log.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/security.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/serve-cgi-bin.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/envvars create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/authz_svn.load create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav.load create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav_svn.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav_svn.load create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/rewrite.load create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/ssl.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/ssl.load create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/.gitignore create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/authz_svn.load create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav.load create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav_svn.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav_svn.load create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/ports.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/000-default.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/certbot.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl-port-only.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/encryption-example.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/mod_macro-example.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/ocsp-ssl.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/old,default.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/wildcard.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/000-default.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/certbot.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/encryption-example.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/mod_macro-example.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/ocsp-ssl.conf create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/sites diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index e5c09fd1d..fca62a626 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -1169,6 +1169,39 @@ class MultipleVhostsTest(util.ApacheTest): self.config.aug.match.side_effect = RuntimeError self.assertFalse(self.config._check_aug_version()) +class AugeasVhostsTest(util.ApacheTest): + """Test vhosts with illegal names dependant on augeas version.""" + + def setUp(self): # pylint: disable=arguments-differ + super(AugeasVhostsTest, self).setUp(test_dir="debian_apache_2_4/augeas_vhosts", + config_root="debian_apache_2_4/augeas_vhosts/apache2", + vhost_root="debian_apache_2_4/augeas_vhosts/apache2/sites-available") + + self.config = util.get_apache_configurator( + self.config_path, self.vhost_path, self.config_dir, self.work_dir) + self.config = self.mock_deploy_cert(self.config) + self.vh_truth = util.get_vh_truth( + self.temp_dir, "debian_apache_2_4/augeas_vhosts") + + def mock_deploy_cert(self, config): + """A test for a mock deploy cert""" + self.config.real_deploy_cert = self.config.deploy_cert + + def mocked_deploy_cert(*args, **kwargs): + """a helper to mock a deployed cert""" + with mock.patch("certbot_apache.configurator.ApacheConfigurator.enable_mod"): + config.real_deploy_cert(*args, **kwargs) + self.config.deploy_cert = mocked_deploy_cert + return self.config + + def tearDown(self): + shutil.rmtree(self.temp_dir) + shutil.rmtree(self.config_dir) + shutil.rmtree(self.work_dir) + + def test_choosevhost_with_illegal_name(self): + chosen_vhost = self.config._create_vhost("debian_apache_2_4/augeas_vhosts/apache2/sites-available/old,default.conf") + self.assertEqual(None, chosen_vhost) if __name__ == "__main__": unittest.main() # pragma: no cover diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/apache2.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/apache2.conf new file mode 100644 index 000000000..2a5bb7be2 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/apache2.conf @@ -0,0 +1,196 @@ +# This is the main Apache server configuration file. It contains the +# configuration directives that give the server its instructions. +# See http://httpd.apache.org/docs/2.4/ for detailed information about +# the directives and /usr/share/doc/apache2/README.Debian about Debian specific +# hints. +# +# +# Summary of how the Apache 2 configuration works in Debian: +# The Apache 2 web server configuration in Debian is quite different to +# upstream's suggested way to configure the web server. This is because Debian's +# default Apache2 installation attempts to make adding and removing modules, +# virtual hosts, and extra configuration directives as flexible as possible, in +# order to make automating the changes and administering the server as easy as +# possible. + +# It is split into several files forming the configuration hierarchy outlined +# below, all located in the /etc/apache2/ directory: +# +# /etc/apache2/ +# |-- apache2.conf +# | `-- ports.conf +# |-- mods-enabled +# | |-- *.load +# | `-- *.conf +# |-- conf-enabled +# | `-- *.conf +# `-- sites-enabled +# `-- *.conf +# +# +# * apache2.conf is the main configuration file (this file). It puts the pieces +# together by including all remaining configuration files when starting up the +# web server. +# +# * ports.conf is always included from the main configuration file. It is +# supposed to determine listening ports for incoming connections which can be +# customized anytime. +# +# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/ +# directories contain particular configuration snippets which manage modules, +# global configuration fragments, or virtual host configurations, +# respectively. +# +# They are activated by symlinking available configuration files from their +# respective *-available/ counterparts. These should be managed by using our +# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See +# their respective man pages for detailed information. +# +# * The binary is called apache2. Due to the use of environment variables, in +# the default configuration, apache2 needs to be started/stopped with +# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not +# work with the default configuration. + + +# Global configuration + +# +# The accept serialization lock file MUST BE STORED ON A LOCAL DISK. +# +Mutex file:${APACHE_LOCK_DIR} default + +# +# PidFile: The file in which the server should record its process +# identification number when it starts. +# This needs to be set in /etc/apache2/envvars +# +PidFile ${APACHE_PID_FILE} + +# +# Timeout: The number of seconds before receives and sends time out. +# +Timeout 300 + +# +# KeepAlive: Whether or not to allow persistent connections (more than +# one request per connection). Set to "Off" to deactivate. +# +KeepAlive On + +# +# MaxKeepAliveRequests: The maximum number of requests to allow +# during a persistent connection. Set to 0 to allow an unlimited amount. +# We recommend you leave this number high, for maximum performance. +# +MaxKeepAliveRequests 100 + +# +# KeepAliveTimeout: Number of seconds to wait for the next request from the +# same client on the same connection. +# +KeepAliveTimeout 5 + + +# These need to be set in /etc/apache2/envvars +User ${APACHE_RUN_USER} +Group ${APACHE_RUN_GROUP} + +# +# HostnameLookups: Log the names of clients or just their IP addresses +# e.g., www.apache.org (on) or 204.62.129.132 (off). +# The default is off because it'd be overall better for the net if people +# had to knowingly turn this feature on, since enabling it means that +# each client request will result in AT LEAST one lookup request to the +# nameserver. +# +HostnameLookups Off + +# ErrorLog: The location of the error log file. +# If you do not specify an ErrorLog directive within a +# container, error messages relating to that virtual host will be +# logged here. If you *do* define an error logfile for a +# container, that host's errors will be logged there and not here. +# +ErrorLog ${APACHE_LOG_DIR}/error.log + +# +# LogLevel: Control the severity of messages logged to the error_log. +# Available values: trace8, ..., trace1, debug, info, notice, warn, +# error, crit, alert, emerg. +# It is also possible to configure the log level for particular modules, e.g. +# "LogLevel info ssl:warn" +# +LogLevel warn + +# Include module configuration: +IncludeOptional mods-enabled/*.load +IncludeOptional mods-enabled/*.conf + +# Include list of ports to listen on +Include ports.conf + + +# Sets the default security model of the Apache2 HTTPD server. It does +# not allow access to the root filesystem outside of /usr/share and /var/www. +# The former is used by web applications packaged in Debian, +# the latter may be used for local directories served by the web server. If +# your system is serving content from a sub-directory in /srv you must allow +# access here, or in any related virtual host. + + Options FollowSymLinks + AllowOverride None + Require all denied + + + + AllowOverride None + Require all granted + + + + Options Indexes FollowSymLinks + AllowOverride None + Require all granted + + +# AccessFileName: The name of the file to look for in each directory +# for additional configuration directives. See also the AllowOverride +# directive. +# +AccessFileName .htaccess + +# +# The following lines prevent .htaccess and .htpasswd files from being +# viewed by Web clients. +# + + Require all denied + + +# The following directives define some format nicknames for use with +# a CustomLog directive. +# +# These deviate from the Common Log Format definitions in that they use %O +# (the actual bytes sent including headers) instead of %b (the size of the +# requested file), because the latter makes it impossible to detect partial +# requests. +# +# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended. +# Use mod_remoteip instead. +# +LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined +LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined +LogFormat "%h %l %u %t \"%r\" %>s %O" common +LogFormat "%{Referer}i -> %U" referer +LogFormat "%{User-agent}i" agent + +# Include of directories ignores editors' and dpkg's backup files, +# see README.Debian for details. + +# Include generic snippets of statements +IncludeOptional conf-enabled/*.conf + +# Include the virtual host configurations: +IncludeOptional sites-enabled/*.conf + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/bad_conf_file.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/bad_conf_file.conf new file mode 100644 index 000000000..8e9178803 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/bad_conf_file.conf @@ -0,0 +1,3 @@ + + +ServerName invalid.net diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/other-vhosts-access-log.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/other-vhosts-access-log.conf new file mode 100644 index 000000000..5e9f5e9e7 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/other-vhosts-access-log.conf @@ -0,0 +1,4 @@ +# Define an access log for VirtualHosts that don't define their own logfile +CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log vhost_combined + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/security.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/security.conf new file mode 100644 index 000000000..eccfcb1fd --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/security.conf @@ -0,0 +1,35 @@ +# Changing the following options will not really affect the security of the +# server, but might make attacks slightly more difficult in some cases. + +# +# ServerTokens +# This directive configures what you return as the Server HTTP response +# Header. The default is 'Full' which sends information about the OS-Type +# and compiled in modules. +# Set to one of: Full | OS | Minimal | Minor | Major | Prod +# where Full conveys the most information, and Prod the least. +#ServerTokens Minimal +ServerTokens OS +#ServerTokens Full + +# +# Optionally add a line containing the server version and virtual host +# name to server-generated pages (internal error documents, FTP directory +# listings, mod_status and mod_info output etc., but not CGI generated +# documents or custom error documents). +# Set to "EMail" to also include a mailto: link to the ServerAdmin. +# Set to one of: On | Off | EMail +#ServerSignature Off +ServerSignature On + +# +# Allow TRACE method +# +# Set to "extended" to also reflect the request body (only for testing and +# diagnostic purposes). +# +# Set to one of: On | Off | extended +TraceEnable Off +#TraceEnable On + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/serve-cgi-bin.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/serve-cgi-bin.conf new file mode 100644 index 000000000..b02782dab --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-available/serve-cgi-bin.conf @@ -0,0 +1,20 @@ + + + Define ENABLE_USR_LIB_CGI_BIN + + + + Define ENABLE_USR_LIB_CGI_BIN + + + + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Require all granted + + + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/other-vhosts-access-log.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/other-vhosts-access-log.conf new file mode 120000 index 000000000..8af91e530 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/other-vhosts-access-log.conf @@ -0,0 +1 @@ +../conf-available/other-vhosts-access-log.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/security.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/security.conf new file mode 120000 index 000000000..036c97fa7 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/security.conf @@ -0,0 +1 @@ +../conf-available/security.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/serve-cgi-bin.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/serve-cgi-bin.conf new file mode 120000 index 000000000..d917f688e --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/conf-enabled/serve-cgi-bin.conf @@ -0,0 +1 @@ +../conf-available/serve-cgi-bin.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/envvars b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/envvars new file mode 100644 index 000000000..a13d9a89e --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/envvars @@ -0,0 +1,29 @@ +# envvars - default environment variables for apache2ctl + +# this won't be correct after changing uid +unset HOME + +# for supporting multiple apache2 instances +if [ "${APACHE_CONFDIR##/etc/apache2-}" != "${APACHE_CONFDIR}" ] ; then + SUFFIX="-${APACHE_CONFDIR##/etc/apache2-}" +else + SUFFIX= +fi + +# Since there is no sane way to get the parsed apache2 config in scripts, some +# settings are defined via environment variables and then used in apache2ctl, +# /etc/init.d/apache2, /etc/logrotate.d/apache2, etc. +export APACHE_RUN_USER=www-data +export APACHE_RUN_GROUP=www-data +# temporary state file location. This might be changed to /run in Wheezy+1 +export APACHE_PID_FILE=/var/run/apache2/apache2$SUFFIX.pid +export APACHE_RUN_DIR=/var/run/apache2$SUFFIX +export APACHE_LOCK_DIR=/var/lock/apache2$SUFFIX +# Only /var/log/apache2 is handled by /etc/logrotate.d/apache2. +export APACHE_LOG_DIR=/var/log/apache2$SUFFIX + +## The locale used by some modules like mod_dav +export LANG=C + +export LANG + diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/authz_svn.load b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/authz_svn.load new file mode 100644 index 000000000..c6df2733b --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/authz_svn.load @@ -0,0 +1,5 @@ +# Depends: dav_svn + + Include mods-enabled/dav_svn.load + +LoadModule authz_svn_module /usr/lib/apache2/modules/mod_authz_svn.so diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav.load b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav.load new file mode 100644 index 000000000..a5867fff3 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav.load @@ -0,0 +1,3 @@ + + LoadModule dav_module /usr/lib/apache2/modules/mod_dav.so + diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav_svn.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav_svn.conf new file mode 100644 index 000000000..801cbd6bd --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav_svn.conf @@ -0,0 +1,56 @@ +# dav_svn.conf - Example Subversion/Apache configuration +# +# For details and further options see the Apache user manual and +# the Subversion book. +# +# NOTE: for a setup with multiple vhosts, you will want to do this +# configuration in /etc/apache2/sites-available/*, not here. + +# ... +# URL controls how the repository appears to the outside world. +# In this example clients access the repository as http://hostname/svn/ +# Note, a literal /svn should NOT exist in your document root. +# + + # Uncomment this to enable the repository + #DAV svn + + # Set this to the path to your repository + #SVNPath /var/lib/svn + # Alternatively, use SVNParentPath if you have multiple repositories under + # under a single directory (/var/lib/svn/repo1, /var/lib/svn/repo2, ...). + # You need either SVNPath and SVNParentPath, but not both. + #SVNParentPath /var/lib/svn + + # Access control is done at 3 levels: (1) Apache authentication, via + # any of several methods. A "Basic Auth" section is commented out + # below. (2) Apache and , also commented out + # below. (3) mod_authz_svn is a svn-specific authorization module + # which offers fine-grained read/write access control for paths + # within a repository. (The first two layers are coarse-grained; you + # can only enable/disable access to an entire repository.) Note that + # mod_authz_svn is noticeably slower than the other two layers, so if + # you don't need the fine-grained control, don't configure it. + + # Basic Authentication is repository-wide. It is not secure unless + # you are using https. See the 'htpasswd' command to create and + # manage the password file - and the documentation for the + # 'auth_basic' and 'authn_file' modules, which you will need for this + # (enable them with 'a2enmod'). + #AuthType Basic + #AuthName "Subversion Repository" + #AuthUserFile /etc/apache2/dav_svn.passwd + + # To enable authorization via mod_authz_svn (enable that module separately): + # + #AuthzSVNAccessFile /etc/apache2/dav_svn.authz + # + + # The following three lines allow anonymous read, but make + # committers authenticate themselves. It requires the 'authz_user' + # module (enable it with 'a2enmod'). + # + #Require valid-user + # + +# diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav_svn.load b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav_svn.load new file mode 100644 index 000000000..e41e1581a --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/dav_svn.load @@ -0,0 +1,7 @@ +# Depends: dav + + + Include mods-enabled/dav.load + + LoadModule dav_svn_module /usr/lib/apache2/modules/mod_dav_svn.so + diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/rewrite.load b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/rewrite.load new file mode 100644 index 000000000..b32f16264 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/rewrite.load @@ -0,0 +1 @@ +LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/ssl.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/ssl.conf new file mode 100644 index 000000000..e9fcf4f9b --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/ssl.conf @@ -0,0 +1,89 @@ + + + # Pseudo Random Number Generator (PRNG): + # Configure one or more sources to seed the PRNG of the SSL library. + # The seed data should be of good random quality. + # WARNING! On some platforms /dev/random blocks if not enough entropy + # is available. This means you then cannot use the /dev/random device + # because it would lead to very long connection times (as long as + # it requires to make more entropy available). But usually those + # platforms additionally provide a /dev/urandom device which doesn't + # block. So, if available, use this one instead. Read the mod_ssl User + # Manual for more details. + # + SSLRandomSeed startup builtin + SSLRandomSeed startup file:/dev/urandom 512 + SSLRandomSeed connect builtin + SSLRandomSeed connect file:/dev/urandom 512 + + ## + ## SSL Global Context + ## + ## All SSL configuration in this context applies both to + ## the main server and all SSL-enabled virtual hosts. + ## + + # + # Some MIME-types for downloading Certificates and CRLs + # + AddType application/x-x509-ca-cert .crt + AddType application/x-pkcs7-crl .crl + + # Pass Phrase Dialog: + # Configure the pass phrase gathering process. + # The filtering dialog program (`builtin' is a internal + # terminal dialog) has to provide the pass phrase on stdout. + SSLPassPhraseDialog exec:/usr/share/apache2/ask-for-passphrase + + # Inter-Process Session Cache: + # Configure the SSL Session Cache: First the mechanism + # to use and second the expiring timeout (in seconds). + # (The mechanism dbm has known memory leaks and should not be used). + #SSLSessionCache dbm:${APACHE_RUN_DIR}/ssl_scache + SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_scache(512000) + SSLSessionCacheTimeout 300 + + # Semaphore: + # Configure the path to the mutual exclusion semaphore the + # SSL engine uses internally for inter-process synchronization. + # (Disabled by default, the global Mutex directive consolidates by default + # this) + #Mutex file:${APACHE_LOCK_DIR}/ssl_mutex ssl-cache + + + # SSL Cipher Suite: + # List the ciphers that the client is permitted to negotiate. See the + # ciphers(1) man page from the openssl package for list of all available + # options. + # Enable only secure ciphers: + SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5 + + # Speed-optimized SSL Cipher configuration: + # If speed is your main concern (on busy HTTPS servers e.g.), + # you might want to force clients to specific, performance + # optimized ciphers. In this case, prepend those ciphers + # to the SSLCipherSuite list, and enable SSLHonorCipherOrder. + # Caveat: by giving precedence to RC4-SHA and AES128-SHA + # (as in the example below), most connections will no longer + # have perfect forward secrecy - if the server's key is + # compromised, captures of past or future traffic must be + # considered compromised, too. + #SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:MEDIUM:!aNULL:!MD5 + #SSLHonorCipherOrder on + + # The protocols to enable. + # Available values: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2 + # SSL v2 is no longer supported + SSLProtocol all + + # Allow insecure renegotiation with clients which do not yet support the + # secure renegotiation protocol. Default: Off + #SSLInsecureRenegotiation on + + # Whether to forbid non-SNI clients to access name based virtual hosts. + # Default: Off + #SSLStrictSNIVHostCheck On + + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/ssl.load b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/ssl.load new file mode 100644 index 000000000..3d2336ae0 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-available/ssl.load @@ -0,0 +1,2 @@ +# Depends: setenvif mime socache_shmcb +LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/.gitignore b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/authz_svn.load b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/authz_svn.load new file mode 120000 index 000000000..7ac0725dd --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/authz_svn.load @@ -0,0 +1 @@ +../mods-available/authz_svn.load \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav.load b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav.load new file mode 120000 index 000000000..9dcfef6da --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav.load @@ -0,0 +1 @@ +../mods-available/dav.load \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav_svn.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav_svn.conf new file mode 120000 index 000000000..964c7bb0b --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav_svn.conf @@ -0,0 +1 @@ +../mods-available/dav_svn.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav_svn.load b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav_svn.load new file mode 120000 index 000000000..4094e4173 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/mods-enabled/dav_svn.load @@ -0,0 +1 @@ +../mods-available/dav_svn.load \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/ports.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/ports.conf new file mode 100644 index 000000000..5daec58c1 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/ports.conf @@ -0,0 +1,15 @@ +# If you just change the port or add more ports here, you will likely also +# have to change the VirtualHost statement in +# /etc/apache2/sites-enabled/000-default.conf + +Listen 80 + + + Listen 443 + + + + Listen 443 + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/000-default.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/000-default.conf new file mode 100644 index 000000000..2bd4e1fe9 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/000-default.conf @@ -0,0 +1,12 @@ + + + ServerName ip-172-30-0-17 + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/certbot.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/certbot.conf new file mode 100644 index 000000000..b3147a523 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/certbot.conf @@ -0,0 +1,42 @@ + +ServerName certbot.demo +ServerAdmin webmaster@localhost + +DocumentRoot /var/www-certbot-reworld/static/ + +Options FollowSymLinks +AllowOverride None + + +Options Indexes FollowSymLinks MultiViews +AllowOverride None +Order allow,deny +allow from all + + +ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + +AllowOverride None +Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch +Order allow,deny +Allow from all + + +ErrorLog ${APACHE_LOG_DIR}/error.log + +# Possible values include: debug, info, notice, warn, error, crit, +# alert, emerg. +LogLevel warn + +CustomLog ${APACHE_LOG_DIR}/access.log combined + +Alias /doc/ "/usr/share/doc/" + +Options Indexes MultiViews FollowSymLinks +AllowOverride None +Order deny,allow +Deny from all +Allow from 127.0.0.0/255.0.0.0 ::1/128 + + + diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl-port-only.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl-port-only.conf new file mode 100644 index 000000000..849b42e9f --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl-port-only.conf @@ -0,0 +1,36 @@ + + + ServerAdmin webmaster@localhost + + DocumentRoot /var/www/html + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + # A self-signed (snakeoil) certificate can be created by installing + # the ssl-cert package. See + # /usr/share/doc/apache2/README.Debian.gz for more info. + # If both key and certificate are stored in the same file, only the + # SSLCertificateFile directive is needed. + SSLCertificateFile /etc/apache2/certs/certbot-cert_5.pem + SSLCertificateKeyFile /etc/apache2/ssl/key-certbot_15.pem + + + #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire + + SSLOptions +StdEnvVars + + + SSLOptions +StdEnvVars + + + BrowserMatch "MSIE [2-6]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 + # MSIE 7 and newer should be able to use keepalive + BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown + + + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl.conf new file mode 100644 index 000000000..a3025ae8a --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl.conf @@ -0,0 +1,40 @@ + + + ServerAdmin webmaster@localhost + + DocumentRoot /var/www/html + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + # SSL Engine Switch: + # Enable/Disable SSL for this virtual host. + SSLEngine on + + # A self-signed (snakeoil) certificate can be created by installing + # the ssl-cert package. See + # /usr/share/doc/apache2/README.Debian.gz for more info. + # If both key and certificate are stored in the same file, only the + # SSLCertificateFile directive is needed. + SSLCertificateFile /etc/apache2/certs/certbot-cert_5.pem + SSLCertificateKeyFile /etc/apache2/ssl/key-certbot_15.pem + + + #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire + + SSLOptions +StdEnvVars + + + SSLOptions +StdEnvVars + + + BrowserMatch "MSIE [2-6]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 + # MSIE 7 and newer should be able to use keepalive + BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown + + + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/encryption-example.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/encryption-example.conf new file mode 100644 index 000000000..4786bda13 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/encryption-example.conf @@ -0,0 +1,42 @@ + + ServerName encryption-example.demo + ServerAdmin webmaster@localhost + + DocumentRoot /var/www-encryption-example/static/ + + Options FollowSymLinks + AllowOverride None + + + Options Indexes FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + allow from all + + + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + + ErrorLog ${APACHE_LOG_DIR}/error.log + + # Possible values include: debug, info, notice, warn, error, crit, + # alert, emerg. + LogLevel warn + + CustomLog ${APACHE_LOG_DIR}/access.log combined + + Alias /doc/ "/usr/share/doc/" + + Options Indexes MultiViews FollowSymLinks + AllowOverride None + Order deny,allow + Deny from all + Allow from 127.0.0.0/255.0.0.0 ::1/128 + + + diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/mod_macro-example.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/mod_macro-example.conf new file mode 100644 index 000000000..6a6579007 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/mod_macro-example.conf @@ -0,0 +1,15 @@ + + + ServerName $domain + ServerAlias www.$domain + DocumentRoot /var/www/html + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + +Use VHost macro1 test.com +Use VHost macro2 hostname.org +Use VHost macro3 apache.org + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/ocsp-ssl.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/ocsp-ssl.conf new file mode 100644 index 000000000..631cf16c8 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/ocsp-ssl.conf @@ -0,0 +1,36 @@ + +SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000) + + # The ServerName directive sets the request scheme, hostname and port that + # the server uses to identify itself. This is used when creating + # redirection URLs. In the context of virtual hosts, the ServerName + # specifies what hostname must appear in the request's Host: header to + # match this virtual host. For the default virtual host (this file) this + # value is not decisive as it is used as a last resort host regardless. + # However, you must set it for any further virtual host explicitly. + ServerName ocspvhost.com + + ServerAdmin webmaster@dumpbits.com + DocumentRoot /var/www/html + + # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, + # error, crit, alert, emerg. + # It is also possible to configure the loglevel for particular + # modules, e.g. + #LogLevel info ssl:warn + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + # For most configuration files from conf-available/, which are + # enabled or disabled at a global level, it is possible to + # include a line for only one particular virtual host. For example the + # following line enables the CGI configuration for this host only + # after it has been globally disabled with "a2disconf". + #Include conf-available/serve-cgi-bin.conf +SSLCertificateFile /etc/apache2/certs/certbot-cert_5.pem +SSLCertificateKeyFile /etc/apache2/ssl/key-certbot_15.pem +SSLUseStapling on + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet + diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/old,default.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/old,default.conf new file mode 100644 index 000000000..2bd4e1fe9 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/old,default.conf @@ -0,0 +1,12 @@ + + + ServerName ip-172-30-0-17 + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/wildcard.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/wildcard.conf new file mode 100644 index 000000000..33e30a63b --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/wildcard.conf @@ -0,0 +1,13 @@ + + + ServerName ip-172-30-0-17 + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html + ServerAlias *.blue.purple.com + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/000-default.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/000-default.conf new file mode 120000 index 000000000..3c4632b73 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/000-default.conf @@ -0,0 +1 @@ +../sites-available/000-default.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/certbot.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/certbot.conf new file mode 120000 index 000000000..4d08c763f --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/certbot.conf @@ -0,0 +1 @@ +../sites-available/certbot.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/encryption-example.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/encryption-example.conf new file mode 120000 index 000000000..417818069 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/encryption-example.conf @@ -0,0 +1 @@ +../sites-available/encryption-example.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/mod_macro-example.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/mod_macro-example.conf new file mode 120000 index 000000000..44f254304 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/mod_macro-example.conf @@ -0,0 +1 @@ +../sites-available/mod_macro-example.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/ocsp-ssl.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/ocsp-ssl.conf new file mode 120000 index 000000000..b25ee0482 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/ocsp-ssl.conf @@ -0,0 +1 @@ +../sites-available/ocsp-ssl.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/sites b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/sites new file mode 100644 index 000000000..ab518ee5b --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/sites @@ -0,0 +1,3 @@ +sites-available/certbot.conf, certbot.demo +sites-available/encryption-example.conf, encryption-example.demo +sites-available/ocsp-ssl.conf, ocspvhost.com From a9679e2c25f81e3263a476978c931ce4431797c9 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Tue, 28 Jun 2016 18:08:38 -0700 Subject: [PATCH 149/264] create regression test --- .../certbot_apache/tests/configurator_test.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index ae56002b8..0d3e7e08f 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -1196,29 +1196,24 @@ class AugeasVhostsTest(util.ApacheTest): self.config = util.get_apache_configurator( self.config_path, self.vhost_path, self.config_dir, self.work_dir) - self.config = self.mock_deploy_cert(self.config) self.vh_truth = util.get_vh_truth( self.temp_dir, "debian_apache_2_4/augeas_vhosts") - def mock_deploy_cert(self, config): - """A test for a mock deploy cert""" - self.config.real_deploy_cert = self.config.deploy_cert - - def mocked_deploy_cert(*args, **kwargs): - """a helper to mock a deployed cert""" - with mock.patch("certbot_apache.configurator.ApacheConfigurator.enable_mod"): - config.real_deploy_cert(*args, **kwargs) - self.config.deploy_cert = mocked_deploy_cert - return self.config - def tearDown(self): shutil.rmtree(self.temp_dir) shutil.rmtree(self.config_dir) shutil.rmtree(self.work_dir) def test_choosevhost_with_illegal_name(self): + self.config.aug = mock.MagicMock() + self.config.aug.match.side_effect = RuntimeError chosen_vhost = self.config._create_vhost("debian_apache_2_4/augeas_vhosts/apache2/sites-available/old,default.conf") self.assertEqual(None, chosen_vhost) + def test_choosevhost_works(self): + path = "debian_apache_2_4/augeas_vhosts/apache2/sites-available/old,default.conf" + chosen_vhost = self.config._create_vhost(path) + self.assertTrue(chosen_vhost == None or chosen_vhost.path == path) + if __name__ == "__main__": unittest.main() # pragma: no cover From 395843f3f409ae654766d7ef18243b957ea7de87 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Wed, 29 Jun 2016 11:06:18 -0700 Subject: [PATCH 150/264] fix coverage --- .../certbot_apache/tests/configurator_test.py | 6 +++ .../apache2/sites-available/000-default.conf | 12 ------ .../apache2/sites-available/certbot.conf | 42 ------------------- .../default-ssl-port-only.conf | 36 ---------------- .../apache2/sites-available/default-ssl.conf | 40 ------------------ .../sites-available/encryption-example.conf | 42 ------------------- .../sites-available/mod_macro-example.conf | 15 ------- .../apache2/sites-available/ocsp-ssl.conf | 36 ---------------- .../apache2/sites-available/wildcard.conf | 13 ------ .../apache2/sites-available/old,default.conf | 12 ------ 10 files changed, 6 insertions(+), 248 deletions(-) delete mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/000-default.conf delete mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/certbot.conf delete mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl-port-only.conf delete mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl.conf delete mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/encryption-example.conf delete mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/mod_macro-example.conf delete mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/ocsp-ssl.conf delete mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/wildcard.conf delete mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/old,default.conf diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index 0d3e7e08f..5de979834 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -1215,5 +1215,11 @@ class AugeasVhostsTest(util.ApacheTest): chosen_vhost = self.config._create_vhost(path) self.assertTrue(chosen_vhost == None or chosen_vhost.path == path) + @mock.patch("certbot_apache.configurator.ApacheConfigurator._create_vhost") + def test_get_vhost_continue(self, mock_vhost): + mock_vhost.return_value = None + vhs = self.config.get_virtual_hosts() + self.assertEqual([], vhs) + if __name__ == "__main__": unittest.main() # pragma: no cover diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/000-default.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/000-default.conf deleted file mode 100644 index 2bd4e1fe9..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/000-default.conf +++ /dev/null @@ -1,12 +0,0 @@ - - - ServerName ip-172-30-0-17 - ServerAdmin webmaster@localhost - DocumentRoot /var/www/html - - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/certbot.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/certbot.conf deleted file mode 100644 index b3147a523..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/certbot.conf +++ /dev/null @@ -1,42 +0,0 @@ - -ServerName certbot.demo -ServerAdmin webmaster@localhost - -DocumentRoot /var/www-certbot-reworld/static/ - -Options FollowSymLinks -AllowOverride None - - -Options Indexes FollowSymLinks MultiViews -AllowOverride None -Order allow,deny -allow from all - - -ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ - -AllowOverride None -Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch -Order allow,deny -Allow from all - - -ErrorLog ${APACHE_LOG_DIR}/error.log - -# Possible values include: debug, info, notice, warn, error, crit, -# alert, emerg. -LogLevel warn - -CustomLog ${APACHE_LOG_DIR}/access.log combined - -Alias /doc/ "/usr/share/doc/" - -Options Indexes MultiViews FollowSymLinks -AllowOverride None -Order deny,allow -Deny from all -Allow from 127.0.0.0/255.0.0.0 ::1/128 - - - diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl-port-only.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl-port-only.conf deleted file mode 100644 index 849b42e9f..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl-port-only.conf +++ /dev/null @@ -1,36 +0,0 @@ - - - ServerAdmin webmaster@localhost - - DocumentRoot /var/www/html - - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - # A self-signed (snakeoil) certificate can be created by installing - # the ssl-cert package. See - # /usr/share/doc/apache2/README.Debian.gz for more info. - # If both key and certificate are stored in the same file, only the - # SSLCertificateFile directive is needed. - SSLCertificateFile /etc/apache2/certs/certbot-cert_5.pem - SSLCertificateKeyFile /etc/apache2/ssl/key-certbot_15.pem - - - #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire - - SSLOptions +StdEnvVars - - - SSLOptions +StdEnvVars - - - BrowserMatch "MSIE [2-6]" \ - nokeepalive ssl-unclean-shutdown \ - downgrade-1.0 force-response-1.0 - # MSIE 7 and newer should be able to use keepalive - BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown - - - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl.conf deleted file mode 100644 index a3025ae8a..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/default-ssl.conf +++ /dev/null @@ -1,40 +0,0 @@ - - - ServerAdmin webmaster@localhost - - DocumentRoot /var/www/html - - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - # SSL Engine Switch: - # Enable/Disable SSL for this virtual host. - SSLEngine on - - # A self-signed (snakeoil) certificate can be created by installing - # the ssl-cert package. See - # /usr/share/doc/apache2/README.Debian.gz for more info. - # If both key and certificate are stored in the same file, only the - # SSLCertificateFile directive is needed. - SSLCertificateFile /etc/apache2/certs/certbot-cert_5.pem - SSLCertificateKeyFile /etc/apache2/ssl/key-certbot_15.pem - - - #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire - - SSLOptions +StdEnvVars - - - SSLOptions +StdEnvVars - - - BrowserMatch "MSIE [2-6]" \ - nokeepalive ssl-unclean-shutdown \ - downgrade-1.0 force-response-1.0 - # MSIE 7 and newer should be able to use keepalive - BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown - - - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/encryption-example.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/encryption-example.conf deleted file mode 100644 index 4786bda13..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/encryption-example.conf +++ /dev/null @@ -1,42 +0,0 @@ - - ServerName encryption-example.demo - ServerAdmin webmaster@localhost - - DocumentRoot /var/www-encryption-example/static/ - - Options FollowSymLinks - AllowOverride None - - - Options Indexes FollowSymLinks MultiViews - AllowOverride None - Order allow,deny - allow from all - - - ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ - - AllowOverride None - Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch - Order allow,deny - Allow from all - - - ErrorLog ${APACHE_LOG_DIR}/error.log - - # Possible values include: debug, info, notice, warn, error, crit, - # alert, emerg. - LogLevel warn - - CustomLog ${APACHE_LOG_DIR}/access.log combined - - Alias /doc/ "/usr/share/doc/" - - Options Indexes MultiViews FollowSymLinks - AllowOverride None - Order deny,allow - Deny from all - Allow from 127.0.0.0/255.0.0.0 ::1/128 - - - diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/mod_macro-example.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/mod_macro-example.conf deleted file mode 100644 index 6a6579007..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/mod_macro-example.conf +++ /dev/null @@ -1,15 +0,0 @@ - - - ServerName $domain - ServerAlias www.$domain - DocumentRoot /var/www/html - - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - -Use VHost macro1 test.com -Use VHost macro2 hostname.org -Use VHost macro3 apache.org - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/ocsp-ssl.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/ocsp-ssl.conf deleted file mode 100644 index 631cf16c8..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/ocsp-ssl.conf +++ /dev/null @@ -1,36 +0,0 @@ - -SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000) - - # The ServerName directive sets the request scheme, hostname and port that - # the server uses to identify itself. This is used when creating - # redirection URLs. In the context of virtual hosts, the ServerName - # specifies what hostname must appear in the request's Host: header to - # match this virtual host. For the default virtual host (this file) this - # value is not decisive as it is used as a last resort host regardless. - # However, you must set it for any further virtual host explicitly. - ServerName ocspvhost.com - - ServerAdmin webmaster@dumpbits.com - DocumentRoot /var/www/html - - # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, - # error, crit, alert, emerg. - # It is also possible to configure the loglevel for particular - # modules, e.g. - #LogLevel info ssl:warn - - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - # For most configuration files from conf-available/, which are - # enabled or disabled at a global level, it is possible to - # include a line for only one particular virtual host. For example the - # following line enables the CGI configuration for this host only - # after it has been globally disabled with "a2disconf". - #Include conf-available/serve-cgi-bin.conf -SSLCertificateFile /etc/apache2/certs/certbot-cert_5.pem -SSLCertificateKeyFile /etc/apache2/ssl/key-certbot_15.pem -SSLUseStapling on - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet - diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/wildcard.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/wildcard.conf deleted file mode 100644 index 33e30a63b..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-available/wildcard.conf +++ /dev/null @@ -1,13 +0,0 @@ - - - ServerName ip-172-30-0-17 - ServerAdmin webmaster@localhost - DocumentRoot /var/www/html - ServerAlias *.blue.purple.com - - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/old,default.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/old,default.conf deleted file mode 100644 index 2bd4e1fe9..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/old,default.conf +++ /dev/null @@ -1,12 +0,0 @@ - - - ServerName ip-172-30-0-17 - ServerAdmin webmaster@localhost - DocumentRoot /var/www/html - - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet From b64da855a2bf0c482ddff53ef508b7bba1bbdb30 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Wed, 29 Jun 2016 11:55:22 -0700 Subject: [PATCH 151/264] lint --- .../certbot_apache/tests/configurator_test.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index 5de979834..a90940f94 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -1,4 +1,4 @@ -# pylint: disable=too-many-public-methods +# pylint: disable=too-many-public-methods, protected-access """Test for certbot_apache.configurator.""" import os import shutil @@ -1190,9 +1190,12 @@ class AugeasVhostsTest(util.ApacheTest): """Test vhosts with illegal names dependant on augeas version.""" def setUp(self): # pylint: disable=arguments-differ - super(AugeasVhostsTest, self).setUp(test_dir="debian_apache_2_4/augeas_vhosts", - config_root="debian_apache_2_4/augeas_vhosts/apache2", - vhost_root="debian_apache_2_4/augeas_vhosts/apache2/sites-available") + td = "debian_apache_2_4/augeas_vhosts" + cr = "debian_apache_2_4/augeas_vhosts/apache2" + vr = "debian_apache_2_4/augeas_vhosts/apache2/sites-available" + super(AugeasVhostsTest, self).setUp(test_dir=td, + config_root=cr, + vhost_root=vr) self.config = util.get_apache_configurator( self.config_path, self.vhost_path, self.config_dir, self.work_dir) @@ -1207,7 +1210,8 @@ class AugeasVhostsTest(util.ApacheTest): def test_choosevhost_with_illegal_name(self): self.config.aug = mock.MagicMock() self.config.aug.match.side_effect = RuntimeError - chosen_vhost = self.config._create_vhost("debian_apache_2_4/augeas_vhosts/apache2/sites-available/old,default.conf") + path = "debian_apache_2_4/augeas_vhosts/apache2/sites-available/old,default.conf" + chosen_vhost = self.config._create_vhost(path) self.assertEqual(None, chosen_vhost) def test_choosevhost_works(self): From 7b50960ac0559e4f2e9fea20a72470127b264515 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 29 Jun 2016 13:57:58 -0700 Subject: [PATCH 152/264] Address review comments --- certbot-apache/certbot_apache/configurator.py | 2 +- certbot-apache/certbot_apache/obj.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index c51778ce5..89d602f5f 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -328,7 +328,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if vhost is None: logger.error( "No vhost exists with servername or alias of: %s " - "(or it's in a file with multiple files, which Certbot " + "(or it's in a file with multiple vhosts, which Certbot " "can't parse yet). " "No vhost was selected. Please specify ServerName or ServerAlias " "in the Apache config, or split vhosts into separate files.", diff --git a/certbot-apache/certbot_apache/obj.py b/certbot-apache/certbot_apache/obj.py index c1af352cb..c71443e92 100644 --- a/certbot-apache/certbot_apache/obj.py +++ b/certbot-apache/certbot_apache/obj.py @@ -19,12 +19,12 @@ class Addr(common.Addr): self.is_wildcard() and other.is_wildcard())) return False - def __repr__(self): - return "certbot_apache.obj.Addr(" + repr(self.tup) + ")" - def __ne__(self, other): return not self.__eq__(other) + def __repr__(self): + return "certbot_apache.obj.Addr(" + repr(self.tup) + ")" + def _addr_less_specific(self, addr): """Returns if addr.get_addr() is more specific than self.get_addr().""" # pylint: disable=protected-access From a70cf6fcf80c3c3322033d0f69f0802df91a4c9f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 29 Jun 2016 15:22:19 -0700 Subject: [PATCH 153/264] Use correct port name --- docs/using.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index 4e49c3eb5..fb96bb853 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -428,7 +428,7 @@ Operating System Packages **FreeBSD** - * Port: ``cd /usr/ports/security/py-letsencrypt && make install clean`` + * Port: ``cd /usr/ports/security/py-certbot && make install clean`` * Package: ``pkg install py27-letsencrypt`` **OpenBSD** From 92870f0bbb2a912b16f77079243efeb4e5293bef Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Thu, 30 Jun 2016 10:22:12 -0500 Subject: [PATCH 154/264] Better docstring for _signal_handler --- certbot/error_handler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index 5b9220583..42861b4a1 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -112,7 +112,8 @@ class ErrorHandler(object): self.prev_handlers.clear() def _signal_handler(self, signum, unused_frame): - """Stores the recieved signal. + """Stores the recieved signal. If we are executing the code block in + the body of the context manager, stop by raising signal exit. :param int signum: number of current signal From 8c3e443de9d26d0e722956107db8a36134c0134c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 30 Jun 2016 15:07:28 -0700 Subject: [PATCH 155/264] First attempt at mitigating #3206 --- certbot-nginx/certbot_nginx/nginxparser.py | 31 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index d6c352296..895c4f8a3 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -38,19 +38,42 @@ class RawNginxParser(object): assignment = space + key + Optional(space + value, default=None) + semicolon location_statement = space + Optional(modifier) + Optional(space + location + space) if_statement = space + Literal("if") + space + condition + space + map_statement = space + Literal("map") + space + nonspace + space + dollar_var + space + + # This is NOT an accurate way to parse nginx map entries; it's almost + # certianly too permissive and may be wrong in other ways, but it should + # preserve things correctly in mmmmost or all cases. + # - it sometimes splits the two tokens incorrectly eg + # '''"~Opera Mini" 1''' -> ['"~Opera', ' Mini" 1'] + # - I can neither prove nor disprove that it is corect wrt all escaped + # semicolon situations + # Addresses https://github.com/fatiherikli/nginxparser/issues/19 + + map_entry = space + nonspace + value + space + semicolon + map_block = Forward() + map_block << Group( + # key could for instance be "server" or "http", or "location" (in which case + # location_statement needs to have a non-empty location) + Group(map_statement).leaveWhitespace() + + left_bracket + + Group(ZeroOrMore(Group(comment | map_entry)) + space).leaveWhitespace() + + right_bracket) + + block = Forward() block << Group( # key could for instance be "server" or "http", or "location" (in which case # location_statement needs to have a non-empty location) - (Group(space + key + location_statement) ^ Group(if_statement) ^ - Group(map_statement)).leaveWhitespace() + + (Group(space + key + location_statement) ^ Group(if_statement)).leaveWhitespace() + left_bracket + - Group(ZeroOrMore(Group(comment | assignment) | block) + space).leaveWhitespace() + + Group(ZeroOrMore(Group(comment | assignment) | block | map_block) + space).leaveWhitespace() + right_bracket) - script = OneOrMore(Group(comment | assignment) ^ block) + space + stringEnd + + + script = OneOrMore(Group(comment | assignment) ^ block ^ map_block) + space + stringEnd script.parseWithTabs() def __init__(self, source): From db8ddac4e252780fb4015298b7cbe0388d340f10 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 30 Jun 2016 15:13:35 -0700 Subject: [PATCH 156/264] lint & tweak --- certbot-nginx/certbot_nginx/nginxparser.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 895c4f8a3..50ed41eb9 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -40,7 +40,6 @@ class RawNginxParser(object): if_statement = space + Literal("if") + space + condition + space map_statement = space + Literal("map") + space + nonspace + space + dollar_var + space - # This is NOT an accurate way to parse nginx map entries; it's almost # certianly too permissive and may be wrong in other ways, but it should # preserve things correctly in mmmmost or all cases. @@ -49,7 +48,6 @@ class RawNginxParser(object): # - I can neither prove nor disprove that it is corect wrt all escaped # semicolon situations # Addresses https://github.com/fatiherikli/nginxparser/issues/19 - map_entry = space + nonspace + value + space + semicolon map_block = Forward() map_block << Group( @@ -60,18 +58,14 @@ class RawNginxParser(object): Group(ZeroOrMore(Group(comment | map_entry)) + space).leaveWhitespace() + right_bracket) - block = Forward() - block << Group( # key could for instance be "server" or "http", or "location" (in which case # location_statement needs to have a non-empty location) (Group(space + key + location_statement) ^ Group(if_statement)).leaveWhitespace() + left_bracket + - Group(ZeroOrMore(Group(comment | assignment) | block | map_block) + space).leaveWhitespace() + - right_bracket) - - + Group(ZeroOrMore(Group(comment | assignment) | block | map_block) + space).leaveWhitespace() + + right_bracket) script = OneOrMore(Group(comment | assignment) ^ block ^ map_block) + space + stringEnd script.parseWithTabs() From be8f0bc53b657fdf3a104c355858c396f96eb6a0 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 30 Jun 2016 15:29:38 -0700 Subject: [PATCH 157/264] Do a better job of parsing map patterns --- certbot-nginx/certbot_nginx/nginxparser.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 50ed41eb9..0cc912515 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -27,6 +27,8 @@ class RawNginxParser(object): condition = Regex(r"\(.+\)") # Matches anything that is not a special character AND any chars in single # or double quotes + # All of these COULD be upgraded to something like + # https://stackoverflow.com/a/16130746 value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+") location = CharsNotIn("{};," + string.whitespace) # modifier for location uri [ = | ~ | ~* | ^~ ] @@ -43,14 +45,13 @@ class RawNginxParser(object): # This is NOT an accurate way to parse nginx map entries; it's almost # certianly too permissive and may be wrong in other ways, but it should # preserve things correctly in mmmmost or all cases. - # - it sometimes splits the two tokens incorrectly eg - # '''"~Opera Mini" 1''' -> ['"~Opera', ' Mini" 1'] + # # - I can neither prove nor disprove that it is corect wrt all escaped # semicolon situations # Addresses https://github.com/fatiherikli/nginxparser/issues/19 - map_entry = space + nonspace + value + space + semicolon - map_block = Forward() - map_block << Group( + map_pattern = Regex(r'".*"') | Regex(r"'.*'") | nonspace + map_entry = space + map_pattern + space + value + space + semicolon + map_block = Group( # key could for instance be "server" or "http", or "location" (in which case # location_statement needs to have a non-empty location) Group(map_statement).leaveWhitespace() + From a9abc7b39e89ee26c116244e528d49931f922252 Mon Sep 17 00:00:00 2001 From: sagi Date: Fri, 1 Jul 2016 15:17:37 +0000 Subject: [PATCH 158/264] typo --- certbot-apache/certbot_apache/configurator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 89d602f5f..fdc0f37d8 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -874,7 +874,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if self._sift_line(line): if not sift: new_file.write( - "# Some rewrite rules in this file were " + "# Some rewrite rules in this file " "were disabled on your HTTPS site,\n" "# because they have the potential to " "create redirection loops.\n") From 15ba12ed4647990d8e72f244a682c00327493443 Mon Sep 17 00:00:00 2001 From: sagi Date: Fri, 1 Jul 2016 21:06:16 +0000 Subject: [PATCH 159/264] Parsing State Machine + some tests --- certbot-apache/certbot_apache/configurator.py | 64 ++++++++++++++++--- .../certbot_apache/tests/configurator_test.py | 11 ++-- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index fdc0f37d8..23c7a0c29 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -819,7 +819,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): else: return non_ssl_vh_fp + self.conf("le_vhost_ext") - def _sift_line(self, line): + def _sift_rewrite_rule(self, line): """Decides whether a line should be copied to a SSL vhost. A canonical example of when sifting a line is required: @@ -861,7 +861,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): A new file is created on the filesystem. """ - # First register the creation so that it is properly removed if + # First register the creation so thatu it is properly removed if # configuration is rolled back self.reverter.register_file_creation(False, ssl_fp) sift = False @@ -870,18 +870,62 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): with open(avail_fp, "r") as orig_file: with open(ssl_fp, "w") as new_file: new_file.write("\n") + + comment = ("# Some rewrite rules in this file were " + "disabled on your HTTPS site,\n" + "# because they have the potential to create " + "redirection loops.\n") + for line in orig_file: - if self._sift_line(line): + A = line.lstrip().startswith("RewriteCond") + B = line.lstrip().startswith("RewriteRule") + + if not (A or B): + new_file.write(line) + continue + + # A RewriteRule that doesn't need filtering + if B and not self._sift_rewrite_rule(line): + new_file.write(line) + continue + + # A RewriteRule that does need filtering + if B and self._sift_rewrite_rule(line): if not sift: - new_file.write( - "# Some rewrite rules in this file " - "were disabled on your HTTPS site,\n" - "# because they have the potential to " - "create redirection loops.\n") + new_file.write(comment) sift = True new_file.write("# " + line) - else: - new_file.write(line) + continue + + # We save RewriteCond(s) and their corresponding + # RewriteRule in 'chunk'. + # We then decide whether we comment out the entire + # chunk based on its RewriteRule. + chunk = [] + if A: + chunk.append(line) + line = next(orig_file) + + # RewriteCond(s) must be followed by one RewriteRule + while not line.lstrip().startswith("RewriteRule"): + chunk.append(line) + line = next(orig_file) + + # Now, current line must start with a RewriteRule + chunk.append(line) + + if self._sift_rewrite_rule(line): + if not sift: + new_file.write(comment) + sift = True + + new_file.write(''.join( + ['# ' + l for l in chunk])) + continue + else: + new_file.write(''.join(chunk)) + continue + new_file.write("\n") except IOError: logger.fatal("Error writing/reading to file in make_vhost_ssl") diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index 9a034c3e0..5a8684c9a 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -1110,16 +1110,19 @@ class MultipleVhostsTest(util.ApacheTest): self.config._enable_redirect(self.vh_truth[1], "") self.assertEqual(len(self.config.vhosts), 9) - def test_sift_line(self): + def test_sift_rewrite_rule(self): # pylint: disable=protected-access small_quoted_target = "RewriteRule ^ \"http://\"" - self.assertFalse(self.config._sift_line(small_quoted_target)) + self.assertFalse(self.config._sift_rewrite_rule(small_quoted_target)) https_target = "RewriteRule ^ https://satoshi" - self.assertTrue(self.config._sift_line(https_target)) + self.assertTrue(self.config._sift_rewrite_rule(https_target)) normal_target = "RewriteRule ^/(.*) http://www.a.com:1234/$1 [L,R]" - self.assertFalse(self.config._sift_line(normal_target)) + self.assertFalse(self.config._sift_rewrite_rule(normal_target)) + + not_rewriterule = "NotRewriteRule ^ ..." + self.assertFalse(self.config._sift_rewrite_rule(not_rewriterule)) @mock.patch("certbot_apache.configurator.zope.component.getUtility") def test_make_vhost_ssl_with_existing_rewrite_rule(self, mock_get_utility): From 74593607803e67818ab23b0e3f7a772ee99bc417 Mon Sep 17 00:00:00 2001 From: sagi Date: Fri, 1 Jul 2016 22:08:37 +0000 Subject: [PATCH 160/264] Add more test cases --- .../certbot_apache/tests/configurator_test.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index 5a8684c9a..57c6a8009 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -1151,7 +1151,61 @@ class MultipleVhostsTest(util.ApacheTest): "[L,QSA,R=permanent]") self.assertTrue(commented_rewrite_rule in conf_text) mock_get_utility().add_message.assert_called_once_with(mock.ANY, + mock.ANY) + @mock.patch("certbot_apache.configurator.zope.component.getUtility") + def test_make_vhost_ssl_with_existing_rewrite_conds(self, mock_get_utility): + self.config.parser.modules.add("rewrite_module") + + http_vhost = self.vh_truth[0] + + self.config.parser.add_dir( + http_vhost.path, "RewriteEngine", "on") + + # Add a chunk that should not be commented out. + self.config.parser.add_dir(http_vhost.path, + "RewriteCond", ["%{DOCUMENT_ROOT}/%{REQUEST_FILENAME}", "!-f"]) + self.config.parser.add_dir( + http_vhost.path, "RewriteRule", + ["^(.*)$", "b://u%{REQUEST_URI}", "[P,QSA,L]"]) + + # Add a chunk that should be commented out. + self.config.parser.add_dir(http_vhost.path, + "RewriteCond", ["%{HTTPS}", "!=on"]) + self.config.parser.add_dir(http_vhost.path, + "RewriteCond", ["%{HTTPS}", "!^$"]) + self.config.parser.add_dir( + http_vhost.path, "RewriteRule", + ["^", + "https://%{SERVER_NAME}%{REQUEST_URI}", + "[L,QSA,R=permanent]"]) + + self.config.save() + + ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0]) + + conf_line_set = set(open(ssl_vhost.filep).read().splitlines()) + + not_commented_cond1 = ("RewriteCond " + "%{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f") + not_commented_rewrite_rule = ("RewriteRule " + "^(.*)$ b://u%{REQUEST_URI} [P,QSA,L]") + + commented_cond1 = "# RewriteCond %{HTTPS} !=on" + commented_cond2 = "# RewriteCond %{HTTPS} !^$" + commented_rewrite_rule = ("# RewriteRule ^ " + "https://%{SERVER_NAME}%{REQUEST_URI} " + "[L,QSA,R=permanent]") + + self.assertTrue(not_commented_cond1 in conf_line_set) + self.assertTrue(not_commented_rewrite_rule in conf_line_set) + + self.assertTrue(commented_cond1 in conf_line_set) + self.assertTrue(commented_cond2 in conf_line_set) + self.assertTrue(commented_rewrite_rule in conf_line_set) + mock_get_utility().add_message.assert_called_once_with(mock.ANY, + mock.ANY) + def get_achalls(self): """Return testing achallenges.""" From 0e9622322a89f8efbeb149d4ccf8cb33ddc19660 Mon Sep 17 00:00:00 2001 From: sagi Date: Fri, 1 Jul 2016 22:17:41 +0000 Subject: [PATCH 161/264] typo --- certbot-apache/certbot_apache/configurator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 23c7a0c29..0a24759dc 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -861,7 +861,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): A new file is created on the filesystem. """ - # First register the creation so thatu it is properly removed if + # First register the creation so that it is properly removed if # configuration is rolled back self.reverter.register_file_creation(False, ssl_fp) sift = False From 2cd4f6f008a9762db08f053084cbabd2d53c7384 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 5 Jul 2016 14:14:31 -0700 Subject: [PATCH 162/264] update FreeBSD package name --- docs/using.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index fb96bb853..806dfb340 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -429,7 +429,7 @@ Operating System Packages **FreeBSD** * Port: ``cd /usr/ports/security/py-certbot && make install clean`` - * Package: ``pkg install py27-letsencrypt`` + * Package: ``pkg install py27-certbot`` **OpenBSD** From 777a654d90ec347231c81c7e6c6135e77f58fce6 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 23:13:16 -0500 Subject: [PATCH 163/264] Move SignalExit to errors.py --- certbot/error_handler.py | 13 +++---------- certbot/errors.py | 4 ++++ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index 42861b4a1..45d37f847 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -5,6 +5,7 @@ import os import signal import traceback +from certbot import errors logger = logging.getLogger(__name__) @@ -19,14 +20,6 @@ _SIGNALS = ([signal.SIGTERM] if os.name == "nt" else signal.SIGXCPU, signal.SIGXFSZ]) -class SignalExit(Exception): - """This exception is used stop of execution of the code in the body of the - ErrorHandler context manager. - - """ - pass - - class ErrorHandler(object): """Registers functions to be called if an exception or signal occurs. @@ -62,7 +55,7 @@ class ErrorHandler(object): def __exit__(self, exec_type, exec_value, trace): self.body_executed = True retval = False - if exec_type is SignalExit: + if exec_type is errors.SignalExit: logger.debug("Encountered signals: %s", self.received_signals) self.call_registered() for signum in self.received_signals: @@ -120,7 +113,7 @@ class ErrorHandler(object): """ self.received_signals.append(signum) if not self.body_executed: - raise SignalExit + raise errors.SignalExit def call_signal(self, signum): """Calls the signal given by signum. diff --git a/certbot/errors.py b/certbot/errors.py index 1553b6317..738b7536b 100644 --- a/certbot/errors.py +++ b/certbot/errors.py @@ -29,6 +29,10 @@ class HookCommandNotFound(Error): """Failed to find a hook command in the PATH.""" +class SignalExit(Error): + """A Unix signal was recieved while in the ErrorHandler context manager.""" + + # Auth Handler Errors class AuthorizationError(Error): """Authorization error.""" From 15336d45bd9f16c9acc1c0662e1c03caf40f7b15 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 23:13:45 -0500 Subject: [PATCH 164/264] Reset self.body_executed in __enter__ --- certbot/error_handler.py | 1 + 1 file changed, 1 insertion(+) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index 45d37f847..a0f9f9143 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -50,6 +50,7 @@ class ErrorHandler(object): self.register(func, *args, **kwargs) def __enter__(self): + self.body_executed = False self.set_signal_handlers() def __exit__(self, exec_type, exec_value, trace): From 79c602ffc83bfac8f95a5d1e89464dd68c2af16a Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 21:30:22 -0500 Subject: [PATCH 165/264] Make non-public methods as private. --- certbot/error_handler.py | 18 +++++++++--------- certbot/tests/error_handler_test.py | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index a0f9f9143..10e956e13 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -51,24 +51,24 @@ class ErrorHandler(object): def __enter__(self): self.body_executed = False - self.set_signal_handlers() + self._set_signal_handlers() def __exit__(self, exec_type, exec_value, trace): self.body_executed = True retval = False if exec_type is errors.SignalExit: logger.debug("Encountered signals: %s", self.received_signals) - self.call_registered() + self._call_registered() for signum in self.received_signals: - self.call_signal(signum) + self._call_signal(signum) retval = True # SystemExit is ignored to properly handle forks that don't exec elif exec_type not in (None, SystemExit): logger.debug("Encountered exception:\n%s", "".join( traceback.format_exception(exec_type, exec_value, trace))) - self.call_registered() + self._call_registered() - self.reset_signal_handlers() + self._reset_signal_handlers() return retval def register(self, func, *args, **kwargs): @@ -79,7 +79,7 @@ class ErrorHandler(object): """ self.funcs.append(functools.partial(func, *args, **kwargs)) - def call_registered(self): + def _call_registered(self): """Calls all registered functions""" logger.debug("Calling registered functions") while self.funcs: @@ -90,7 +90,7 @@ class ErrorHandler(object): logger.exception(error) self.funcs.pop() - def set_signal_handlers(self): + def _set_signal_handlers(self): """Sets signal handlers for signals in _SIGNALS.""" for signum in _SIGNALS: prev_handler = signal.getsignal(signum) @@ -99,7 +99,7 @@ class ErrorHandler(object): self.prev_handlers[signum] = prev_handler signal.signal(signum, self._signal_handler) - def reset_signal_handlers(self): + def _reset_signal_handlers(self): """Resets signal handlers for signals in _SIGNALS.""" for signum in self.prev_handlers: signal.signal(signum, self.prev_handlers[signum]) @@ -116,7 +116,7 @@ class ErrorHandler(object): if not self.body_executed: raise errors.SignalExit - def call_signal(self, signum): + def _call_signal(self, signum): """Calls the signal given by signum. :param int signum: signal number diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index f8ac0718b..a7906c5ef 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -68,7 +68,7 @@ class ErrorHandlerTest(unittest.TestCase): def test_bad_recovery(self): bad_func = mock.MagicMock(side_effect=[ValueError]) self.handler.register(bad_func) - self.handler.call_registered() + self.handler._call_registered() self.init_func.assert_called_once_with(*self.init_args, **self.init_kwargs) bad_func.assert_called_once_with() From 277b7a89f10a5cfa8b216db77d0d522d1fe8fc94 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 21:59:00 -0500 Subject: [PATCH 166/264] Update ErrorHandler docstring. --- certbot/error_handler.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index 10e956e13..f3226de9d 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -21,19 +21,26 @@ _SIGNALS = ([signal.SIGTERM] if os.name == "nt" else class ErrorHandler(object): - """Registers functions to be called if an exception or signal occurs. + """Context manager for running code that must be cleaned up on failure. - This class allows you to register functions that will be called when - an exception (excluding SystemExit) or signal is encountered. The - class works best as a context manager. For example: + The context manager allows you to register functions that will be called + when an exception (excluding SystemExit) or signal is encountered. Usage: - with ErrorHandler(cleanup_func): + handler = ErrorHandler(cleanup1_func, *cleanup1_args, **cleanup1_kwargs) + handler.register(cleanup2_func, *cleanup2_args, **cleanup2_kwargs) + + with handler: do_something() - If an exception is raised out of do_something, cleanup_func will be - called. The exception is not caught by the ErrorHandler. Similarly, - if a signal is encountered, cleanup_func is called followed by the - previously registered signal handler. + Or for one cleanup function: + + with ErrorHandler(func, args, kwargs): + do_something() + + If an exception is raised out of do_something, the cleanup functions will + be called in last in first out order. Then the exception is raised. + Similarly, if a signal is encountered, the cleanup functions are called + followed by the previously received signal handler. Each registered cleanup function is called exactly once. If a registered function raises an exception, it is logged and the next function is called. From 815887d4e4167102260f866cc4170abdfe31612b Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 22:44:22 -0500 Subject: [PATCH 167/264] Refactor ErrorHandler.__exit__ also call_signal -> call_signals --- certbot/error_handler.py | 41 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index f3226de9d..20315ded7 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -61,22 +61,24 @@ class ErrorHandler(object): self._set_signal_handlers() def __exit__(self, exec_type, exec_value, trace): - self.body_executed = True - retval = False - if exec_type is errors.SignalExit: - logger.debug("Encountered signals: %s", self.received_signals) - self._call_registered() - for signum in self.received_signals: - self._call_signal(signum) - retval = True - # SystemExit is ignored to properly handle forks that don't exec - elif exec_type not in (None, SystemExit): - logger.debug("Encountered exception:\n%s", "".join( - traceback.format_exception(exec_type, exec_value, trace))) - self._call_registered() + try: + self.body_executed = True + retval = False + # SystemExit is ignored to properly handle forks that don't exec + if exec_type in (None, SystemExit): + return retval + elif exec_type is errors.SignalExit: + logger.debug("Encountered signals: %s", self.received_signals) + retval = True + else: + logger.debug("Encountered exception:\n%s", "".join( + traceback.format_exception(exec_type, exec_value, trace))) - self._reset_signal_handlers() - return retval + self._call_registered() + self._call_signals() + return retval + finally: + self._reset_signal_handlers() def register(self, func, *args, **kwargs): """Sets func to be called with *args and **kwargs during cleanup @@ -123,12 +125,13 @@ class ErrorHandler(object): if not self.body_executed: raise errors.SignalExit - def _call_signal(self, signum): + def _call_signals(self): """Calls the signal given by signum. :param int signum: signal number """ - logger.debug("Calling signal %s", signum) - signal.signal(signum, self.prev_handlers[signum]) - os.kill(os.getpid(), signum) + for signum in self.received_signals: + logger.debug("Calling signal %s", signum) + signal.signal(signum, self.prev_handlers[signum]) + os.kill(os.getpid(), signum) From 5e4f250110366e126e099ab41b1b2f4d6f10d50a Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 22:46:23 -0500 Subject: [PATCH 168/264] Stylize _signal_handler docstring. --- certbot/error_handler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index 20315ded7..779c2d5ca 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -115,7 +115,9 @@ class ErrorHandler(object): self.prev_handlers.clear() def _signal_handler(self, signum, unused_frame): - """Stores the recieved signal. If we are executing the code block in + """Replacement function for handling recieved signals. + + Store the recieved signal. If we are executing the code block in the body of the context manager, stop by raising signal exit. :param int signum: number of current signal From 8333829bbe53d5e20813285e483c8ac9776e984b Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 22:47:42 -0500 Subject: [PATCH 169/264] Check that ErrorHandler raises exception. --- certbot/tests/error_handler_test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index a7906c5ef..0974fe92a 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -46,7 +46,9 @@ class ErrorHandlerTest(unittest.TestCase): with self.handler: raise ValueError except ValueError: - pass + exception_raised = True + + self.assertTrue(exception_raised) self.init_func.assert_called_once_with(*self.init_args, **self.init_kwargs) From 7ade835476d4afca12597fcf54f77bb4c7afca92 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 22:57:13 -0500 Subject: [PATCH 170/264] import module instead of function --- certbot/tests/error_handler_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index 0974fe92a..a81d4a2d1 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -3,12 +3,12 @@ import os import signal import sys import unittest -from contextlib import contextmanager +import contextlib import mock -@contextmanager +@contextlib.contextmanager def signal_receiver(signums): """Context manager to catch signals""" signals = [] From e9f879a443e0f6d037ff9abeb11bd55fdf74a5df Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 22:58:15 -0500 Subject: [PATCH 171/264] Use assertTrue and index in _SIGNALS --- certbot/tests/error_handler_test.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index a81d4a2d1..a242c4cab 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -56,13 +56,13 @@ class ErrorHandlerTest(unittest.TestCase): with signal_receiver(self.signals) as signals_received: with self.handler: should_be_42 = 42 - send_signal(signal.SIGTERM) + send_signal(self.signals[0]) should_be_42 *= 10 # check exectuion stoped when the signal was sent - assert 42 == should_be_42 + self.assertEqual(42, should_be_42) # assert signals were caught - assert [signal.SIGTERM] == signals_received + self.assertEqual([self.signals[0]], signals_received) # assert the error handling function was just called once self.init_func.assert_called_once_with(*self.init_args, **self.init_kwargs) @@ -76,13 +76,14 @@ class ErrorHandlerTest(unittest.TestCase): bad_func.assert_called_once_with() def test_bad_recovery_with_signal(self): - bad_func = mock.MagicMock( - side_effect=lambda: send_signal(signal.SIGHUP)) + sig1 = self.signals[0] + sig2 = self.signals[-1] + bad_func = mock.MagicMock(side_effect=lambda: send_signal(sig1)) self.handler.register(bad_func) with signal_receiver(self.signals) as signals_received: with self.handler: - send_signal(signal.SIGTERM) - assert [signal.SIGTERM, signal.SIGHUP] == signals_received + send_signal(sig2) + self.assertEqual([sig2, sig1], signals_received) self.init_func.assert_called_once_with(*self.init_args, **self.init_kwargs) bad_func.assert_called_once_with() From ece1f6a24d5abfe8991638ef4c5b5dd61ebbdc79 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 5 Jul 2016 23:28:57 -0500 Subject: [PATCH 172/264] Don't use _private functions in tests. --- certbot/tests/error_handler_test.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index a242c4cab..6cbc3c1fe 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -70,7 +70,11 @@ class ErrorHandlerTest(unittest.TestCase): def test_bad_recovery(self): bad_func = mock.MagicMock(side_effect=[ValueError]) self.handler.register(bad_func) - self.handler._call_registered() + try: + with self.handler: + raise ValueError + except ValueError: + pass self.init_func.assert_called_once_with(*self.init_args, **self.init_kwargs) bad_func.assert_called_once_with() From 3d3908c8b31d66e495b0762627962f3f64b08b2e Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Wed, 6 Jul 2016 13:19:03 -0500 Subject: [PATCH 173/264] Update _call_signals docstring. --- certbot/error_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index 779c2d5ca..2140aec4f 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -128,7 +128,7 @@ class ErrorHandler(object): raise errors.SignalExit def _call_signals(self): - """Calls the signal given by signum. + """Finally call the deferred signals. :param int signum: signal number From 40983d67d7b4f1431619086ac0df19ddcf24f363 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Wed, 6 Jul 2016 13:19:58 -0500 Subject: [PATCH 174/264] Alphabetize imports in error_handler_test.py --- certbot/tests/error_handler_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index 6cbc3c1fe..58bc4850c 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -1,9 +1,9 @@ """Tests for certbot.error_handler.""" +import contextlib import os import signal import sys import unittest -import contextlib import mock From fd35a1c724ae2d1501fc64ac6be945fb5c7b8786 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 6 Jul 2016 12:40:24 -0700 Subject: [PATCH 175/264] Explain why Apache [appears] not to be installed Would help debug #3244 --- certbot-apache/certbot_apache/configurator.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 89d602f5f..d1c2b7165 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -157,8 +157,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): raise errors.NoInstallationError("Problem in Augeas installation") # Verify Apache is installed - if not util.exe_exists(constants.os_constant("restart_cmd")[0]): - raise errors.NoInstallationError + restart_cmd = constants.os_constant("restart_cmd")[0] + if not util.exe_exists(restart_cmd): + raise errors.NoInstallationError( + 'Cannot find Apache install ({0} not in PATH)'.format(restart_cmd)) # Make sure configuration is valid self.config_test() From 4b84538c8c9c0bb852eb2874cf38cc144dbd3f0d Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 6 Jul 2016 12:57:16 -0700 Subject: [PATCH 176/264] Address review comments --- certbot/display/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot/display/util.py b/certbot/display/util.py index 4e7d45741..39486b2bd 100644 --- a/certbot/display/util.py +++ b/certbot/display/util.py @@ -72,7 +72,7 @@ def _clean(dialog_result): elif code in (CANCEL, ESC): return (CANCEL, result) else: - logger.info("Surprising dialog return code %s", code) + logger.debug("Surprising dialog return code %s", code) return (CANCEL, result) @@ -83,6 +83,7 @@ class NcursesDisplay(object): def __init__(self, width=WIDTH, height=HEIGHT): super(NcursesDisplay, self).__init__() self.dialog = dialog.Dialog() + assert OK == self.dialog.DIALOG_OK, "What kind of absurdity is this?" self.width = width self.height = height @@ -189,7 +190,6 @@ class NcursesDisplay(object): :rtype: bool """ - assert OK == self.dialog.DIALOG_OK, "What kind of absurdity is this?" return self.dialog.DIALOG_OK == self.dialog.yesno( message, self.height, self.width, yes_label=yes_label, no_label=no_label) From 2e7f02805ce848b8cd4cea8cda944e5fb473c607 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Wed, 6 Jul 2016 15:59:51 -0500 Subject: [PATCH 177/264] Call _call_signals after _reset_signals. --- certbot/error_handler.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index 2140aec4f..e9deaea5c 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -75,10 +75,10 @@ class ErrorHandler(object): traceback.format_exception(exec_type, exec_value, trace))) self._call_registered() - self._call_signals() return retval finally: - self._reset_signal_handlers() + prev_handlers = self._reset_signal_handlers() + self._call_signals(prev_handlers) def register(self, func, *args, **kwargs): """Sets func to be called with *args and **kwargs during cleanup @@ -112,7 +112,9 @@ class ErrorHandler(object): """Resets signal handlers for signals in _SIGNALS.""" for signum in self.prev_handlers: signal.signal(signum, self.prev_handlers[signum]) + out = dict((k, v) for k, v in self.prev_handlers.items()) self.prev_handlers.clear() + return out def _signal_handler(self, signum, unused_frame): """Replacement function for handling recieved signals. @@ -127,7 +129,7 @@ class ErrorHandler(object): if not self.body_executed: raise errors.SignalExit - def _call_signals(self): + def _call_signals(self, prev_handlers): """Finally call the deferred signals. :param int signum: signal number @@ -135,5 +137,5 @@ class ErrorHandler(object): """ for signum in self.received_signals: logger.debug("Calling signal %s", signum) - signal.signal(signum, self.prev_handlers[signum]) + signal.signal(signum, prev_handlers[signum]) os.kill(os.getpid(), signum) From e28560514a8f9c6da979a8fc86d7b8c42544dd64 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Wed, 6 Jul 2016 16:56:11 -0500 Subject: [PATCH 178/264] Test that ErrorHandler resets default signals. --- certbot/tests/error_handler_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index 58bc4850c..a32f2a448 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -66,6 +66,9 @@ class ErrorHandlerTest(unittest.TestCase): # assert the error handling function was just called once self.init_func.assert_called_once_with(*self.init_args, **self.init_kwargs) + for signum in self.signals: + sig = signal.getsignal(signum) + self.assertTrue((sig == signal.SIG_DFL) or (sig == signal.SIG_IGN)) def test_bad_recovery(self): bad_func = mock.MagicMock(side_effect=[ValueError]) From 83857baf30bd6a25ce29612885666a3fdd30abf6 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 6 Jul 2016 13:25:52 -0700 Subject: [PATCH 179/264] Update / cleanup installer error message Closes: #1756 Updating since we landed #788 and have shipped Apache support almost everywhere --- certbot/plugins/selection.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/certbot/plugins/selection.py b/certbot/plugins/selection.py index ac509d779..1d7fa323f 100644 --- a/certbot/plugins/selection.py +++ b/certbot/plugins/selection.py @@ -260,14 +260,9 @@ def diagnose_configurator_problem(cfg_type, requested, plugins): "your existing configuration.\nThe error was: {1!r}" .format(requested, plugins[requested].problem)) elif cfg_type == "installer": - if os.path.exists("/etc/debian_version"): - # Debian... installers are at least possible - msg = ('No installers seem to be present and working on your system; ' - 'fix that or try running certbot with the "certonly" command') - else: - # XXX update this logic as we make progress on #788 and nginx support - msg = ('No installers are available on your OS yet; try running ' - '"letsencrypt-auto certonly" to get a cert you can install manually') + msg = ('No installer plugins seem to be present and working on your system; ' + 'fix that or try running certbot with the "certonly" command to obtain' + ' a certificate you can install manually') else: msg = "{0} could not be determined or is not installed".format(cfg_type) raise errors.PluginSelectionError(msg) From fd35e407ca221e145805cdb88d76dc8b094d4e2d Mon Sep 17 00:00:00 2001 From: Robert Buchholz Date: Thu, 7 Jul 2016 11:20:52 +0200 Subject: [PATCH 180/264] Reference certbot-auto in CLI help --- certbot/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/certbot/cli.py b/certbot/cli.py index 35b3b74ae..470267029 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -721,10 +721,10 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis "(both can be renewed in parallel)") helpful.add( "automation", "--os-packages-only", action="store_true", - help="(letsencrypt-auto only) install OS package dependencies and then stop") + help="(certbot-auto only) install OS package dependencies and then stop") helpful.add( "automation", "--no-self-upgrade", action="store_true", - help="(letsencrypt-auto only) prevent the letsencrypt-auto script from" + help="(certbot-auto only) prevent the certbot-auto script from" " upgrading itself to newer released versions") helpful.add( "automation", "-q", "--quiet", dest="quiet", action="store_true", @@ -737,7 +737,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis "really know what you're doing!") helpful.add( "testing", "--debug", action="store_true", - help="Show tracebacks in case of errors, and allow letsencrypt-auto " + help="Show tracebacks in case of errors, and allow certbot-auto " "execution on experimental platforms") helpful.add( "testing", "--no-verify-ssl", action="store_true", From c92a1cd182f4ad15e40552777648621b08dab486 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 7 Jul 2016 17:24:58 -0700 Subject: [PATCH 181/264] Clarifications to Docker, certbot-auto content reflecting first three questions in my comment https://github.com/certbot/certbot/pull/3232#issuecomment-231154320 --- docs/using.rst | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 806dfb340..1d9dc0c32 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -8,14 +8,16 @@ User Guide Getting Certbot =============== -To get specific instructions for installing Certbot on your OS, we recommend -visiting certbot.eff.org_. If you're offline, you can find some general +To get specific instructions for installing Certbot on your OS, +visit certbot.eff.org_. This is the easiest way to install Certbot. + +If you're offline, or if your webserver or OS are not in the menu, you can find some general instructions `in the README / Introduction `__ __ installation_ .. _certbot.eff.org: https://certbot.eff.org -.. _certbot-auto: +.. _certbot-auto: https://certbot.eff.org/docs/using.html#certbot-auto The name of the certbot command ------------------------------- @@ -394,7 +396,12 @@ Running with Docker Docker_ is an amazingly simple and quick way to obtain a certificate. However, this mode of operation is unable to install certificates or configure your webserver, because our installer -plugins cannot reach it from inside the Docker container. +plugins cannot reach your webserver from inside the Docker container. + +Most users should use the operating system packages (available from +certbot.eff.org_) or, as a fallback, ``certbot-auto``. You should only +use Docker if you are sure you know what you are doing and have a +good reason to do so. You should definitely read the :ref:`where-certs` section, in order to know how to manage the certs @@ -415,9 +422,13 @@ to, `install Docker`_, then issue the following command: -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ quay.io/letsencrypt/letsencrypt:latest auth -and follow the instructions (note that ``auth`` command is explicitly -used - no installer plugins involved). Your new cert will be available -in ``/etc/letsencrypt/live`` on the host. +Certbot will obtain a certificate and place it in the directory +``/etc/letsencrypt/live`` on your system and display further instructions +for installing the certificates. You must use the ``auth`` command +to install the certificates instead of plug-ins for this method. + +For more information about the layout +of the ``/etc/letsencrypt`` directory, see :ref:`where-certs`. .. _Docker: https://docker.com .. _`install Docker`: https://docs.docker.com/userguide/ @@ -543,10 +554,10 @@ whole process is described in the :doc:`contributing`. Comparison of different methods ------------------------------- -Unless you have a very specific requirements, we kindly suggest that you use -the certbot-auto_ method. It's the fastest, the most thoroughly -tested and the most reliable way of getting our software and the free -TLS/SSL certificates! +Unless you have very specific requirements, we kindly suggest that you use +the Certbot packages provided by your package manager (see certbot.eff.org_). +If such packages are not available, we recommend using ``certbot-auto``, which +automates the process of installing Certbot on your system. Beyond the methods discussed here, other methods may be possible, such as installing Certbot directly with pip from PyPI or downloading a ZIP From 4b4a02a7af221116c2820af310cab317f78c4ed3 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Thu, 7 Jul 2016 20:07:13 -0500 Subject: [PATCH 182/264] Remove extra tracking of prev_handlers. --- certbot/error_handler.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/certbot/error_handler.py b/certbot/error_handler.py index e9deaea5c..68bd7f754 100644 --- a/certbot/error_handler.py +++ b/certbot/error_handler.py @@ -77,8 +77,8 @@ class ErrorHandler(object): self._call_registered() return retval finally: - prev_handlers = self._reset_signal_handlers() - self._call_signals(prev_handlers) + self._reset_signal_handlers() + self._call_signals() def register(self, func, *args, **kwargs): """Sets func to be called with *args and **kwargs during cleanup @@ -112,9 +112,7 @@ class ErrorHandler(object): """Resets signal handlers for signals in _SIGNALS.""" for signum in self.prev_handlers: signal.signal(signum, self.prev_handlers[signum]) - out = dict((k, v) for k, v in self.prev_handlers.items()) self.prev_handlers.clear() - return out def _signal_handler(self, signum, unused_frame): """Replacement function for handling recieved signals. @@ -129,13 +127,8 @@ class ErrorHandler(object): if not self.body_executed: raise errors.SignalExit - def _call_signals(self, prev_handlers): - """Finally call the deferred signals. - - :param int signum: signal number - - """ + def _call_signals(self): + """Finally call the deferred signals.""" for signum in self.received_signals: logger.debug("Calling signal %s", signum) - signal.signal(signum, prev_handlers[signum]) os.kill(os.getpid(), signum) From 40449ed2747634ae77928cae45424e5031a66c5b Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 8 Jul 2016 12:49:41 -0700 Subject: [PATCH 183/264] Add single _PERM_ERR_FMT string --- certbot/main.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/certbot/main.py b/certbot/main.py index be68d694e..8e47e736a 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -36,6 +36,12 @@ from certbot.display import util as display_util, ops as display_ops from certbot.plugins import disco as plugins_disco from certbot.plugins import selection as plug_sel + +_PERM_ERR_FMT = ("An error occurred while trying to create or modify {0}. To " + "run as non-root, set --config-dir, --logs-dir, and " + "--work-dir to writeable paths.") + + logger = logging.getLogger(__name__) From 9ae755ef4cf3f8f4978d7c5594d6d16ed835a1f5 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 8 Jul 2016 12:53:09 -0700 Subject: [PATCH 184/264] simplify log file error handling --- certbot/main.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/certbot/main.py b/certbot/main.py index 8e47e736a..d3f90926a 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -2,7 +2,6 @@ from __future__ import print_function import atexit import dialog -import errno import functools import logging.handlers import os @@ -602,13 +601,8 @@ def setup_log_file_handler(config, logfile, fmt): try: handler = logging.handlers.RotatingFileHandler( log_file_path, maxBytes=2 ** 20, backupCount=10) - except IOError as e: - if e.errno == errno.EACCES: - msg = ("Access denied writing to {0}. To run as non-root, set " + - "--logs-dir, --config-dir, --work-dir to writable paths.") - raise errors.Error(msg.format(log_file_path)) - else: - raise + except IOError: + raise errors.Error(_PERM_ERR_FMT.format(log_file_path)) # rotate on each invocation, rollover only possible when maxBytes # is nonzero and backupCount is nonzero, so we set maxBytes as big # as possible not to overrun in single CLI invocation (1MB). From f3c6bac31065a200e1a2b79579c907279d48af1b Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 8 Jul 2016 13:02:28 -0700 Subject: [PATCH 185/264] stop spacing out --- certbot/tests/main_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index 66cba64a3..d044a50b7 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -1,10 +1,8 @@ """Tests for certbot.main.""" import unittest - import mock - from certbot import cli from certbot import configuration from certbot.plugins import disco as plugins_disco From 4f35f3fdf7e8631282d11d3c7a854770dd02dccf Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 8 Jul 2016 13:07:49 -0700 Subject: [PATCH 186/264] Add SetupLogFileHandlerTest --- certbot/tests/main_test.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index d044a50b7..5f6723bd7 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -1,10 +1,13 @@ """Tests for certbot.main.""" +import shutil +import tempfile import unittest import mock from certbot import cli from certbot import configuration +from certbot import errors from certbot.plugins import disco as plugins_disco @@ -42,5 +45,26 @@ class ObtainCertTest(unittest.TestCase): self.assertFalse(pause) +class SetupLogFileHandlerTest(unittest.TestCase): + """Tests for certbot.main.setup_log_file_handler.""" + + def setUp(self): + self.config = mock.Mock(spec_set=['logs_dir'], + logs_dir=tempfile.mkdtemp()) + + def tearDown(self): + shutil.rmtree(self.config.logs_dir) + + def _call(self, *args, **kwargs): + from certbot.main import setup_log_file_handler + return setup_log_file_handler(*args, **kwargs) + + @mock.patch('certbot.main.logging.handlers.RotatingFileHandler') + def test_ioerror(self, mock_handler): + mock_handler.side_effect = IOError + self.assertRaises(errors.Error, self._call, + self.config, "test.log", "%s") + + if __name__ == '__main__': unittest.main() # pragma: no cover From 754b7956b3003cc75b2b1a11e40d86a6bf6828f3 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 6 Jul 2016 15:49:22 -0700 Subject: [PATCH 187/264] Make the error even more informative --- certbot-apache/certbot_apache/configurator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index d1c2b7165..0c95fe18e 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -159,8 +159,9 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): # Verify Apache is installed restart_cmd = constants.os_constant("restart_cmd")[0] if not util.exe_exists(restart_cmd): + logger.warn("Failed to find %s in PATH: %s", restart_cmd, os.environ["PATH"]) raise errors.NoInstallationError( - 'Cannot find Apache install ({0} not in PATH)'.format(restart_cmd)) + 'Cannot find Apache control command {0}'.format(restart_cmd)) # Make sure configuration is valid self.config_test() From a322f44f2b7c0ef0302de956ed068671cf4ef32f Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 7 Jul 2016 17:54:39 -0700 Subject: [PATCH 188/264] Implement PATH fallback for apachectl search --- certbot-apache/certbot_apache/configurator.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 0c95fe18e..c9a00a64e 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -159,9 +159,16 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): # Verify Apache is installed restart_cmd = constants.os_constant("restart_cmd")[0] if not util.exe_exists(restart_cmd): - logger.warn("Failed to find %s in PATH: %s", restart_cmd, os.environ["PATH"]) - raise errors.NoInstallationError( - 'Cannot find Apache control command {0}'.format(restart_cmd)) + # mitigate https://github.com/certbot/certbot/issues/1833 + logger.debug("Can't find %s, attempting PATH mitigation by adding " + "/usr/sbin/ and /usr/local/bin/", restart_cmd) + os.environ["PATH"] = os.pathsep.join((os.environ["PATH"], "/usr/sbin/", + "/usr/local/bin/")) + if not util.exe_exists(restart_cmd): + logger.warn("Failed to find %s in expanded PATH: %s", + restart_cmd, os.environ["PATH"]) + raise errors.NoInstallationError( + 'Cannot find Apache control command {0}'.format(restart_cmd)) # Make sure configuration is valid self.config_test() From cecac803a09c8c934f6fbe14bbe9204467d7174b Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 7 Jul 2016 18:17:45 -0700 Subject: [PATCH 189/264] Do this more cleanly --- certbot-apache/certbot_apache/configurator.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index c9a00a64e..329e62135 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -141,6 +141,20 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): return os.path.join(self.config.config_dir, constants.MOD_SSL_CONF_DEST) + def _path_surgery(self): + """Mitigate https://github.com/certbot/certbot/issues/1833""" + dirs = ("/usr/sbin/", "/usr/local/bin/", "/usr/local/sbin/") + path = os.environ["PATH"] + added = [] + for d in dirs: + if d not in path: + path += os.pathsep + d + added.append(d) + if any(added): + logger.debug("Can't find %s, attempting PATH mitigation by adding %s" + restart_cmd, os.pathsep.join(added)) + os.environ["PATH"] = path + def prepare(self): """Prepare the authenticator/installer. @@ -159,11 +173,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): # Verify Apache is installed restart_cmd = constants.os_constant("restart_cmd")[0] if not util.exe_exists(restart_cmd): - # mitigate https://github.com/certbot/certbot/issues/1833 - logger.debug("Can't find %s, attempting PATH mitigation by adding " - "/usr/sbin/ and /usr/local/bin/", restart_cmd) - os.environ["PATH"] = os.pathsep.join((os.environ["PATH"], "/usr/sbin/", - "/usr/local/bin/")) + self._path_surgery() if not util.exe_exists(restart_cmd): logger.warn("Failed to find %s in expanded PATH: %s", restart_cmd, os.environ["PATH"]) From 757a8ddae7c5ac1a8acd500cda9b1f7505fc4963 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 8 Jul 2016 00:37:52 -0700 Subject: [PATCH 190/264] Fixes & tests --- certbot-apache/certbot_apache/configurator.py | 20 +++++++++----- .../certbot_apache/tests/configurator_test.py | 26 +++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 329e62135..12cba34f1 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -141,9 +141,13 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): return os.path.join(self.config.config_dir, constants.MOD_SSL_CONF_DEST) - def _path_surgery(self): - """Mitigate https://github.com/certbot/certbot/issues/1833""" - dirs = ("/usr/sbin/", "/usr/local/bin/", "/usr/local/sbin/") + def _path_surgery(self, restart_cmd): + """Mitigate https://github.com/certbot/certbot/issues/1833 + + :returns: " expanded" if an expansion of the PATH occurred; + "" otherwise + """ + dirs = ("/usr/sbin", "/usr/local/bin", "/usr/local/sbin") path = os.environ["PATH"] added = [] for d in dirs: @@ -151,9 +155,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): path += os.pathsep + d added.append(d) if any(added): - logger.debug("Can't find %s, attempting PATH mitigation by adding %s" + logger.debug("Can't find %s, attempting PATH mitigation by adding %s", restart_cmd, os.pathsep.join(added)) os.environ["PATH"] = path + return " expanded" + return "" def prepare(self): """Prepare the authenticator/installer. @@ -173,10 +179,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): # Verify Apache is installed restart_cmd = constants.os_constant("restart_cmd")[0] if not util.exe_exists(restart_cmd): - self._path_surgery() + expanded = self._path_surgery(restart_cmd) if not util.exe_exists(restart_cmd): - logger.warn("Failed to find %s in expanded PATH: %s", - restart_cmd, os.environ["PATH"]) + logger.warn("Failed to find %s in %s PATH: %s", + restart_cmd, expanded, os.environ["PATH"]) raise errors.NoInstallationError( 'Cannot find Apache control command {0}'.format(restart_cmd)) diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index 9a034c3e0..d5139912e 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -86,6 +86,32 @@ class MultipleVhostsTest(util.ApacheTest): self.assertRaises( errors.NotSupportedError, self.config.prepare) + @mock.patch("certbot_apache.configurator.logger.debug") + def test_path_surgery(self, mock_debug): + # pylint: disable=protected-access + all_path = {"PATH": "/usr/local/bin:/bin/:/usr/sbin/:/usr/local/sbin/"} + with mock.patch.dict('os.environ', all_path): + self.config._path_surgery("thingy") + self.assertEquals(mock_debug.call_count, 0) + self.assertEquals(os.environ["PATH"], all_path["PATH"]) + no_path = {"PATH": "/tmp/"} + with mock.patch.dict('os.environ', no_path): + self.config._path_surgery("thingy") + self.assertEquals(mock_debug.call_count, 1) + self.assertTrue("/usr/local/bin" in os.environ["PATH"]) + self.assertTrue("/tmp" in os.environ["PATH"]) + + @mock.patch("certbot_apache.configurator.ApacheConfigurator.init_augeas") + @mock.patch("certbot_apache.configurator.ApacheConfigurator._path_surgery") + @mock.patch("certbot_apache.configurator.logger.warn") + def test_no_install(self, mock_warn, mock_surgery, _init_augeas): + silly_path = {"PATH": "/tmp/nothingness2342"} + with mock.patch.dict('os.environ', silly_path): + self.assertRaises(errors.NoInstallationError, self.config.prepare) + self.assertEquals(mock_warn.call_count, 1) + self.assertEquals(mock_surgery.call_count, 1) + self.assertTrue("Failed to find" in mock_warn.call_args[0][0]) + def test_add_parser_arguments(self): # pylint: disable=no-self-use from certbot_apache.configurator import ApacheConfigurator # Weak test.. From 0bedeb449a239e79ccba3989c12ba07b3c93e363 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 8 Jul 2016 13:58:39 -0700 Subject: [PATCH 191/264] Refactor path_surgery into plugins.util so that nginx can call it --- certbot-apache/certbot_apache/configurator.py | 25 +----------- .../certbot_apache/tests/configurator_test.py | 38 ++++--------------- certbot/plugins/util.py | 30 +++++++++++++++ certbot/plugins/util_test.py | 24 ++++++++++++ 4 files changed, 64 insertions(+), 53 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 12cba34f1..74aab242e 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -18,6 +18,7 @@ from certbot import interfaces from certbot import util from certbot.plugins import common +from certbot.plugins.util import path_surgery from certbot_apache import augeas_configurator from certbot_apache import constants @@ -141,25 +142,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): return os.path.join(self.config.config_dir, constants.MOD_SSL_CONF_DEST) - def _path_surgery(self, restart_cmd): - """Mitigate https://github.com/certbot/certbot/issues/1833 - - :returns: " expanded" if an expansion of the PATH occurred; - "" otherwise - """ - dirs = ("/usr/sbin", "/usr/local/bin", "/usr/local/sbin") - path = os.environ["PATH"] - added = [] - for d in dirs: - if d not in path: - path += os.pathsep + d - added.append(d) - if any(added): - logger.debug("Can't find %s, attempting PATH mitigation by adding %s", - restart_cmd, os.pathsep.join(added)) - os.environ["PATH"] = path - return " expanded" - return "" def prepare(self): """Prepare the authenticator/installer. @@ -179,10 +161,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): # Verify Apache is installed restart_cmd = constants.os_constant("restart_cmd")[0] if not util.exe_exists(restart_cmd): - expanded = self._path_surgery(restart_cmd) - if not util.exe_exists(restart_cmd): - logger.warn("Failed to find %s in %s PATH: %s", - restart_cmd, expanded, os.environ["PATH"]) + if not path_surgery(restart_cmd): raise errors.NoInstallationError( 'Cannot find Apache control command {0}'.format(restart_cmd)) diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index d5139912e..eac16c7fe 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -49,11 +49,14 @@ class MultipleVhostsTest(util.ApacheTest): shutil.rmtree(self.config_dir) shutil.rmtree(self.work_dir) - @mock.patch("certbot_apache.configurator.util.exe_exists") - def test_prepare_no_install(self, mock_exe_exists): - mock_exe_exists.return_value = False - self.assertRaises( - errors.NoInstallationError, self.config.prepare) + @mock.patch("certbot_apache.configurator.ApacheConfigurator.init_augeas") + @mock.patch("certbot_apache.configurator.path_surgery") + def test_prepare_no_install(self, mock_surgery, _init_augeas): + silly_path = {"PATH": "/tmp/nothingness2342"} + mock_surgery.return_value = False + with mock.patch.dict('os.environ', silly_path): + self.assertRaises(errors.NoInstallationError, self.config.prepare) + self.assertEquals(mock_surgery.call_count, 1) @mock.patch("certbot_apache.augeas_configurator.AugeasConfigurator.init_augeas") def test_prepare_no_augeas(self, mock_init_augeas): @@ -86,31 +89,6 @@ class MultipleVhostsTest(util.ApacheTest): self.assertRaises( errors.NotSupportedError, self.config.prepare) - @mock.patch("certbot_apache.configurator.logger.debug") - def test_path_surgery(self, mock_debug): - # pylint: disable=protected-access - all_path = {"PATH": "/usr/local/bin:/bin/:/usr/sbin/:/usr/local/sbin/"} - with mock.patch.dict('os.environ', all_path): - self.config._path_surgery("thingy") - self.assertEquals(mock_debug.call_count, 0) - self.assertEquals(os.environ["PATH"], all_path["PATH"]) - no_path = {"PATH": "/tmp/"} - with mock.patch.dict('os.environ', no_path): - self.config._path_surgery("thingy") - self.assertEquals(mock_debug.call_count, 1) - self.assertTrue("/usr/local/bin" in os.environ["PATH"]) - self.assertTrue("/tmp" in os.environ["PATH"]) - - @mock.patch("certbot_apache.configurator.ApacheConfigurator.init_augeas") - @mock.patch("certbot_apache.configurator.ApacheConfigurator._path_surgery") - @mock.patch("certbot_apache.configurator.logger.warn") - def test_no_install(self, mock_warn, mock_surgery, _init_augeas): - silly_path = {"PATH": "/tmp/nothingness2342"} - with mock.patch.dict('os.environ', silly_path): - self.assertRaises(errors.NoInstallationError, self.config.prepare) - self.assertEquals(mock_warn.call_count, 1) - self.assertEquals(mock_surgery.call_count, 1) - self.assertTrue("Failed to find" in mock_warn.call_args[0][0]) def test_add_parser_arguments(self): # pylint: disable=no-self-use from certbot_apache.configurator import ApacheConfigurator diff --git a/certbot/plugins/util.py b/certbot/plugins/util.py index 5fc98dff6..cdba88a87 100644 --- a/certbot/plugins/util.py +++ b/certbot/plugins/util.py @@ -1,15 +1,45 @@ """Plugin utilities.""" import logging +import os import socket import psutil import zope.component from certbot import interfaces +from certbot import util logger = logging.getLogger(__name__) +def path_surgery(restart_cmd): + """Attempt to perform PATH surgery to find restart_cmd + + Mitigates https://github.com/certbot/certbot/issues/1833 + + :param str restart_cmd: the command that is being searched for in the PATH + + :returns: True if the operation succeeded, False otherwise + """ + dirs = ("/usr/sbin", "/usr/local/bin", "/usr/local/sbin") + path = os.environ["PATH"] + added = [] + for d in dirs: + if d not in path: + path += os.pathsep + d + added.append(d) + + if any(added): + logger.debug("Can't find %s, attempting PATH mitigation by adding %s", + restart_cmd, os.pathsep.join(added)) + os.environ["PATH"] = path + + if util.exe_exists(restart_cmd): + return True + else: + expanded = " expanded" if any(added) else "" + logger.warn("Failed to find %s in%s PATH: %s", restart_cmd, expanded, path) + return False def already_listening(port, renewer=False): """Check if a process is already listening on the port. diff --git a/certbot/plugins/util_test.py b/certbot/plugins/util_test.py index 9bc8793c7..fa8b364d9 100644 --- a/certbot/plugins/util_test.py +++ b/certbot/plugins/util_test.py @@ -1,9 +1,33 @@ """Tests for certbot.plugins.util.""" +import os import unittest import mock import psutil +class PathSurgeryTest(unittest.TestCase): + """Tests for certbot.plugins.path_surgery.""" + + @mock.patch("certbot.plugins.util.logger.warn") + @mock.patch("certbot.plugins.util.logger.debug") + def test_path_surgery(self, mock_debug, mock_warn): + from certbot.plugins.util import path_surgery + all_path = {"PATH": "/usr/local/bin:/bin/:/usr/sbin/:/usr/local/sbin/"} + with mock.patch.dict('os.environ', all_path): + with mock.patch('certbot.util.exe_exists') as mock_exists: + mock_exists.return_value = True + self.assertEquals(path_surgery("eg"), True) + self.assertEquals(mock_debug.call_count, 0) + self.assertEquals(mock_warn.call_count, 0) + self.assertEquals(os.environ["PATH"], all_path["PATH"]) + no_path = {"PATH": "/tmp/"} + with mock.patch.dict('os.environ', no_path): + path_surgery("thingy") + self.assertEquals(mock_debug.call_count, 1) + self.assertEquals(mock_warn.call_count, 1) + self.assertTrue("Failed to find" in mock_warn.call_args[0][0]) + self.assertTrue("/usr/local/bin" in os.environ["PATH"]) + self.assertTrue("/tmp" in os.environ["PATH"]) class AlreadyListeningTest(unittest.TestCase): """Tests for certbot.plugins.already_listening.""" From ed73c55b7bfca9939d9cd0d8edebddedf29ade2e Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Fri, 8 Jul 2016 16:03:40 -0500 Subject: [PATCH 192/264] Instantiate exception_raised in test. --- certbot/tests/error_handler_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index a32f2a448..2eb1506be 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -42,6 +42,7 @@ class ErrorHandlerTest(unittest.TestCase): self.signals = error_handler._SIGNALS def test_context_manager(self): + exception_raised = False try: with self.handler: raise ValueError From 48b7c01a5925e476f6b4197fa34370cc07d97607 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 8 Jul 2016 14:06:15 -0700 Subject: [PATCH 193/264] bring make_or_verify_dir docstring up to date --- certbot/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/certbot/util.py b/certbot/util.py index 301fc669b..2b40a0f2c 100644 --- a/certbot/util.py +++ b/certbot/util.py @@ -95,6 +95,7 @@ def make_or_verify_dir(directory, mode=0o755, uid=0, strict=False): :param str directory: Path to a directory. :param int mode: Directory mode. :param int uid: Directory owner. + :param bool strict: require directory to be owned by current user :raises .errors.Error: if a directory already exists, but has wrong permissions or owner From d7772217032235337405f8e4b62a9970f057a8fc Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 8 Jul 2016 14:17:19 -0700 Subject: [PATCH 194/264] write make_or_verify_core_dir --- certbot/main.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/certbot/main.py b/certbot/main.py index d3f90926a..2a18aa528 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -702,6 +702,23 @@ def _handle_exception(exc_type, exc_value, trace, config): traceback.format_exception(exc_type, exc_value, trace))) +def make_or_verify_core_dir(directory, mode, uid, strict): + """Make sure directory exists with proper permissions. + + :param str directory: Path to a directory. + :param int mode: Directory mode. + :param int uid: Directory owner. + :param bool strict: require directory to be owned by current user + + :raises .errors.Error: if the directory cannot be made or verified + + """ + try: + util.make_or_verify_dir(directory, mode, uid, strict) + except OSError: + raise errors.Error(_PERM_ERR_FMT.format(directory)) + + def main(cli_args=sys.argv[1:]): """Command line argument parsing and main script execution.""" sys.excepthook = functools.partial(_handle_exception, config=None) @@ -712,16 +729,16 @@ def main(cli_args=sys.argv[1:]): config = configuration.NamespaceConfig(args) zope.component.provideUtility(config) - # Setup logging ASAP, otherwise "No handlers could be found for - # logger ..." TODO: this should be done before plugins discovery - for directory in config.config_dir, config.work_dir: - util.make_or_verify_dir( - directory, constants.CONFIG_DIRS_MODE, os.geteuid(), - "--strict-permissions" in cli_args) + make_or_verify_core_dir(config.config_dir, constants.CONFIG_DIRS_MODE, + os.geteuid(), config.strict_permissions) + make_or_verify_core_dir(config.work_dir, constants.CONFIG_DIRS_MODE, + os.geteuid(), config.strict_permissions) # TODO: logs might contain sensitive data such as contents of the # private key! #525 - util.make_or_verify_dir( - config.logs_dir, 0o700, os.geteuid(), "--strict-permissions" in cli_args) + make_or_verify_core_dir(config.logs_dir, 0o700, + os.geteuid(), config.strict_permissions) + # Setup logging ASAP, otherwise "No handlers could be found for + # logger ..." TODO: this should be done before plugins discovery setup_logging(config, _cli_log_handler, logfile='letsencrypt.log') cli.possible_deprecation_warning(config) From e598e907bdbfb69418e6909a5e0f8bc3eb1994e4 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 8 Jul 2016 14:54:51 -0700 Subject: [PATCH 195/264] create MakeOrVerifyCoreDirTest --- certbot/tests/main_test.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index 5f6723bd7..32df525f0 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -1,4 +1,5 @@ """Tests for certbot.main.""" +import os import shutil import tempfile import unittest @@ -66,5 +67,30 @@ class SetupLogFileHandlerTest(unittest.TestCase): self.config, "test.log", "%s") +class MakeOrVerifyCoreDirTest(unittest.TestCase): + """Tests for certbot.main.make_or_verify_core_dir.""" + + def setUp(self): + self.dir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.dir) + + def _call(self, *args, **kwargs): + from certbot.main import make_or_verify_core_dir + return make_or_verify_core_dir(*args, **kwargs) + + def test_success(self): + new_dir = os.path.join(self.dir, 'new') + self._call(new_dir, 0o700, os.geteuid(), False) + self.assertTrue(os.path.exists(new_dir)) + + @mock.patch('certbot.main.util.make_or_verify_dir') + def test_failure(self, mock_make_or_verify): + mock_make_or_verify.side_effect = OSError + self.assertRaises(errors.Error, self._call, + self.dir, 0o700, os.geteuid(), False) + + if __name__ == '__main__': unittest.main() # pragma: no cover From d4a8820bdcc2cfaf380e58fb026b4681636ed084 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Fri, 8 Jul 2016 15:04:44 -0700 Subject: [PATCH 196/264] wrap with escapes --- certbot-apache/certbot_apache/configurator.py | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 5733baa26..3d6253f33 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -529,7 +529,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if addr.get_port() == "443": is_ssl = True - filename = self._unescape(get_file_path(path)) + filename = get_file_path(self.aug.get("/augeas/files%s/file" % get_file_path(path))) if self.conf("handle-sites"): is_enabled = self.is_site_enabled(filename) else: @@ -770,7 +770,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): """ avail_fp = nonssl_vhost.filep - ssl_fp = self._escape(self._get_ssl_vhost_path(avail_fp)) + ssl_fp = self._get_ssl_vhost_path(avail_fp) self._copy_create_ssl_vhost_skeleton(avail_fp, ssl_fp) @@ -778,7 +778,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): self.aug.load() # Get Vhost augeas path for new vhost vh_p = self.aug.match("/files%s//* [label()=~regexp('%s')]" % - (ssl_fp, parser.case_i("VirtualHost"))) + (_escape(ssl_fp), parser.case_i("VirtualHost"))) if len(vh_p) != 1: logger.error("Error: should only be one vhost in %s", avail_fp) raise errors.PluginError("Currently, we only support " @@ -997,11 +997,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if need_to_save: self.save() - def _unescape(self, fp): - return fp.replace("\\", "") - def _escape(self, fp): - return fp.replace(",", "\\,") + fp = fp.replace(",", "\\,") + fp = fp.replace("[", "\\[") + fp = fp.replace("]", "\\]") + fp = fp.replace("|", "\\|") + fp = fp.replace("=", "\\=") + fp = fp.replace("(", "\\(") + fp = fp.replace(")", "\\)") + fp = fp.replace("!", "\\!") ###################################################################### # Enhancements @@ -1332,7 +1336,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): self.aug.load() # Make a new vhost data structure and add it to the lists - new_vhost = self._create_vhost(parser.get_aug_path(redirect_filepath)) + new_vhost = self._create_vhost(parser.get_aug_path(self._escape(redirect_filepath))) self.vhosts.append(new_vhost) self._enhanced_vhosts["redirect"].add(new_vhost) From 1113e280460f811486a6404d4ed5a9b0c286ef8f Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Fri, 8 Jul 2016 15:22:56 -0700 Subject: [PATCH 197/264] fix typo --- certbot-apache/certbot_apache/configurator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 3d6253f33..afaf7f93e 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -529,7 +529,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if addr.get_port() == "443": is_ssl = True - filename = get_file_path(self.aug.get("/augeas/files%s/file" % get_file_path(path))) + filename = get_file_path(self.aug.get("/augeas/files%s/path" % get_file_path(path))) if self.conf("handle-sites"): is_enabled = self.is_site_enabled(filename) else: From d8c2dd1a5c741bb9d2f375bf3f453a44a6ab7184 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Fri, 8 Jul 2016 15:28:12 -0700 Subject: [PATCH 198/264] add self --- certbot-apache/certbot_apache/configurator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index afaf7f93e..a2a4182db 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -778,7 +778,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): self.aug.load() # Get Vhost augeas path for new vhost vh_p = self.aug.match("/files%s//* [label()=~regexp('%s')]" % - (_escape(ssl_fp), parser.case_i("VirtualHost"))) + (self._escape(ssl_fp), parser.case_i("VirtualHost"))) if len(vh_p) != 1: logger.error("Error: should only be one vhost in %s", avail_fp) raise errors.PluginError("Currently, we only support " From 1bbfde1771a97b828218061b1c83734a087896ce Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Fri, 8 Jul 2016 15:35:29 -0700 Subject: [PATCH 199/264] don't code while distracted --- certbot-apache/certbot_apache/configurator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index a2a4182db..b4ce29d31 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -1006,6 +1006,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): fp = fp.replace("(", "\\(") fp = fp.replace(")", "\\)") fp = fp.replace("!", "\\!") + return fp ###################################################################### # Enhancements From 9372914c67e189c00a4f6c4143011811b4a617d9 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 8 Jul 2016 15:51:31 -0700 Subject: [PATCH 200/264] Improve error message --- certbot/main.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/certbot/main.py b/certbot/main.py index 2a18aa528..8bccc524d 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -36,9 +36,10 @@ from certbot.plugins import disco as plugins_disco from certbot.plugins import selection as plug_sel -_PERM_ERR_FMT = ("An error occurred while trying to create or modify {0}. To " - "run as non-root, set --config-dir, --logs-dir, and " - "--work-dir to writeable paths.") +_PERM_ERR_FMT = os.linesep.join(( + "The following error was encountered:", "{0}", + "If running as non-root, set --config-dir, " + "--logs-dir, and --work-dir to writeable paths.")) logger = logging.getLogger(__name__) @@ -601,8 +602,8 @@ def setup_log_file_handler(config, logfile, fmt): try: handler = logging.handlers.RotatingFileHandler( log_file_path, maxBytes=2 ** 20, backupCount=10) - except IOError: - raise errors.Error(_PERM_ERR_FMT.format(log_file_path)) + except IOError as error: + raise errors.Error(_PERM_ERR_FMT.format(error)) # rotate on each invocation, rollover only possible when maxBytes # is nonzero and backupCount is nonzero, so we set maxBytes as big # as possible not to overrun in single CLI invocation (1MB). @@ -715,8 +716,8 @@ def make_or_verify_core_dir(directory, mode, uid, strict): """ try: util.make_or_verify_dir(directory, mode, uid, strict) - except OSError: - raise errors.Error(_PERM_ERR_FMT.format(directory)) + except OSError as error: + raise errors.Error(_PERM_ERR_FMT.format(error)) def main(cli_args=sys.argv[1:]): From 156ea46a09fde04fd24c959566d25a11326a089d Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Fri, 8 Jul 2016 16:30:50 -0500 Subject: [PATCH 201/264] Compare initial and final signals in tests. --- certbot/tests/error_handler_test.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/certbot/tests/error_handler_test.py b/certbot/tests/error_handler_test.py index 2eb1506be..2e2ffe2d9 100644 --- a/certbot/tests/error_handler_test.py +++ b/certbot/tests/error_handler_test.py @@ -7,18 +7,25 @@ import unittest import mock +def get_signals(signums): + """Get the handlers for an iterable of signums.""" + return dict((s, signal.getsignal(s)) for s in signums) + + +def set_signals(sig_handler_dict): + """Set the signal (keys) with the handler (values) from the input dict.""" + tuple(signal.signal(s, h) for (s, h) in sig_handler_dict.items()) + @contextlib.contextmanager def signal_receiver(signums): """Context manager to catch signals""" signals = [] prev_handlers = {} - for signum in signums: - prev_handlers[signum] = signal.getsignal(signum) - signal.signal(signum, lambda signum, _: signals.append(signum)) + prev_handlers = get_signals(signums) + set_signals(dict((s, lambda s, _: signals.append(s)) for s in signums)) yield signals - for signum in signums: - signal.signal(signum, prev_handlers[signum]) + set_signals(dict((s, prev_handlers[s]) for s in signums)) def send_signal(signum): @@ -54,6 +61,7 @@ class ErrorHandlerTest(unittest.TestCase): **self.init_kwargs) def test_context_manager_with_signal(self): + init_signals = get_signals(self.signals) with signal_receiver(self.signals) as signals_received: with self.handler: should_be_42 = 42 @@ -68,8 +76,7 @@ class ErrorHandlerTest(unittest.TestCase): self.init_func.assert_called_once_with(*self.init_args, **self.init_kwargs) for signum in self.signals: - sig = signal.getsignal(signum) - self.assertTrue((sig == signal.SIG_DFL) or (sig == signal.SIG_IGN)) + self.assertEqual(init_signals[signum], signal.getsignal(signum)) def test_bad_recovery(self): bad_func = mock.MagicMock(side_effect=[ValueError]) From 68500cd4361bd0d07167c8f42a77adec3ac034f9 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 9 Jul 2016 15:13:09 -0700 Subject: [PATCH 202/264] Don't allow dollar_var to swalllow characters like "{" --- certbot-nginx/certbot_nginx/nginxparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index 0cc912515..1859777d8 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -23,7 +23,7 @@ class RawNginxParser(object): right_bracket = space.leaveWhitespace() + Literal("}").suppress() semicolon = Literal(";").suppress() key = Word(alphanums + "_/+-.") - dollar_var = Combine(Literal('$') + nonspace) + dollar_var = Combine(Literal('$') + Regex(r"[^\{\};,\s]+")) condition = Regex(r"\(.+\)") # Matches anything that is not a special character AND any chars in single # or double quotes From 9bc50d4a4761e6734389697b1cdff1c5339726d7 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Mon, 11 Jul 2016 12:43:33 -0500 Subject: [PATCH 203/264] Try to fix travis-ci lint failure --- certbot-apache/certbot_apache/tests/configurator_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index 633757de4..99b1b8b74 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -1,4 +1,4 @@ -# pylint: disable=too-many-public-methods +# pylint: disable=too-many-public-methods,too-many-lines """Test for certbot_apache.configurator.""" import os import shutil From 8f1a141d2a3c343d1521a48897fde187e7bcc94e Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 11 Jul 2016 13:20:31 -0700 Subject: [PATCH 204/264] incorporate brad's comments --- certbot-apache/certbot_apache/configurator.py | 2 +- certbot-apache/certbot_apache/tests/configurator_test.py | 3 ++- .../augeas_vhosts/apache2/sites-enabled/000-default.conf | 1 - .../augeas_vhosts/apache2/sites-enabled/certbot.conf | 1 - .../apache2/sites-enabled/encryption-example.conf | 1 - .../augeas_vhosts/apache2/sites-enabled/mod_macro-example.conf | 1 - .../augeas_vhosts/apache2/sites-enabled/ocsp-ssl.conf | 1 - 7 files changed, 3 insertions(+), 7 deletions(-) delete mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/000-default.conf delete mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/certbot.conf delete mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/encryption-example.conf delete mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/mod_macro-example.conf delete mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/ocsp-ssl.conf diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index b4ce29d31..2c9bd982f 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -1080,7 +1080,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): if not use_stapling_aug_path: self.parser.add_dir(ssl_vhost.path, "SSLUseStapling", "on") - ssl_vhost_aug_path = parser.get_aug_path(ssl_vhost.filep) + ssl_vhost_aug_path = self._escape(parser.get_aug_path(ssl_vhost.filep)) # Check if there's an existing SSLStaplingCache directive. stapling_cache_aug_path = self.parser.find_dir('SSLStaplingCache', diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index a90940f94..ceef5b9e4 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -1,4 +1,4 @@ -# pylint: disable=too-many-public-methods, protected-access +# pylint: disable=too-many-public-methods """Test for certbot_apache.configurator.""" import os import shutil @@ -1188,6 +1188,7 @@ class MultipleVhostsTest(util.ApacheTest): class AugeasVhostsTest(util.ApacheTest): """Test vhosts with illegal names dependant on augeas version.""" + # pylint: disable=protected-access def setUp(self): # pylint: disable=arguments-differ td = "debian_apache_2_4/augeas_vhosts" diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/000-default.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/000-default.conf deleted file mode 120000 index 3c4632b73..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/000-default.conf +++ /dev/null @@ -1 +0,0 @@ -../sites-available/000-default.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/certbot.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/certbot.conf deleted file mode 120000 index 4d08c763f..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/certbot.conf +++ /dev/null @@ -1 +0,0 @@ -../sites-available/certbot.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/encryption-example.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/encryption-example.conf deleted file mode 120000 index 417818069..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/encryption-example.conf +++ /dev/null @@ -1 +0,0 @@ -../sites-available/encryption-example.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/mod_macro-example.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/mod_macro-example.conf deleted file mode 120000 index 44f254304..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/mod_macro-example.conf +++ /dev/null @@ -1 +0,0 @@ -../sites-available/mod_macro-example.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/ocsp-ssl.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/ocsp-ssl.conf deleted file mode 120000 index b25ee0482..000000000 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/augeas_vhosts/apache2/sites-enabled/ocsp-ssl.conf +++ /dev/null @@ -1 +0,0 @@ -../sites-available/ocsp-ssl.conf \ No newline at end of file From b48ddac5285572129937661e0e8291a329d3bb98 Mon Sep 17 00:00:00 2001 From: Seth Schoen Date: Mon, 11 Jul 2016 13:58:21 -0700 Subject: [PATCH 205/264] Initial version of nginx parser roundtrip test --- certbot-compatibility-test/nginx/README | 27 ++++ .../79-configs/site-10033 | 34 +++++ .../79-configs/site-10571 | 71 +++++++++ .../79-configs/site-10591 | 38 +++++ .../79-configs/site-10920 | 16 +++ .../79-configs/site-10947 | 40 ++++++ .../79-configs/site-11018 | 37 +++++ .../79-configs/site-11046 | 36 +++++ .../79-configs/site-11382 | 29 ++++ .../79-configs/site-1167 | 38 +++++ .../79-configs/site-11849 | 36 +++++ .../79-configs/site-12027 | 29 ++++ .../79-configs/site-12235 | 33 +++++ .../79-configs/site-12649 | 45 ++++++ .../79-configs/site-13577 | 38 +++++ .../79-configs/site-14402 | 33 +++++ .../79-configs/site-14430 | 54 +++++++ .../79-configs/site-15141 | 36 +++++ .../79-configs/site-15270 | 38 +++++ .../79-configs/site-15291 | 112 +++++++++++++++ .../79-configs/site-15456 | 39 +++++ .../79-configs/site-15497 | 35 +++++ .../79-configs/site-15852 | 38 +++++ .../79-configs/site-16345 | 34 +++++ .../79-configs/site-17175 | 14 ++ .../79-configs/site-17832 | 32 +++++ .../79-configs/site-17942 | 32 +++++ .../79-configs/site-18018 | 36 +++++ .../79-configs/site-18069 | 39 +++++ .../79-configs/site-19334 | 39 +++++ .../79-configs/site-19639 | 39 +++++ .../79-configs/site-1966 | 36 +++++ .../79-configs/site-19791 | 34 +++++ .../79-configs/site-19955 | 36 +++++ .../79-configs/site-21369 | 33 +++++ .../79-configs/site-21549 | 32 +++++ .../79-configs/site-230 | 33 +++++ .../79-configs/site-23325 | 74 ++++++++++ .../79-configs/site-23470 | 56 ++++++++ .../79-configs/site-23791 | 33 +++++ .../79-configs/site-23803 | 32 +++++ .../79-configs/site-23838 | 32 +++++ .../79-configs/site-24125 | 7 + .../79-configs/site-24193 | 62 ++++++++ .../79-configs/site-24213 | 36 +++++ .../79-configs/site-25480 | 32 +++++ .../79-configs/site-26195 | 26 ++++ .../79-configs/site-26221 | 32 +++++ .../79-configs/site-26637 | 32 +++++ .../79-configs/site-26758 | 21 +++ .../79-configs/site-27646 | 37 +++++ .../79-configs/site-27728 | 5 + .../79-configs/site-27736 | 32 +++++ .../79-configs/site-27812 | 36 +++++ .../79-configs/site-28050 | 36 +++++ .../79-configs/site-28690 | 32 +++++ .../79-configs/site-29159 | 33 +++++ .../79-configs/site-2951 | 67 +++++++++ .../79-configs/site-30011 | 37 +++++ .../79-configs/site-30571 | 31 ++++ .../79-configs/site-31900 | 33 +++++ .../79-configs/site-32190 | 4 + .../79-configs/site-32279 | 25 ++++ .../79-configs/site-32317 | 32 +++++ .../79-configs/site-32438 | 46 ++++++ .../79-configs/site-3483 | 32 +++++ .../79-configs/site-3507 | 44 ++++++ .../79-configs/site-3874 | 46 ++++++ .../79-configs/site-4035 | 31 ++++ .../79-configs/site-4143 | 33 +++++ .../79-configs/site-4264 | 12 ++ .../79-configs/site-5826 | 38 +++++ .../79-configs/site-5872 | 36 +++++ .../79-configs/site-6228 | 39 +++++ .../79-configs/site-7895 | 32 +++++ .../79-configs/site-8343 | 36 +++++ .../79-configs/site-8422 | 46 ++++++ .../79-configs/site-8637 | 40 ++++++ .../79-configs/site-8662 | 32 +++++ .../79-configs/site-9426 | 111 ++++++++++++++ .../activecolab/www.example.com.vhost | 44 ++++++ .../chive/chive-nginx-master/fastcgi.conf | 9 ++ .../chive/chive-nginx-master/fastcgi_params | 32 +++++ .../chive/chive-nginx-master/koi-utf | 109 ++++++++++++++ .../chive/chive-nginx-master/koi-win | 103 +++++++++++++ .../chive-nginx-master/map_https_fcgi.conf | 7 + .../chive/chive-nginx-master/mime.types | 77 ++++++++++ .../chive/chive-nginx-master/nginx.conf | 119 +++++++++++++++ .../chive-nginx-master/reverse_proxy.conf | 10 ++ .../sites-available/000-default | 19 +++ .../sites-available/chive.example.com.conf | 102 +++++++++++++ .../secure.chive.example.com.conf | 135 ++++++++++++++++++ .../upstream_phpapache.conf | 8 ++ .../chive-nginx-master/upstream_phpcgi.conf | 8 ++ .../chive/chive-nginx-master/win-utf | 126 ++++++++++++++++ .../cms-made-simple/nginx.conf | 17 +++ .../codeigniter/nginx-alt.conf | 25 ++++ .../codeigniter/nginx.conf | 22 +++ .../contao/sites-available/example.com.vhost | 41 ++++++ .../cs-cart/sites-available/example.com.vhost | 65 +++++++++ .../djangofastcgi/large.conf | 98 +++++++++++++ .../djangofastcgi/nginx.conf | 34 +++++ .../dokuwiki/dokuwiki.conf | 30 ++++ .../dokuwiki/drop.conf | 4 + .../dokuwiki/full.conf | 61 ++++++++ .../dokuwiki/nginx-no-ssl.conf | 29 ++++ .../dokuwiki/nginx.conf | 30 ++++ .../drupal/nginx.conf | 95 ++++++++++++ .../dynamic_ssi/nginx.conf | 39 +++++ .../nginx-roundtrip-testdata/elgg/nginx.conf | 84 +++++++++++ .../embeddedperlminifyjs/nginx.conf | 19 +++ .../embeddedperlsitemapsproxy/nginx.conf | 29 ++++ .../expressionengine/bad.conf | 24 ++++ .../expressionengine/better.conf | 24 ++++ .../expressionengine/yourpath.conf | 37 +++++ .../fastcgiexample/fastcgi.conf | 18 +++ .../fastcgiexample/nginx.conf | 6 + .../sites-available/www.example.com.vhost | 33 +++++ .../full-example/fastcgi.conf | 21 +++ .../full-example/mime.types | 48 +++++++ .../full-example/nginx.conf | 70 +++++++++ .../full-example/proxy.conf | 10 ++ .../fullexample2/nginx.conf | 126 ++++++++++++++++ .../nginx-roundtrip-testdata/geoip/nginx.conf | 9 ++ .../guide-to-nginx-ssl-spdy-hsts/nginx.conf | 120 ++++++++++++++++ .../hardwarelberrors/nginx.conf | 22 +++ .../sites-available/www.example.com.vhost | 66 +++++++++ .../nginx.conf | 39 +++++ .../nginx.conf | 27 ++++ .../imapproxyexample/nginx.conf | 38 +++++ .../imapproxyexample/proxy-example.conf | 20 +++ .../iphone-website-with-nginx/mobile.conf | 37 +++++ .../iphone-website-with-nginx/nginx.conf | 33 +++++ .../iredmail/iredadmin.conf | 31 ++++ .../iredmail/nginx.conf | 43 ++++++ .../javaservers/nginx.conf | 49 +++++++ .../joomla/nginx.conf | 39 +++++ .../likeapache/nginx.conf | 11 ++ .../loadbalanceexample/nginx.conf | 16 +++ .../mailman/nginx.conf | 37 +++++ .../mediawiki/nginx.conf | 44 ++++++ .../memcachepreload/sites-available/default | 12 ++ .../minio/sites-enabled/nginx.conf | 10 ++ .../nginx-roundtrip-testdata/mono/nginx.conf | 36 +++++ .../nginx-roundtrip-testdata/mybb/nginx.conf | 27 ++++ .../nonrootwebpath/nginx.conf | 7 + .../nginx-roundtrip-testdata/omeka/nginx.conf | 50 +++++++ .../oscommerce/nginx.conf | 50 +++++++ .../osticket/nginx.conf | 71 +++++++++ .../sites-available/www.example.com.vhost | 75 ++++++++++ .../sites-available/www.example.com.vhost | 66 +++++++++ .../php-fpm/default.conf | 9 ++ .../phpbb/nginx.sample.conf | 129 +++++++++++++++++ .../phpfastcgionwindows/nginx.conf | 8 ++ .../phpfcgi/fastcgi_params | 27 ++++ .../phpfcgi/nginx.conf | 10 ++ .../phplist/nginx.conf | 44 ++++++ .../nginx-roundtrip-testdata/piwik/nginx.conf | 70 +++++++++ .../pmwiki/nginx.conf | 39 +++++ .../sites-available/www.example.com.vhost | 75 ++++++++++ .../sites-available/www.example.com.vhost | 64 +++++++++ .../pylons/nginx.vhost.conf | 11 ++ .../pyrocms/drop.conf | 4 + .../pyrocms/fastcgi_params | 31 ++++ .../pyrocms/nginx.conf | 50 +++++++ .../qwebric/redirect.conf | 6 + .../qwebric/reverse-proxy.conf | 18 +++ .../sites-available/www.example.com.vhost | 46 ++++++ .../redmine/nginx.conf | 19 +++ .../reverseproxycachingexample/nginx.conf | 14 ++ .../sites-available/example.com.vhost.conf | 46 ++++++ .../nginx.conf | 20 +++ .../server_blocks/catchall.conf | 13 ++ .../server_blocks/two.conf | 17 +++ .../server_blocks/wildcard-subdomains.conf | 31 ++++ .../sites-available/www.example.com.vhost | 75 ++++++++++ .../sites-available/www.example.com.vhost | 53 +++++++ .../silverstripe/nginx.conf | 72 ++++++++++ .../simplecgi/nginx.conf | 26 ++++ .../sites-available/www.example.com.vhost | 78 ++++++++++ .../simplepythonfcgi/fastcgi.conf | 20 +++ .../simplepythonfcgi/nginx.conf | 17 +++ .../simplerubyfcgi/nginx.conf | 32 +++++ .../nginx-roundtrip-testdata/spip/nginx.conf | 24 ++++ .../sites-available/www.example.com.vhost | 39 +++++ .../symfony/nginx.conf | 54 +++++++ .../nginx-roundtrip-testdata/symfony/old.conf | 70 +++++++++ .../symfony/oldold.conf | 50 +++++++ .../sites-available/www.example.com.vhost | 89 ++++++++++++ .../sites-available/www.example.com.vhost | 91 ++++++++++++ .../wordpress-caching/no-cache.conf | 41 ++++++ .../wordpress-caching/supercache.conf | 74 ++++++++++ .../wordpress-caching/total-cache.conf | 41 ++++++ .../totalcache-enhanced.conf | 64 +++++++++ .../wordpress/multisite-subdir.conf | 47 ++++++ .../wordpress/multisite-subdomain.conf | 39 +++++ .../wordpress/nginx.conf | 43 ++++++ .../xenforo/nginx.conf | 18 +++ .../nginx-roundtrip-testdata/yii/nginx.conf | 42 ++++++ .../nginx-roundtrip-testdata/zend/nginx.conf | 16 +++ .../zenphoto/nginx.conf | 93 ++++++++++++ .../nginx-roundtrip-testdata/zope/nginx.conf | 18 +++ certbot-compatibility-test/nginx/roundtrip.py | 34 +++++ 203 files changed, 8263 insertions(+) create mode 100644 certbot-compatibility-test/nginx/README create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10033 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10571 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10591 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10920 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10947 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11018 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11046 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11382 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-1167 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11849 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12027 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12235 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12649 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-13577 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-14402 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-14430 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15141 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15270 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15291 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15456 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15497 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15852 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-16345 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17175 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17832 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17942 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-18018 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-18069 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19334 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19639 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-1966 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19791 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19955 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-21369 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-21549 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-230 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23325 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23470 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23791 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23803 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23838 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24125 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24193 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24213 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-25480 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26195 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26221 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26637 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26758 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27646 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27728 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27736 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27812 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-28050 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-28690 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-29159 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-2951 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-30011 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-30571 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-31900 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32190 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32279 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32317 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32438 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3483 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3507 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3874 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4035 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4143 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4264 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-5826 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-5872 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-6228 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-7895 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8343 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8422 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8637 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8662 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-9426 create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/activecolab/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/fastcgi.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/fastcgi_params create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/koi-utf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/koi-win create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/map_https_fcgi.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/mime.types create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/reverse_proxy.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/sites-available/000-default create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/sites-available/chive.example.com.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/sites-available/secure.chive.example.com.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/upstream_phpapache.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/upstream_phpcgi.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/win-utf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/cms-made-simple/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/codeigniter/nginx-alt.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/codeigniter/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/contao/sites-available/example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/cs-cart/sites-available/example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/djangofastcgi/large.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/djangofastcgi/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/dokuwiki/dokuwiki.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/dokuwiki/drop.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/dokuwiki/full.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/dokuwiki/nginx-no-ssl.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/dokuwiki/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/drupal/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/dynamic_ssi/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/elgg/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/embeddedperlminifyjs/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/embeddedperlsitemapsproxy/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/expressionengine/bad.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/expressionengine/better.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/expressionengine/yourpath.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/fastcgiexample/fastcgi.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/fastcgiexample/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/fengoffice/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/full-example/fastcgi.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/full-example/mime.types create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/full-example/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/full-example/proxy.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/fullexample2/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/geoip/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/guide-to-nginx-ssl-spdy-hsts/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/hardwarelberrors/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/icinga/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/imapauthenticatewithapacheperlscript/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/imapauthenticatewithapachephpscript/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/imapproxyexample/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/imapproxyexample/proxy-example.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/iphone-website-with-nginx/mobile.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/iphone-website-with-nginx/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/iredmail/iredadmin.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/iredmail/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/javaservers/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/joomla/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/likeapache/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/loadbalanceexample/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/mailman/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/mediawiki/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/memcachepreload/sites-available/default create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/minio/sites-enabled/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/mono/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/mybb/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/nonrootwebpath/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/omeka/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/oscommerce/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/osticket/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/owncloud/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/oxid-eshop/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/php-fpm/default.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/phpbb/nginx.sample.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/phpfastcgionwindows/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/phpfcgi/fastcgi_params create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/phpfcgi/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/phplist/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/piwik/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/pmwiki/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/prestashop/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/processwire/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/pylons/nginx.vhost.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/pyrocms/drop.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/pyrocms/fastcgi_params create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/pyrocms/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/qwebric/redirect.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/qwebric/reverse-proxy.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/redaxo/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/redmine/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/reverseproxycachingexample/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/roundcube/sites-available/example.com.vhost.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/separateerrorloggingpervirtualhost/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/server_blocks/catchall.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/server_blocks/two.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/server_blocks/wildcard-subdomains.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/shopware/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/shopware4/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/silverstripe/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/simplecgi/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/simplegroupware/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/simplepythonfcgi/fastcgi.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/simplepythonfcgi/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/simplerubyfcgi/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/spip/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/sugarcrm/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/symfony/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/symfony/old.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/symfony/oldold.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/typo3-4.6/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/typo3-6.2/sites-available/www.example.com.vhost create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/wordpress-caching/no-cache.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/wordpress-caching/supercache.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/wordpress-caching/total-cache.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/wordpress-caching/totalcache-enhanced.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/wordpress/multisite-subdir.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/wordpress/multisite-subdomain.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/wordpress/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/xenforo/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/yii/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/zend/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/zenphoto/nginx.conf create mode 100644 certbot-compatibility-test/nginx/nginx-roundtrip-testdata/zope/nginx.conf create mode 100644 certbot-compatibility-test/nginx/roundtrip.py diff --git a/certbot-compatibility-test/nginx/README b/certbot-compatibility-test/nginx/README new file mode 100644 index 000000000..f32de2148 --- /dev/null +++ b/certbot-compatibility-test/nginx/README @@ -0,0 +1,27 @@ +Eventually there will also be a compatibility test here like the Apache one. + +Right now, this is data for the roundtrip test (checking that the parser +can parse each file and that the reserialized config file it generates is +identical to the original). + +If run in a virtualenv or otherwise so that certbot_nginx can be imported, +the roundtrip test can run as + +python roundtrip.py nginx-roundtrip-testdata + +It gives exit status 0 for success and 1 if at least one parse or roundtrip +failure occurred. + + +The directory nginx-roundtrip-testdata includes some config files that were +contributed to our project as well as most of the configs linked from + +https://www.nginx.com/resources/wiki/start/ + +Some exceptions that were skipped are + +https://www.nginx.com/resources/wiki/start/topics/recipes/moinmoin/ +https://www.nginx.com/resources/wiki/start/topics/examples/SSL-Offloader/ (not much nginx configuration) +https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/ (likewise) +https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/ +https://www.nginx.com/resources/wiki/start/topics/examples/fcgiwrap/ diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10033 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10033 new file mode 100644 index 000000000..19dc49444 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10033 @@ -0,0 +1,34 @@ +upstream django_server_random18709.example.org { + server unix:/srv/http/random22194/live/website.sock; +} + +server { + listen 80; + server_name random18709.example.org; + + location /media/ { + alias /srv/http/random22194/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random22194/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random18709.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random22194/live/access.log combined_plus; + error_log /var/log/nginx/random22194/live/error.log; +} + +server { + server_name www.random18709.example.org; + server_name random24607.example.org www.random24607.example.org; + return 301 http://random18709.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10571 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10571 new file mode 100644 index 000000000..fe95ac8dc --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10571 @@ -0,0 +1,71 @@ +upstream django_server_random1413.example.org { + server unix:/srv/http/random25151/live/website.sock; +} + +server { + listen 443; + server_name www.random25266.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random25266.example.org.bundle.crt; + ssl_certificate_key /etc/ssl/private/random25266.example.org.key; + + location /media/ { + alias /srv/http/random25151/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random25151/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random1413.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random25151/live/access.log combined_plus; + error_log /var/log/nginx/random25151/live/error.log; +} + + +server { + listen 443; + server_name random1413.example.org www.random1413.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random1413.example.org.bundle.crt; + ssl_certificate_key /etc/ssl/private/random1413.example.org.key; + + location / { + return 301 https://www.random25266.example.org$request_uri; + } +} + +server { + listen 443; + server_name random25266.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random25266.example.org.bundle.crt; + ssl_certificate_key /etc/ssl/private/random25266.example.org.key; + + location / { + return 301 https://www.random25266.example.org$request_uri; + } +} + +server { + listen 80; + server_name random1413.example.org www.random1413.example.org; + server_name random28524.example.org www.random28524.example.org; + server_name random25266.example.org www.random25266.example.org; + server_name random26791.example.org www.random26791.example.org; + + location / { + return 301 https://www.random25266.example.org$request_uri; + } +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10591 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10591 new file mode 100644 index 000000000..103b56009 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10591 @@ -0,0 +1,38 @@ +upstream django_server_random11921.example.org { + server unix:/srv/http/random9726/acceptance/website.sock; +} + +server { + listen 80; + server_name random11921.example.org www.random11921.example.org; + + if ($host != 'random11921.example.org') { + rewrite ^/(.*)$ http://random11921.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random9726/acceptance/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random9726/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random11921.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + error_page 502 503 504 /50x.html; + } + + location /50x.html { + root /usr/share/nginx/www/; + } + + access_log /var/log/nginx/random9726/acceptance/access.log combined_plus; + error_log /var/log/nginx/random9726/acceptance/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10920 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10920 new file mode 100644 index 000000000..0f7c55762 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10920 @@ -0,0 +1,16 @@ +server { + listen 80 default; + + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $host; + proxy_pass http://127.0.0.1:81; + } + + location ~ /\.ht { + deny all; + } + + access_log /var/log/nginx/random27802/access.log combined_plus; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10947 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10947 new file mode 100644 index 000000000..a09605d03 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-10947 @@ -0,0 +1,40 @@ +upstream django_server_acceptance.random8289.random17507.example.org { + server unix:/srv/http/random8289/acceptance/website.sock; +} + +server { + listen 80; + server_name random23045.example.org; + + location /media/ { + alias /srv/http/random8289/acceptance/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random8289/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_acceptance.random8289.random17507.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + + satisfy any; + auth_basic 'random8289 acceptance'; + auth_basic_user_file /srv/http/random8289/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random8289/acceptance/access.log combined_plus; + error_log /var/log/nginx/random8289/acceptance/error.log; +} + +server { + server_name www.random23045.example.org; + return 301 http://random23045.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11018 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11018 new file mode 100644 index 000000000..8aceca7ca --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11018 @@ -0,0 +1,37 @@ +upstream django_server_random24036.example.org { + server unix:/srv/http/random1006/live/website.sock; +} + +server { + listen 80; + server_name random24036.example.org; + gzip on; + gzip_http_version 1.0; + gzip_types *; + gzip_vary on; + gzip_proxied any; + + location ~ /media/(.*)$ { + alias /srv/http/random1006/live/website/static/$1; + expires 7d; + gzip on; + } + + + location / { + proxy_pass http://django_server_random24036.example.org; + include /etc/nginx/proxy_params; + + # You can configure access rules here + } + + access_log /var/log/nginx/random1006/live/access.log combined_plus; + error_log /var/log/nginx/random1006/live/error.log; +} + +server { + server_name www.random24036.example.org; + server_name random32349.example.org www.random32349.example.org; + server_name random23794.example.org www.random23794.example.org; + rewrite ^ http://random24036.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11046 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11046 new file mode 100644 index 000000000..1d81e5b52 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11046 @@ -0,0 +1,36 @@ +upstream django_server_random25979.example.org { + server unix:/srv/http/random24211/internal/website.sock; +} + +server { + listen 80; + server_name random25979.example.org; + + location ^~ /media/ { + alias /srv/http/random24211/internal/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random24211/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random25979.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'internal for random24211'; + auth_basic_user_file /srv/http/random24211/internal/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random24211/internal/access.log combined_plus; + error_log /var/log/nginx/random24211/internal/error.log; +} + +server { + server_name www.random25979.example.org; + rewrite ^ http://intern.random24211.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11382 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11382 new file mode 100644 index 000000000..0dc1af725 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11382 @@ -0,0 +1,29 @@ +server { + listen 80; + listen 7891; # User0 + listen 8080; # User1 + listen 8900; # User2 + listen 8912; # User3 + listen 3567; # User4 + + server_name random666.example.org www.random666.example.org; + + root /srv/http/random666.example.org; + index index.html index.htm; + + location /duif_assets/ { + try_files $uri $uri/ =404; + } + + location /index.html { + try_files $uri $uri/ =404; + } + + location / { + rewrite ^.+$ / break; + try_files $uri $uri/ =404; + } + + access_log /var/log/nginx/random666.example.org/access.log combined_plus; + error_log /var/log/nginx/random666.example.org/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-1167 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-1167 new file mode 100644 index 000000000..13210b056 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-1167 @@ -0,0 +1,38 @@ +upstream django_server_random23900.example.org { + server unix:/srv/http/random29467/acceptance/website.sock; +} + +server { + listen 80; + server_name random23900.example.org www.random23900.example.org; + + if ($host != 'random23900.example.org') { + rewrite ^/(.*)$ http://random23900.example.org/$1 permanent; + } + + location ^~ /media/ { + alias /srv/http/random29467/acceptance/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location ^~ /static/ { + alias /srv/http/random29467/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random23900.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + satisfy any; + allow 89.188.25.162; + auth_basic "random29467 acceptance"; + auth_basic_user_file htpasswords/random29467_acceptance; + + } + + access_log /var/log/nginx/random29467/acceptance/access.log combined_plus; + error_log /var/log/nginx/random29467/acceptance/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11849 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11849 new file mode 100644 index 000000000..8a8c90b7e --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-11849 @@ -0,0 +1,36 @@ +upstream django_server_random3140.example.org { + server unix:/srv/http/random2912/live/website.sock; +} + +server { + listen 80; + server_name random3140.example.org; + + location ^~ /media/ { + alias /srv/http/random2912/live/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random2912/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random3140.example.org; + include /etc/nginx/proxy_params; + + # You can configure access rules here + } + + access_log /var/log/nginx/random2912/live/access.log combined_plus; + error_log /var/log/nginx/random2912/live/error.log; +} + +server { + server_name www.random3140.example.org; + server_name random28398.example.org; + server_name random23689.example.org www.random23689.example.org; + server_name random25863.example.org www.random25863.example.org; + + rewrite ^ http://random3140.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12027 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12027 new file mode 100644 index 000000000..9d74e2098 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12027 @@ -0,0 +1,29 @@ +upstream django_server_random6410.example.org { + server unix:/srv/http/random28641/live/website.sock; +} + +server { + listen 80; + server_name www.random6410.example.org; + + location ~ /static/(.*)$ { + alias /srv/http/random28641/live/website/static/$1; + expires 7d; + } + + location / { + proxy_pass http://django_server_random6410.example.org; + include /etc/nginx/proxy_params; + + proxy_connect_timeout 240; + proxy_read_timeout 240; + } + + access_log /var/log/nginx/random28641/live/access.log combined_plus; + error_log /var/log/nginx/random28641/live/error.log; +} + +server { + server_name random6410.example.org; + rewrite ^ http://www.random6410.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12235 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12235 new file mode 100644 index 000000000..17ba72db4 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12235 @@ -0,0 +1,33 @@ +server { + server_name random18267.example.org; + gzip on; + gzip_min_length 2000; + gzip_proxied any; + gzip_types application/json; + + client_max_body_size 30M; + + root /srv/http/random23264/data; + + # Security + satisfy any; + include /etc/nginx/allow_ytec_ips_params; + deny all; + + # try serving docs and (md5/immutable) directly + location ~ \+(f|doc)/ { + try_files $uri @proxy_to_app; + } + location / { + # XXX how to tell nginx to just refer to @proxy_to_app here? + try_files /.lqkwje @proxy_to_app; + } + location @proxy_to_app { + proxy_pass http://random20604.example.org:4040; + proxy_set_header X-outside-url $scheme://$host; + proxy_set_header X-Real-IP $remote_addr; + } + + access_log /var/log/nginx/random23264/access.log combined_plus; + error_log /var/log/nginx/random23264/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12649 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12649 new file mode 100644 index 000000000..af5a22620 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-12649 @@ -0,0 +1,45 @@ +upstream django_server_random10305.example.org { + server unix:/srv/http/random23322/live/website.sock; +} + +server { + listen 80; + server_name random10305.example.org; + + location /media/ { + alias /srv/http/random23322/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random23322/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random10305.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random23322/live/access.log combined_plus; + error_log /var/log/nginx/random23322/live/error.log; +} + +server { + listen 80; + + server_name random13399.example.org; + server_name www.random10305.example.org; + server_name random17958.example.org www.random17958.example.org; + server_name random15266.example.org www.random15266.example.org; + server_name random21296.example.org www.random21296.example.org; + server_name random5261.example.org www.random5261.example.org; + server_name random679.example.org www.random679.example.org; + server_name random31788.example.org www.random31788.example.org; + server_name random22704.example.org www.random22704.example.org; + server_name random17411.example.org www.random17411.example.org; + + return 301 http://random10305.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-13577 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-13577 new file mode 100644 index 000000000..d7a17f76e --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-13577 @@ -0,0 +1,38 @@ +upstream django_server_random30837.example.org { + server unix:/srv/http/random30992/live/website.sock; +} + +server { + listen 80; + server_name www.random30837.example.org; + + location ^~ /media/ { + alias /srv/http/random30992/live/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random30992/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random30837.example.org; + include /etc/nginx/proxy_params; + + # You can configure access rules here + } + + access_log /var/log/nginx/random30992/live/access.log combined_plus; + error_log /var/log/nginx/random30992/live/error.log; +} + +server { + server_name random30837.example.org; + server_name random3263.example.org www.random3263.example.org; + server_name random6771.example.org www.random6771.example.org; + server_name random17696.example.org www.random17696.example.org; + server_name random7179.example.org www.random7179.example.org; + server_name random8127.example.org www.random8127.example.org; + + rewrite ^ http://www.random30837.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-14402 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-14402 new file mode 100644 index 000000000..ca9ca2f61 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-14402 @@ -0,0 +1,33 @@ +upstream django_server_random17705.example.org { + server unix:/srv/http/random8289/internal/website.sock; +} + +server { + listen 80; + server_name random17705.example.org; + + location /media/ { + alias /srv/http/random8289/internal/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random8289/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random17705.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random8289/internal/access.log combined_plus; + error_log /var/log/nginx/random8289/internal/error.log; +} + +server { + server_name www.random17705.example.org; + return 301 http://random17705.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-14430 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-14430 new file mode 100644 index 000000000..7caf7b2a4 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-14430 @@ -0,0 +1,54 @@ +upstream django_server_random17507.example.org { + server unix:/srv/http/random7740/live/website.sock; +} + +server { + listen 80; + server_name random17507.example.org; + + location ^~ /media/ { + alias /srv/http/random7740/live/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random7740/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random17507.example.org; + include /etc/nginx/proxy_params; + + # You can configure access rules here + } + + access_log /var/log/nginx/random7740/live/access.log combined_plus; + error_log /var/log/nginx/random7740/live/error.log; +} + +server { + server_name www.random17507.example.org; + server_name random31197.example.org www.random31197.example.org; + server_name random19579.example.org www.random19579.example.org; + server_name random16629.example.org www.random16629.example.org; + server_name random28363.example.org www.random28363.example.org; + server_name random30185.example.org www.random30185.example.org; + server_name random22326.example.org www.random22326.example.org; + server_name random3622.example.org www.random3622.example.org; + server_name random1463.example.org www.random1463.example.org; + server_name random23341.example.org www.random23341.example.org; + server_name random2214.example.org www.random2214.example.org; + server_name random22684.example.org www.random22684.example.org; + server_name random6606.example.org www.random6606.example.org; + server_name random29138.example.org www.random29138.example.org; + server_name random15109.example.org www.random15109.example.org; + server_name random8002.example.org www.random8002.example.org; + server_name random16836.example.org www.random16836.example.org; + server_name random22283.example.org www.random22283.example.org; + + location = /googleXXXXXXXXXXXXXXXX.html { + alias /srv/http/random7740/live/website/templates/googleXXXXXXXXXXXXXXXX.html; + } + + rewrite ^ http://random17507.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15141 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15141 new file mode 100644 index 000000000..2b2689f09 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15141 @@ -0,0 +1,36 @@ +upstream django_server_acceptatie.random20374.nl { + server unix:/srv/http/random20374/acceptance/website.sock; +} + +server { + listen 80; + server_name random28586.example.org; + + location ^~ /media/ { + alias /srv/http/random20374/acceptance/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random20374/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_acceptatie.random20374.nl; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'acceptance for random20374'; + auth_basic_user_file /srv/http/random20374/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random20374/acceptance/access.log combined_plus; + error_log /var/log/nginx/random20374/acceptance/error.log; +} + +server { + server_name www.random28586.example.org; + rewrite ^ http://random28586.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15270 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15270 new file mode 100644 index 000000000..b4f4bd61c --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15270 @@ -0,0 +1,38 @@ +upstream django_server_random6822.example.org { + server unix:/srv/http/random7047/live/website.sock; +} + +server { + listen 8443; + server_name random6822.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random6822.example.org.complete-bundle.crt; + ssl_certificate_key /etc/ssl/private/random6822.example.org.key; + + location /media/ { + alias /srv/http/random7047/live/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random7047/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random6822.example.org; + include /etc/nginx/proxy_params; + } + + access_log /var/log/nginx/random7047/live/access.log combined_plus; + error_log /var/log/nginx/random7047/live/error.log; +} + +server { + listen 80; + server_name random6822.example.org; + + rewrite ^/(.*) https://random6822.example.org:8443/$1; +} + + diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15291 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15291 new file mode 100644 index 000000000..fa09bed93 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15291 @@ -0,0 +1,112 @@ +# You may add here your +# server { +# ... +# } +# statements for each of your virtual hosts to this file + +## +# You should look at the following URL's in order to grasp a solid understanding +# of Nginx configuration files in order to fully unleash the power of Nginx. +# http://wiki.nginx.org/Pitfalls +# http://wiki.nginx.org/QuickStart +# http://wiki.nginx.org/Configuration +# +# Generally, you will want to move this file somewhere, and start with a clean +# file but keep this around for reference. Or just disable in sites-enabled. +# +# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. +## + +server { + listen 80 default_server; + listen [::]:80 default_server ipv6only=on; + + root /usr/share/nginx/html; + index index.html index.htm; + + # Make site accessible from http://random20604.example.org/ + server_name random20604.example.org; + + location / { + # First attempt to serve request as file, then + # as directory, then fall back to displaying a 404. + try_files $uri $uri/ =404; + # Uncomment to enable naxsi on this location + # include /etc/nginx/naxsi.rules + } + + # Only for nginx-naxsi used with nginx-naxsi-ui : process denied requests + #location /RequestDenied { + # proxy_pass http://127.0.0.1:8080; + #} + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + #error_page 500 502 503 504 /50x.html; + #location = /50x.html { + # root /usr/share/nginx/html; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + #location ~ \.php$ { + # fastcgi_split_path_info ^(.+\.php)(/.+)$; + # # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini + # + # # With php5-cgi alone: + # fastcgi_pass 127.0.0.1:9000; + # # With php5-fpm: + # fastcgi_pass unix:/var/run/php5-fpm.sock; + # fastcgi_index index.php; + # include fastcgi_params; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} +} + + +# another virtual host using mix of IP-, name-, and port-based configuration +# +#server { +# listen 8000; +# listen random20605.example.org:8080; +# server_name random20605.example.org alias another.alias; +# root html; +# index index.html index.htm; +# +# location / { +# try_files $uri $uri/ =404; +# } +#} + + +# HTTPS server +# +#server { +# listen 443; +# server_name random20604.example.org; +# +# root html; +# index index.html index.htm; +# +# ssl on; +# ssl_certificate cert.pem; +# ssl_certificate_key cert.key; +# +# ssl_session_timeout 5m; +# +# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; +# ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES"; +# ssl_prefer_server_ciphers on; +# +# location / { +# try_files $uri $uri/ =404; +# } +#} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15456 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15456 new file mode 100644 index 000000000..273694b51 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15456 @@ -0,0 +1,39 @@ +upstream django_server_random29275.example.org { + server unix:/srv/http/random14353/internal/website.sock; +} + +server { + listen 80; + server_name random29275.example.org; + + location /media/ { + alias /srv/http/random14353/internal/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random14353/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random29275.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + + satisfy any; + auth_basic 'internal for random14353'; + auth_basic_user_file /srv/http/random14353/internal/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random14353/internal/access.log; + error_log /var/log/nginx/random14353/internal/error.log; +} + +server { + server_name www.random29275.example.org; + return 301 http://random29275.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15497 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15497 new file mode 100644 index 000000000..86a8980d2 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15497 @@ -0,0 +1,35 @@ +upstream django_server_random16112.example.org { + server unix:/srv/http/random29227/live/website.sock; +} + +server { + listen 80; + server_name random16112.example.org; + + location /media/ { + alias /srv/http/random29227/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random29227/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random16112.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random29227/live/access.log combined_plus; + error_log /var/log/nginx/random29227/live/error.log; +} +server { + server_name random5297.example.org www.random5297.example.org; + server_name random17050.example.org www.random17050.example.org; + server_name www.random16112.example.org; + + return 301 http://random16112.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15852 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15852 new file mode 100644 index 000000000..32b88c62f --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-15852 @@ -0,0 +1,38 @@ +upstream django_server_random7474.example.org { + server unix:/srv/http/random4886/acceptance/website.sock; +} + +server { + listen 80; + server_name random7474.example.org; + + location /media/ { + alias /srv/http/random4886/acceptance/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random4886/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random7474.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'acceptance for random4886'; + auth_basic_user_file /srv/http/random4886/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + client_max_body_size 20m; + + access_log /var/log/nginx/random4886/acceptance/access.log; + error_log /var/log/nginx/random4886/acceptance/error.log; +} + +server { + server_name www.random7474.example.org; + return 301 http://random7474.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-16345 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-16345 new file mode 100644 index 000000000..ac8ce609c --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-16345 @@ -0,0 +1,34 @@ +upstream django_server_random25713.example.org { + server unix:/srv/http/random24922/live/website.sock; +} + +server { + listen 80; + server_name random25713.example.org; + + location /media/ { + alias /srv/http/random24922/live/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random24922/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random25713.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random24922/live/access.log; + error_log /var/log/nginx/random24922/live/error.log; +} + +server { + server_name www.random25713.example.org; + return 301 http://random25713.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17175 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17175 new file mode 100644 index 000000000..e733a70ed --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17175 @@ -0,0 +1,14 @@ +server { + listen 80; + server_name random25647.example.org www.random25647.example.org random10963.example.org www.random10963.example.org; + + if ($host != 'random25647.example.org') { + rewrite ^/(.*)$ http://random25647.example.org/$1 permanent; + } + + index index.html index.htm; + root /srv/http/random11461/countdown/; + + access_log /var/log/nginx/random11461/live/access.log combined_plus; + error_log /var/log/nginx/random11461/live/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17832 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17832 new file mode 100644 index 000000000..4a0967de8 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17832 @@ -0,0 +1,32 @@ +upstream django_server_random6430.example.org { + server unix:/srv/http/random550/internal/website.sock; +} + +server { + listen 80; + server_name random6430.example.org; + + location /media/ { + alias /srv/http/random550/internal/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random550/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random6430.example.org; + include /etc/nginx/django_proxy_params; + + } + + access_log /var/log/nginx/random550/internal/access.log combined_plus; + error_log /var/log/nginx/random550/internal/error.log; +} + +server { + server_name www.random6430.example.org; + return 301 http://random6430.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17942 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17942 new file mode 100644 index 000000000..a3b10eed6 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-17942 @@ -0,0 +1,32 @@ +upstream django_server_random25647.example.org { + server unix:/srv/http/random11461/live/website.sock; +} + +server { + listen 80; + server_name random25647.example.org www.random25647.example.org random10963.example.org www.random10963.example.org; + + if ($host != 'random25647.example.org') { + rewrite ^/(.*)$ http://random25647.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random11461/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random11461/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random25647.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random11461/live/access.log combined_plus; + error_log /var/log/nginx/random11461/live/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-18018 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-18018 new file mode 100644 index 000000000..63b68d6ff --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-18018 @@ -0,0 +1,36 @@ +upstream django_server_intern.random20374.nl { + server unix:/srv/http/random20374/internal/website.sock; +} + +server { + listen 80; + server_name random23818.example.org; + + location ^~ /media/ { + alias /srv/http/random20374/internal/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random20374/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_intern.random20374.nl; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'internal for random20374'; + auth_basic_user_file /srv/http/random20374/internal/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random20374/internal/access.log combined_plus; + error_log /var/log/nginx/random20374/internal/error.log; +} + +server { + server_name www.random23818.example.org; + rewrite ^ http://random23818.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-18069 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-18069 new file mode 100644 index 000000000..d6d4e5bea --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-18069 @@ -0,0 +1,39 @@ +upstream django_server_random7949.example.org { + server unix:/srv/http/random1006/acceptance/website.sock; +} + +server { + listen 80; + server_name random7949.example.org; + gzip on; + gzip_http_version 1.0; + gzip_types *; + gzip_vary on; + gzip_proxied any; + + location ~ /media/(.*)$ { + alias /srv/http/random1006/acceptance/website/static/$1; + expires 7d; + gzip on; + } + + + location / { + proxy_pass http://django_server_random7949.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'acceptance for random1006'; + auth_basic_user_file /srv/http/random1006/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random1006/acceptance/access.log combined_plus; + error_log /var/log/nginx/random1006/acceptance/error.log; +} + +server { + server_name www.random7949.example.org; + rewrite ^ http://random7949.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19334 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19334 new file mode 100644 index 000000000..2609e2080 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19334 @@ -0,0 +1,39 @@ +upstream django_server_random1515.example.org { + server unix:/srv/http/random15255/acceptance/website.sock fail_timeout=5; +} + +server { + listen 80; + server_name random1515.example.org www.random1515.example.org; + + if ($host != 'random1515.example.org') { + rewrite ^/(.*)$ http://random1515.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random15255/acceptance/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random15255/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random1515.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + + satisfy any; + auth_basic 'random191 acceptance'; + auth_basic_user_file /srv/http/random15255/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random15255/acceptance/access.log combined_plus; + error_log /var/log/nginx/random15255/acceptance/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19639 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19639 new file mode 100644 index 000000000..617472e0d --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19639 @@ -0,0 +1,39 @@ +upstream django_server_live.random8289.random17507.example.org { + server unix:/srv/http/random8289/live/website.sock; +} + +server { + listen 443; + server_name random23886.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random23886.example.org.complete-bundle.crt; + ssl_certificate_key /etc/ssl/private/random23886.example.org.key; + + location /media/ { + alias /srv/http/random8289/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random8289/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_live.random8289.random17507.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + } + + access_log /var/log/nginx/random8289/live/access.log combined_plus; + error_log /var/log/nginx/random8289/live/error.log; +} + +server { + listen 80; + server_name random23886.example.org; + return 301 https://random23886.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-1966 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-1966 new file mode 100644 index 000000000..41aaef04d --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-1966 @@ -0,0 +1,36 @@ +upstream django_server_random31523.example.org { + server unix:/srv/http/random16722.example.org/internal/website.sock; +} + +server { + listen 80; + server_name random31523.example.org; + + location ^~ /media/ { + alias /srv/http/random16722.example.org/internal/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random16722.example.org/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random31523.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'internal for random16722.example.org'; + auth_basic_user_file /srv/http/random16722.example.org/internal/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random16722.example.org/internal/access.log combined_plus; + error_log /var/log/nginx/random16722.example.org/internal/error.log; +} + +server { + server_name www.random31523.example.org; + rewrite ^ http://random31523.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19791 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19791 new file mode 100644 index 000000000..6e3112ad8 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19791 @@ -0,0 +1,34 @@ +upstream django_server_random1413.example.org { + server unix:/srv/http/random25151/live/website.sock; +} + +server { + listen 80; + server_name random1413.example.org; + + location ^~ /media/ { + alias /srv/http/random25151/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location ^~ /static/ { + alias /srv/http/random25151/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random1413.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random25151/live/access.log combined_plus; + error_log /var/log/nginx/random25151/live/error.log; +} + +server { + server_name www.random1413.example.org; + server_name random28524.example.org www.random28524.example.org; + rewrite ^ http://random1413.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19955 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19955 new file mode 100644 index 000000000..20d718409 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-19955 @@ -0,0 +1,36 @@ +upstream django_server_random9619.example.org { + server unix:/srv/http/random28641/internal/website.sock; +} + +server { + listen 80; + server_name random9619.example.org; + + location ^~ /media/ { + alias /srv/http/random28641/internal/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random28641/internal/website/static/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random9619.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'internal for random28641'; + auth_basic_user_file /srv/http/random28641/internal/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random28641/internal/access.log combined_plus; + error_log /var/log/nginx/random28641/internal/error.log; +} + +server { + server_name www.random9619.example.org; + rewrite ^ http://random9619.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-21369 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-21369 new file mode 100644 index 000000000..5650efb4c --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-21369 @@ -0,0 +1,33 @@ +upstream django_server_random31758.example.org { + server unix:/srv/http/random21623/internal/website.sock; +} + +server { + listen 80; + server_name random31758.example.org www.random31758.example.org; + + if ($host != 'random31758.example.org') { + rewrite ^/(.*)$ http://random31758.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random21623/internal/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random21623/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random31758.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + } + + access_log /var/log/nginx/random21623/internal/access.log combined_plus; + error_log /var/log/nginx/random21623/internal/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-21549 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-21549 new file mode 100644 index 000000000..85576da76 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-21549 @@ -0,0 +1,32 @@ +upstream django_server_random1688.example.org { + server unix:/srv/http/random6470/acceptance/website.sock; +} + +server { + listen 80; + server_name random5078.example.org random1688.example.org www.random1688.example.org; + + if ($host != 'random5078.example.org') { + rewrite ^/(.*)$ http://random5078.example.org/$1 permanent; + } + + location ^~ /media/ { + alias /srv/http/random6470/acceptance/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location ^~ /static/ { + alias /srv/http/random6470/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random1688.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random6470/acceptance/access.log combined_plus; + error_log /var/log/nginx/random6470/acceptance/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-230 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-230 new file mode 100644 index 000000000..00d1d2b0b --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-230 @@ -0,0 +1,33 @@ +upstream django_server_random22746.example.org { + server unix:/srv/http/random6344/internal/website.sock; +} + +server { + listen 80; + server_name random22746.example.org; + + if ($host != 'random22746.example.org') { + rewrite ^/(.*)$ http://random22746.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random6344/internal/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random6344/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random22746.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + } + + access_log /var/log/nginx/random6344/internal/access.log combined_plus; + error_log /var/log/nginx/random6344/internal/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23325 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23325 new file mode 100644 index 000000000..5b91f0eaf --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23325 @@ -0,0 +1,74 @@ +upstream django_server_random15255_live { + server unix:/srv/http/random15255/live/website.sock fail_timeout=5; +} + +server { + listen 443; + server_name random7381.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random7381.example.org_chained.crt; + ssl_certificate_key /etc/ssl/private/random7381.example.org.key; + + location /media/ { + alias /srv/http/random15255/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + + location /static/ { + alias /srv/http/random15255/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random15255_live; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + } + + access_log /var/log/nginx/random15255/live/access.log combined_plus; + error_log /var/log/nginx/random15255/live/error.log; +} + +server { + listen 80; + server_name random7381.example.org www.random7381.example.org; + + return 301 https://random7381.example.org$request_uri; +} + +server { + listen 8445; + server_name random7381.example.org www.random7381.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random7381.example.org_chained.crt; + ssl_certificate_key /etc/ssl/private/random7381.example.org.key; + + return 301 https://random7381.example.org$request_uri; +} + +server { + listen 1000; + server_name random7381.example.org www.random7381.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random7381.example.org_chained.crt; + ssl_certificate_key /etc/ssl/private/random7381.example.org.key; + + return 301 https://random7381.example.org$request_uri; +} + +server { + listen 443; + server_name www.random7381.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random7381.example.org_chained.crt; + ssl_certificate_key /etc/ssl/private/random7381.example.org.key; + + return 301 https://random7381.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23470 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23470 new file mode 100644 index 000000000..4f78b645b --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23470 @@ -0,0 +1,56 @@ +upstream django_server_random27579.example.org { + server unix:/srv/http/random21623/live/website.sock; +} + +server { + listen 443; + server_name random27579.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random27579.example.org.bundle.crt; + ssl_certificate_key /etc/ssl/private/random27579.example.org.key; + + location /media/ { + alias /srv/http/random21623/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random21623/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random27579.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + } + + access_log /var/log/nginx/random21623/live/access.log combined_plus; + error_log /var/log/nginx/random21623/live/error.log; +} + +server { + listen 443; + server_name www.random27579.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random27579.example.org.bundle.crt; + ssl_certificate_key /etc/ssl/private/random27579.example.org.key; + + return 301 https://random27579.example.org$request_uri; +} + +server { + listen 80; + + server_name random27579.example.org www.random27579.example.org random11512.example.org; + server_name random18003.example.org www.random18003.example.org; + server_name random26730.example.org www.random26730.example.org; + server_name random3968.example.org www.random3968.example.org; + server_name random11925.example.org www.random11925.example.org; + + return 301 https://random27579.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23791 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23791 new file mode 100644 index 000000000..25933cebb --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23791 @@ -0,0 +1,33 @@ +upstream django_server_random31057.example.org { + server unix:/srv/http/random22194/acceptance/website.sock; +} + +server { + listen 80; + server_name random31057.example.org www.random31057.example.org; + + if ($host != 'random31057.example.org') { + rewrite ^/(.*)$ http://random31057.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random22194/acceptance/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random22194/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random31057.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_read_timeout 120; + } + + access_log /var/log/nginx/random22194/acceptance/access.log combined_plus; + error_log /var/log/nginx/random22194/acceptance/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23803 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23803 new file mode 100644 index 000000000..9db2c07f5 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23803 @@ -0,0 +1,32 @@ +upstream django_server_random16722.example.org { + server unix:/srv/http/random16722.example.org/live/website.sock; +} + +server { + listen 80; + server_name random16722.example.org; + + location ^~ /media/ { + alias /srv/http/random16722.example.org/live/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random16722.example.org/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random16722.example.org; + include /etc/nginx/proxy_params; + + # You can configure access rules here + } + + access_log /var/log/nginx/random16722.example.org/live/access.log combined_plus; + error_log /var/log/nginx/random16722.example.org/live/error.log; +} + +server { + server_name www.random16722.example.org; + rewrite ^ http://random16722.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23838 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23838 new file mode 100644 index 000000000..7bd3f2778 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-23838 @@ -0,0 +1,32 @@ +upstream django_server_random14388.example.org { + server unix:/srv/http/random4886/live/website.sock; +} + +server { + listen 80; + server_name random14388.example.org; + + location /media/ { + alias /srv/http/random4886/live/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random4886/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random14388.example.org; + include /etc/nginx/proxy_params; + + # You can configure access rules here + } + + access_log /var/log/nginx/random4886/live/access.log; + error_log /var/log/nginx/random4886/live/error.log; +} + +server { + server_name www.random14388.example.org; + return 301 http://random14388.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24125 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24125 new file mode 100644 index 000000000..f7efda324 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24125 @@ -0,0 +1,7 @@ +server { + listen 80; + server_name random14996.example.org; + + root /srv/http/random23392/; + index index.html; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24193 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24193 new file mode 100644 index 000000000..1d2b7ec83 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24193 @@ -0,0 +1,62 @@ +upstream django_server_random6177.example.org { + server unix:/srv/http/random550/live/website.sock; +} + +server { + listen 443 ssl; + server_name random2179.example.org; + + ssl_certificate /etc/ssl/public/random2179.example.org.bundle.crt; + ssl_certificate_key /etc/ssl/private/random2179.example.org.key; + + + location /media/ { + alias /srv/http/random550/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random550/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random6177.example.org; + include /etc/nginx/django_proxy_params; + } + + access_log /var/log/nginx/random550/live/access.log combined_plus; + error_log /var/log/nginx/random550/live/error.log; +} + +server { + listen 80; + server_name random2179.example.org; + + location /media/ { + alias /srv/http/random550/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random550/live/static_collected/; + expires 7d; + } + + #location = / { + # return 301 https://random2179.example.org$request_uri; + #} + + location / { + proxy_pass http://django_server_random6177.example.org; + include /etc/nginx/django_proxy_params; + } + + access_log /var/log/nginx/random550/live/access_http.log combined_plus; + error_log /var/log/nginx/random550/live/error_http.log; +} + +server { + server_name random6177.example.org www.random6177.example.org; + return 301 http://random2179.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24213 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24213 new file mode 100644 index 000000000..b23aeae19 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-24213 @@ -0,0 +1,36 @@ +upstream django_server_random22047.example.org { + server unix:/srv/http/random26975/acceptance/website.sock; +} + +server { + listen 80; + server_name random22047.example.org; + + location /media/ { + alias /srv/http/random26975/acceptance/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random26975/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random22047.example.org; + include /etc/nginx/django_proxy_params; + + satisfy any; + auth_basic 'acceptance for random26975'; + auth_basic_user_file /srv/http/random26975/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random26975/acceptance/access.log; + error_log /var/log/nginx/random26975/acceptance/error.log; +} + +server { + server_name www.random22047.example.org; + return 301 http://random22047.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-25480 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-25480 new file mode 100644 index 000000000..7628d27d2 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-25480 @@ -0,0 +1,32 @@ +upstream django_server_random6193.example.org { + server unix:/srv/http/random4755/live/website.sock; +} + +server { + listen 80; + server_name random6193.example.org www.random6193.example.org; + + if ($host != 'random6193.example.org') { + rewrite ^/(.*)$ http://random6193.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random4755/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random4755/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random6193.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random4755/live/access.log combined_plus; + error_log /var/log/nginx/random4755/live/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26195 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26195 new file mode 100644 index 000000000..232935a51 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26195 @@ -0,0 +1,26 @@ +server { + listen 80; + server_name www.random25446.example.org random25446.example.org; + + if ($host != 'random25446.example.org') { + rewrite ^/(.*)$ http://random25446.example.org/$1 permanent; + } + + location ^~ /media { + alias /srv/http/random17476/internal/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location ^~ /static { + alias /srv/http/random17476/internal/static_collected/; + expires 7d; + } + + location / { + include fastcgi_params; + fastcgi_pass unix:/srv/http/random17476/internal/website.sock; + } + + access_log /var/log/nginx/random17476/internal/access.log combined_plus; + error_log /var/log/nginx/random17476/internal/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26221 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26221 new file mode 100644 index 000000000..8e5893d61 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26221 @@ -0,0 +1,32 @@ +upstream django_server_random4030.example.org { + server unix:/srv/http/random26975/live/website.sock; +} + +server { + listen 80; + server_name random4030.example.org; + + location /media/ { + alias /srv/http/random26975/live/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random26975/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random4030.example.org; + include /etc/nginx/django_proxy_params; + + # You can configure access rules here + } + + access_log /var/log/nginx/random26975/live/access.log; + error_log /var/log/nginx/random26975/live/error.log; +} + +server { + server_name www.random4030.example.org; + return 301 http://random4030.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26637 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26637 new file mode 100644 index 000000000..3ef549982 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26637 @@ -0,0 +1,32 @@ +upstream django_server_random5890.example.org { + server unix:/srv/http/random4755/internal/website.sock; +} + +server { + listen 80; + server_name random5890.example.org; + + if ($host != 'random5890.example.org') { + rewrite ^/(.*)$ http://random5890.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random4755/internal/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random4755/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random5890.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random4755/internal/access.log combined_plus; + error_log /var/log/nginx/random4755/internal/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26758 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26758 new file mode 100644 index 000000000..f7cfb854c --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-26758 @@ -0,0 +1,21 @@ +server { + listen 80 default_server; + #listen [::]:80 default_server ipv6only=on; + root /var/www/default/; + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + location ~ /\.ht { + deny all; + } + + location /nginx_status { + stub_status on; + access_log off; + allow 127.0.0.1; + deny all; + } + + access_log /var/log/nginx/access.log combined_plus; + error_log /var/log/nginx/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27646 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27646 new file mode 100644 index 000000000..9328e2943 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27646 @@ -0,0 +1,37 @@ +upstream django_server_random10783.example.org { + server unix:/srv/http/random4711/acceptance/website.sock; +} + +server { + listen 80; + server_name random10783.example.org; + + location ^~ /media/ { + alias /srv/http/random4711/acceptance/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random4711/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random10783.example.org; + include /etc/nginx/proxy_params; + proxy_read_timeout 4m; + + satisfy any; + auth_basic 'acceptance for random4711'; + auth_basic_user_file /srv/http/random4711/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random4711/acceptance/access.log combined_plus; + error_log /var/log/nginx/random4711/acceptance/error.log; +} + +server { + server_name www.random10783.example.org; + rewrite ^ http://random10783.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27728 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27728 new file mode 100644 index 000000000..fdef2900c --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27728 @@ -0,0 +1,5 @@ +server { + location =/ { + return 404; + } +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27736 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27736 new file mode 100644 index 000000000..5f579971a --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27736 @@ -0,0 +1,32 @@ +upstream django_server_random17112.example.org { + server unix:/srv/http/random29467/live/website.sock; +} + +server { + listen 80; + server_name random17112.example.org www.random17112.example.org; + + if ($host != 'random17112.example.org') { + rewrite ^/(.*)$ http://random17112.example.org/$1 permanent; + } + + location ^~ /media/ { + alias /srv/http/random29467/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location ^~ /static/ { + alias /srv/http/random29467/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random17112.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random29467/live/access.log combined_plus; + error_log /var/log/nginx/random29467/live/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27812 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27812 new file mode 100644 index 000000000..8e455eb9b --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-27812 @@ -0,0 +1,36 @@ +upstream django_server_random1296.example.org { + server unix:/srv/http/random2912/acceptance/website.sock; +} + +server { + listen 80; + server_name random1296.example.org; + + location ^~ /media/ { + alias /srv/http/random2912/acceptance/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random2912/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random1296.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'acceptance for random2912'; + auth_basic_user_file /srv/http/random2912/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random2912/acceptance/access.log combined_plus; + error_log /var/log/nginx/random2912/acceptance/error.log; +} + +server { + server_name www.random1296.example.org; + rewrite ^ http://random1296.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-28050 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-28050 new file mode 100644 index 000000000..3d0ac97ae --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-28050 @@ -0,0 +1,36 @@ +upstream django_server_random11685.example.org { + server unix:/srv/http/random4886/internal/website.sock; +} + +server { + listen 80; + server_name random11685.example.org; + + location /media/ { + alias /srv/http/random4886/internal/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random4886/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random11685.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'internal for random4886'; + auth_basic_user_file /srv/http/random4886/internal/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random4886/internal/access.log; + error_log /var/log/nginx/random4886/internal/error.log; +} + +server { + server_name www.random11685.example.org; + return 301 http://random11685.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-28690 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-28690 new file mode 100644 index 000000000..69bcb26c0 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-28690 @@ -0,0 +1,32 @@ +upstream django_server_random16112.example.org { + server unix:/srv/http/random24645/live/website.sock; +} + +server { + listen 80; + server_name random16112.example.org; + + location ^~ /media/ { + alias /srv/http/random24645/live/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random24645/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random16112.example.org; + include /etc/nginx/proxy_params; + + # You can configure access rules here + } + + access_log /var/log/nginx/random24645/live/access.log; + error_log /var/log/nginx/random24645/live/error.log; +} + +server { + server_name www.random16112.example.org; + rewrite ^ http://random16112.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-29159 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-29159 new file mode 100644 index 000000000..be6481eae --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-29159 @@ -0,0 +1,33 @@ +upstream django_server_random29198.example.org { + server unix:/srv/http/random28641/acceptance/website.sock; +} + +server { + listen 80; + server_name random29198.example.org; + + location ~ /static/(.*)$ { + alias /srv/http/random28641/acceptance/website/static/$1; + expires 7d; + } + + + location / { + proxy_pass http://django_server_random29198.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'acceptance for random28641'; + auth_basic_user_file /srv/http/random28641/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random28641/acceptance/access.log combined_plus; + error_log /var/log/nginx/random28641/acceptance/error.log; +} + +server { + server_name www.random29198.example.org; + rewrite ^ http://random29198.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-2951 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-2951 new file mode 100644 index 000000000..683aa3226 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-2951 @@ -0,0 +1,67 @@ +server { + listen 80; + #listen [::]:80 default_server ipv6only=on; + root /var/www/random616_log/; + server_name random12800.example.org; + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini + + # With php5-fpm: + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_index index.php; + include fastcgi_params; + } + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + location ~ /\.ht { + deny all; + } + + location /nginx_status { + stub_status on; + access_log off; + allow 127.0.0.1; + deny all; + } + + access_log /var/log/nginx/random12543/access.log combined_plus; + error_log /var/log/nginx/random12543/error.log; +} + +server { + listen 443 default_server; + #listen [::]:443 default_server ipv6only=on; + root /var/www/random616_log/; + server_name random12800.example.org; + + # We created (will create) this SSL certificate ourselves, using our own CA. This way, we can control strictly which CA the XXX trusts. + # See ytec #6244 + # However, we're working on a fix for high SSL overhead. We're hoping to be able to keep the connections open between log POSTs, like SSL can. + ssl on; + ssl_certificate /etc/ssl/public/random12800.example.org.crt; + ssl_certificate_key /etc/ssl/private/random12800.example.org.key; + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini + + # With php5-fpm: + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_index index.php; + include fastcgi_params; + } + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + location ~ /\.ht { + deny all; + } + + access_log /var/log/nginx/random12543/access.log combined_plus; + error_log /var/log/nginx/random12543/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-30011 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-30011 new file mode 100644 index 000000000..479edac5d --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-30011 @@ -0,0 +1,37 @@ +upstream django_server_random12785.example.org { + server unix:/srv/http/random14353/live/website.sock; +} + +server { + listen 80; + server_name random12785.example.org; + + location /media/ { + alias /srv/http/random14353/live/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random14353/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random12785.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + + satisfy any; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random14353/live/access.log; + error_log /var/log/nginx/random14353/live/error.log; +} + +server { + server_name www.random12785.example.org; + return 301 http://random12785.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-30571 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-30571 new file mode 100644 index 000000000..84e44dd7c --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-30571 @@ -0,0 +1,31 @@ +upstream django_server_random7150.example.org { + server unix:/srv/http/random550/acceptance/website.sock; +} + +server { + listen 80; + server_name random7150.example.org; + + location /media/ { + alias /srv/http/random550/acceptance/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random550/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random7150.example.org; + include /etc/nginx/django_proxy_params; + } + + access_log /var/log/nginx/random550/acceptance/access.log combined_plus; + error_log /var/log/nginx/random550/acceptance/error.log; +} + +server { + server_name www.random7150.example.org; + return 301 http://random7150.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-31900 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-31900 new file mode 100644 index 000000000..648693cbc --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-31900 @@ -0,0 +1,33 @@ +upstream django_server_random31131.example.org { + server unix:/srv/http/random24334/internal/website.sock; +} + +server { + listen 80; + server_name random31131.example.org; + + location /media/ { + alias /srv/http/random24334/internal/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random24334/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random31131.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random24334/internal/access.log combined_plus; + error_log /var/log/nginx/random24334/internal/error.log; +} + +server { + server_name www.random31131.example.org; + return 301 http://random31131.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32190 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32190 new file mode 100644 index 000000000..8c7738c03 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32190 @@ -0,0 +1,4 @@ +server { + server_name www.random5115; + return 301 http://www.random10305.example.org; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32279 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32279 new file mode 100644 index 000000000..16f4e5e9e --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32279 @@ -0,0 +1,25 @@ +server { + listen 80; + root /home/admin/random19651_log/; + server_name random16339.example.org; + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini + + # With php5-fpm: + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_index index.php; + include fastcgi_params; + } + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + location ~ /\.ht { + deny all; + } + + access_log /var/log/nginx/random4235/access.log combined_plus; + error_log /var/log/nginx/random4235/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32317 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32317 new file mode 100644 index 000000000..e9c986ff1 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32317 @@ -0,0 +1,32 @@ +upstream django_server_random21989.example.org { + server unix:/srv/http/random28136/acceptance/website.sock; +} + +server { + listen 80; + server_name random21989.example.org; + + location ~ /static/(.*)$ { + alias /srv/http/random28136/acceptance/website/static/$1; + expires 7d; + } + + location / { + proxy_pass http://django_server_random21989.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'acceptance for random28136'; + auth_basic_user_file /srv/http/random28136/acceptance/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random28136/acceptance/access.log combined_plus; + error_log /var/log/nginx/random28136/acceptance/error.log; +} + +server { + server_name www.random21989.example.org; + rewrite ^ http://random21989.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32438 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32438 new file mode 100644 index 000000000..66929620f --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-32438 @@ -0,0 +1,46 @@ +upstream django_server_random1769.example.org { + server unix:/srv/http/random7047/acceptance/website.sock; +} + +server { + listen 80; + server_name random1769.example.org; + + if ($host != 'random1769.example.org') { + rewrite ^/(.*)$ http://random1769.example.org/$1 permanent; + } + + rewrite ^/(.*) https://$host:8444/$1; +} + +server { + listen 8444; + server_name random1769.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random6822.example.org.crt; + ssl_certificate_key /etc/ssl/private/random6822.example.org.key; + + location ^~ /media/ { + alias /srv/http/random7047/acceptance/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random7047/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random1769.example.org; + include /etc/nginx/proxy_params; + + #satisfy any; + #auth_basic 'acceptance for random7047'; + #auth_basic_user_file /srv/http/random7047/acceptance/htpasswords; + #include /etc/nginx/allow_ytec_ips_params; + #deny all; + } + + access_log /var/log/nginx/random7047/acceptance/access.log combined_plus; + error_log /var/log/nginx/random7047/acceptance/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3483 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3483 new file mode 100644 index 000000000..7a415c293 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3483 @@ -0,0 +1,32 @@ +server { + listen 80; + server_name random9761.example.org; + + + location ~ /static/(.*)$ { + alias /srv/http/random14537/static_collected/$1; + expires 7d; + } + + location ~ /media/(.*)$ { + alias /srv/http/random14537/dynamic/public/$1; + expires 7d; + include upload_folder_security_params; + } + + + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $host; + proxy_pass http://127.0.0.1:81; + proxy_connect_timeout 120; + proxy_read_timeout 120; + } + + location ~ /\.ht { + deny all; + } + + access_log /var/log/nginx/random14537/access.log combined_plus; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3507 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3507 new file mode 100644 index 000000000..0fdca78d7 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3507 @@ -0,0 +1,44 @@ +server { + listen 80; + server_name random3674.example.org www.random3674.example.org; + + root /srv/http/random3674.example.org; + index index.html index.htm; + + location / { + try_files $uri $uri/ =404; + } + + access_log /var/log/nginx/random3674.example.org/access.log combined_plus; + error_log /var/log/nginx/random3674.example.org/error.log; +} + +server { + listen 80; + server_name random27569.example.org www.random27569.example.org; + + root /srv/http/random27569.example.org; + index index.html index.htm; + + location / { + try_files $uri $uri/ =404; + } + + access_log /var/log/nginx/random27569.example.org/access.log combined_plus; + error_log /var/log/nginx/random27569.example.org/error.log; +} + +server { + listen 80; + server_name random11055.example.org www.random11055.example.org; + + root /srv/http/random11055.example.org; + index index.html index.htm; + + location / { + try_files $uri $uri/ =404; + } + + access_log /var/log/nginx/random11055.example.org/access.log combined_plus; + error_log /var/log/nginx/random11055.example.org/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3874 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3874 new file mode 100644 index 000000000..1180f2eb1 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-3874 @@ -0,0 +1,46 @@ +upstream django_server_random7267.example.org { + server unix:/srv/http/random24334/live/website.sock; +} + +server { + listen 80; + listen 443 ssl; + + server_name random7267.example.org; + + ssl_certificate /etc/ssl/public/random7267.example.org_chained.crt; + ssl_certificate_key /etc/ssl/private/random7267.example.org.key; + + location /media/ { + alias /srv/http/random24334/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random24334/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random7267.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + } + + access_log /var/log/nginx/random24334/live/access.log combined_plus; + error_log /var/log/nginx/random24334/live/error.log; +} + +server { + listen 80; + listen 443 ssl; + + server_name www.random7267.example.org; + + ssl_certificate /etc/ssl/public/random7267.example.org_chained.crt; + ssl_certificate_key /etc/ssl/private/random7267.example.org.key; + + return 301 http://random7267.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4035 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4035 new file mode 100644 index 000000000..1a1deb96b --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4035 @@ -0,0 +1,31 @@ +upstream django_server_random2104.example.org { + server unix:/srv/http/random28136/live/website.sock; +} + +server { + listen 80; + server_name www.random2104.example.org; + + location ~ /static/(.*)$ { + alias /srv/http/random28136/live/website/static/$1; + expires 7d; + } + + + location / { + proxy_pass http://django_server_random2104.example.org; + include /etc/nginx/proxy_params; + proxy_connect_timeout 240; + proxy_read_timeout 240; + + # You can configure access rules here + } + + access_log /var/log/nginx/random28136/live/access.log combined_plus; + error_log /var/log/nginx/random28136/live/error.log; +} + +server { + server_name random2104.example.org; + rewrite ^ http://www.random2104.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4143 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4143 new file mode 100644 index 000000000..add683007 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4143 @@ -0,0 +1,33 @@ +upstream django_server_random24919.example.org { + server unix:/srv/http/random7831/live/website.sock; +} + +server { + listen 80; + server_name random24919.example.org; + + location ^~ /media/ { + alias /srv/http/random7831/live/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random7831/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random24919.example.org; + include /etc/nginx/proxy_params; + + proxy_connect_timeout 240; + proxy_read_timeout 240; + } + + access_log /var/log/nginx/random7831/live/access.log combined_plus; + error_log /var/log/nginx/random7831/live/error.log; +} + +server { + server_name www.random24919.example.org; + rewrite ^ http://random24919.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4264 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4264 new file mode 100644 index 000000000..ef347862f --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-4264 @@ -0,0 +1,12 @@ +# vhost created by moving from marauder, but there it was an apache vhost. + +server { + listen 80; + server_name random3080.example.org www.random3080.example.org random26833.example.org www.random26833.example.org; + + root /srv/http/random10391.example.org/; + + if ($request_uri != '/googleYYYYYYYYYYYYYYYY.html') { + rewrite ^ http://random10305.example.org/ permanent; + } +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-5826 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-5826 new file mode 100644 index 000000000..bcfc662b2 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-5826 @@ -0,0 +1,38 @@ +upstream django_server_random1107.example.org { + server unix:/srv/http/random4755/acceptance/website.sock; +} + +server { + listen 80; + server_name random1107.example.org www.random1107.example.org; + + if ($host != 'random1107.example.org') { + rewrite ^/(.*)$ http://random1107.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random4755/acceptance/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random4755/acceptance/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random1107.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + satisfy any; + allow 89.188.25.162; + auth_basic "random4755 acceptance"; + auth_basic_user_file htpasswords/random4755_acceptance; + + } + + access_log /var/log/nginx/random4755/acceptance/access.log combined_plus; + error_log /var/log/nginx/random4755/acceptance/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-5872 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-5872 new file mode 100644 index 000000000..fe41f9872 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-5872 @@ -0,0 +1,36 @@ +upstream django_server_random8404.example.org { + server unix:/srv/http/random1006/internal/website.sock; +} + +server { + listen 80; + server_name random8404.example.org; + + location ^~ /media/ { + alias /srv/http/random1006/internal/website/static/; + expires 7d; + } + #location ^~ /static/ { + # alias /srv/http/random1006/internal/website/static/; + # expires 7d; + #} + + location / { + proxy_pass http://django_server_random8404.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'internal for random1006'; + auth_basic_user_file /srv/http/random1006/internal/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random1006/internal/access.log combined_plus; + error_log /var/log/nginx/random1006/internal/error.log; +} + +server { + server_name www.random8404.example.org; + rewrite ^ http://random8404.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-6228 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-6228 new file mode 100644 index 000000000..d5c157e88 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-6228 @@ -0,0 +1,39 @@ +upstream django_server_random15255_intern { + server unix:/srv/http/random15255/intern/website.sock fail_timeout=5; +} + +server { + listen 80; + server_name random11459.example.org www.random11459.example.org; + + if ($host != 'random11459.example.org') { + rewrite ^/(.*)$ http://random11459.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random15255/internal/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random15255/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random15255_intern; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + + satisfy any; + auth_basic 'random191 internal'; + auth_basic_user_file /srv/http/random15255/internal/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random15255/internal/access.log combined_plus; + error_log /var/log/nginx/random15255/internal/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-7895 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-7895 new file mode 100644 index 000000000..4a49ea47e --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-7895 @@ -0,0 +1,32 @@ +upstream django_server_random20084.example.org { + server unix:/srv/http/random1540/live/website.sock; +} + +server { + listen 80; + server_name random3969.example.org www.random20084.example.org random20084.example.org; + + if ($host != 'www.random20084.example.org') { + rewrite ^/(.*)$ http://www.random20084.example.org/$1 permanent; + } + + location /media/ { + alias /srv/http/random1540/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random1540/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random20084.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + access_log /var/log/nginx/random1540/live/access.log combined_plus; + error_log /var/log/nginx/random1540/live/error.log; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8343 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8343 new file mode 100644 index 000000000..9e0d39d47 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8343 @@ -0,0 +1,36 @@ +upstream django_server_random29577.example.org { + server unix:/srv/http/random24645/internal/website.sock; +} + +server { + listen 80; + server_name random29577.example.org; + + location ^~ /media/ { + alias /srv/http/random24645/internal/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random24645/internal/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random29577.example.org; + include /etc/nginx/proxy_params; + + satisfy any; + auth_basic 'internal for random24645'; + auth_basic_user_file /srv/http/random24645/internal/htpasswords; + include /etc/nginx/allow_ytec_ips_params; + deny all; + } + + access_log /var/log/nginx/random24645/internal/access.log; + error_log /var/log/nginx/random24645/internal/error.log; +} + +server { + server_name www.random29577.example.org; + rewrite ^ http://random29577.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8422 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8422 new file mode 100644 index 000000000..c3b979b4e --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8422 @@ -0,0 +1,46 @@ +upstream django_server_random25771.example.org { + server unix:/srv/http/random4711/live/website.sock; +} + +server { + listen 80; + server_name random25771.example.org; + + location ^~ /media/ { + alias /srv/http/random4711/live/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random4711/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random25771.example.org; + include /etc/nginx/proxy_params; + proxy_read_timeout 4m; + + # You can configure access rules here + } + + client_max_body_size 25m; + + access_log /var/log/nginx/random4711/live/access.log combined_plus; + error_log /var/log/nginx/random4711/live/error.log; +} + +server { + server_name www.random25771.example.org; + server_name *.random17707.example.org; + server_name *.random22274.example.org; + server_name *.random26333.example.org; + server_name *.random10742.example.org; + server_name *.random8297.example.org; + server_name *.random18250.example.org; + server_name *.random30184.example.org; + server_name *.random27005.example.org; + server_name *.random12286.example.org; + server_name *.random28076.example.org; + server_name *.random26194.example.org; + rewrite ^ http://random25771.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8637 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8637 new file mode 100644 index 000000000..91e31bbfd --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8637 @@ -0,0 +1,40 @@ +upstream django_server_random27891.example.org { + server unix:/srv/http/random6344/live/website.sock; +} + +server { + listen 443; + server_name random27891.example.org; + + ssl on; + ssl_certificate /etc/ssl/public/random27891.example.org.bundle.crt; + ssl_certificate_key /etc/ssl/private/random27891.example.org.key; + + location /media/ { + alias /srv/http/random6344/live/dynamic/public/; + expires 7d; + include upload_folder_security_params; + } + location /static/ { + alias /srv/http/random6344/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random27891.example.org; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Protocol $scheme; + } + + access_log /var/log/nginx/random6344/live/access.log combined_plus; + error_log /var/log/nginx/random6344/live/error.log; +} + +server { + listen 80; + server_name random27891.example.org; + + return 301 https://random27891.example.org$request_uri; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8662 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8662 new file mode 100644 index 000000000..3fe9c4011 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-8662 @@ -0,0 +1,32 @@ +upstream django_server_random27507.example.org { + server unix:/srv/http/random24211/live/website.sock; +} + +server { + listen 80; + server_name random27507.example.org; + + location ^~ /media/ { + alias /srv/http/random24211/live/dynamic/public/; + expires 7d; + } + location ^~ /static/ { + alias /srv/http/random24211/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random27507.example.org; + include /etc/nginx/proxy_params; + + # You can configure access rules here + } + + access_log /var/log/nginx/random24211/live/access.log combined_plus; + error_log /var/log/nginx/random24211/live/error.log; +} + +server { + server_name www.random27507.example.org; + rewrite ^ http://random27507.example.org$request_uri permanent; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-9426 b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-9426 new file mode 100644 index 000000000..90dad9601 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/79-configs/site-9426 @@ -0,0 +1,111 @@ +upstream django_server_random20374.nl { + server unix:/srv/http/random20374/live/website.sock; +} + +server { + listen 80; + + # Main domain + server_name random9123.example.org; + + # So called mini-sites, resulting in landing pages for Google. + server_name random16942.example.org; + server_name random23560.example.org; + server_name random17636.example.org; + server_name random13969.example.org; + server_name random4892.example.org; + server_name random24240.example.org; + server_name random25863.example.org; + server_name random26503.example.org; + server_name random5090.example.org; + server_name random1856.example.org; + server_name random2911.example.org; + server_name random16405.example.org; + + location /media/ { + alias /srv/http/random20374/live/dynamic/public/; + expires 7d; + } + location /static/ { + alias /srv/http/random20374/live/static_collected/; + expires 7d; + } + + location / { + proxy_pass http://django_server_random20374.nl; + include /etc/nginx/proxy_params; + } + + access_log /var/log/nginx/random20374/live/access.log combined_plus; + error_log /var/log/nginx/random20374/live/error.log; +} + +server { + server_name www.random9123.example.org; + return 301 $scheme://random9123.example.org$request_uri; +} + +server { + server_name www.random1825.example.org random1825.example.org; + return 301 $scheme://random9123.example.org$request_uri; +} + +server { + server_name www.random16942.example.org; + return 301 $scheme://random16942.example.org; +} + +server { + server_name www.random23560.example.org; + return 301 $scheme://random23560.example.org; +} + +server { + server_name www.random17636.example.org; + return 301 $scheme://random17636.example.org; +} + +server { + server_name www.random13969.example.org; + return 301 $scheme://random13969.example.org; +} + +server { + server_name www.random4892.example.org; + return 301 $scheme://random4892.example.org; +} + +server { + server_name www.random24240.example.org; + return 301 $scheme://random24240.example.org; +} + +server { + server_name www.random25863.example.org; + return 301 $scheme://random25863.example.org; +} + +server { + server_name www.random26503.example.org; + return 301 $scheme://random26503.example.org; +} + +server { + server_name www.random5090.example.org; + return 301 $scheme://random5090.example.org; +} + +server { + server_name www.random1856.example.org; + return 301 $scheme://random1856.example.org; +} + +server { + server_name www.random2911.example.org; + return 301 $scheme://random2911.example.org; +} + +server { + server_name www.random16405.example.org; + return 301 $scheme://random16405.example.org; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/activecolab/www.example.com.vhost b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/activecolab/www.example.com.vhost new file mode 100644 index 000000000..71344abea --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/activecolab/www.example.com.vhost @@ -0,0 +1,44 @@ +server { + listen 80; + server_name www.example.com example.com; + root /var/www/www.example.com/web; + + if ($http_host != "www.example.com") { + rewrite ^ http://www.example.com$request_uri permanent; + } + + index index.php index.html; + + location = /favicon.ico { + log_not_found off; + access_log off; + } + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac). + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + + location / { + try_files $uri $uri/ /index.php?path_info=$uri&$args; + access_log off; + expires max; + } + + location ~ \.php$ { + try_files $uri =404; + include /etc/nginx/fastcgi_params; + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_intercept_errors on; + } +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/fastcgi.conf b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/fastcgi.conf new file mode 100644 index 000000000..056987136 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/fastcgi.conf @@ -0,0 +1,9 @@ +#-*- mode: nginx; mode: flyspell-prog; mode: autopair; ispell-local-dictionary: "american" -*- +### fastcgi configuration. +fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; +include fastcgi_params; +fastcgi_buffers 256 4k; +fastcgi_intercept_errors on; +## allow 4 hrs - pass timeout responsibility to upstrea +fastcgi_read_timeout 14400; +fastcgi_index index.php; diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/fastcgi_params b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/fastcgi_params new file mode 100644 index 000000000..4a7f26920 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/fastcgi_params @@ -0,0 +1,32 @@ +# -*- mode: conf; mode: flyspell-prog; ispell-local-dictionary: "american" -*- +### fastcgi parameters. +fastcgi_param QUERY_STRING $query_string; +fastcgi_param REQUEST_METHOD $request_method; +fastcgi_param CONTENT_TYPE $content_type; +fastcgi_param CONTENT_LENGTH $content_length; + +fastcgi_param SCRIPT_NAME $fastcgi_script_name; +fastcgi_param REQUEST_URI $request_uri; +fastcgi_param DOCUMENT_URI $document_uri; +fastcgi_param DOCUMENT_ROOT $document_root; +fastcgi_param SERVER_PROTOCOL $server_protocol; + +fastcgi_param GATEWAY_INTERFACE CGI/1.1; +fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; + +fastcgi_param REMOTE_ADDR $remote_addr; +fastcgi_param REMOTE_PORT $remote_port; +fastcgi_param SERVER_ADDR $server_addr; +fastcgi_param SERVER_PORT $server_port; +fastcgi_param SERVER_NAME $server_name; +fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + +## PHP only, required if PHP was built with --enable-force-cgi-redirect +fastcgi_param REDIRECT_STATUS 200; +## HTTPS 'on' parameter. This requires Nginx version 1.1.11 or +## later. The if_not_empty flag was introduced in 1.1.11. See: +## http://nginx.org/en/CHANGES. If using a version that doesn't +## support this comment out the line below. +fastcgi_param HTTPS $https if_not_empty; +## For Nginx versions below 1.1.11 uncomment the line below after commenting out the above. +#fastcgi_param HTTPS $https diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/koi-utf b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/koi-utf new file mode 100644 index 000000000..e7974ff6a --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/koi-utf @@ -0,0 +1,109 @@ + +# This map is not a full koi8-r <> utf8 map: it does not contain +# box-drawing and some other characters. Besides this map contains +# several koi8-u and Byelorussian letters which are not in koi8-r. +# If you need a full and standard map, use contrib/unicode2nginx/koi-utf +# map instead. + +charset_map koi8-r utf-8 { + + 80 E282AC ; # euro + + 95 E280A2 ; # bullet + + 9A C2A0 ; #   + + 9E C2B7 ; # · + + A3 D191 ; # small yo + A4 D194 ; # small Ukrainian ye + + A6 D196 ; # small Ukrainian i + A7 D197 ; # small Ukrainian yi + + AD D291 ; # small Ukrainian soft g + AE D19E ; # small Byelorussian short u + + B0 C2B0 ; # ° + + B3 D081 ; # capital YO + B4 D084 ; # capital Ukrainian YE + + B6 D086 ; # capital Ukrainian I + B7 D087 ; # capital Ukrainian YI + + B9 E28496 ; # numero sign + + BD D290 ; # capital Ukrainian soft G + BE D18E ; # capital Byelorussian short U + + BF C2A9 ; # (C) + + C0 D18E ; # small yu + C1 D0B0 ; # small a + C2 D0B1 ; # small b + C3 D186 ; # small ts + C4 D0B4 ; # small d + C5 D0B5 ; # small ye + C6 D184 ; # small f + C7 D0B3 ; # small g + C8 D185 ; # small kh + C9 D0B8 ; # small i + CA D0B9 ; # small j + CB D0BA ; # small k + CC D0BB ; # small l + CD D0BC ; # small m + CE D0BD ; # small n + CF D0BE ; # small o + + D0 D0BF ; # small p + D1 D18F ; # small ya + D2 D180 ; # small r + D3 D181 ; # small s + D4 D182 ; # small t + D5 D183 ; # small u + D6 D0B6 ; # small zh + D7 D0B2 ; # small v + D8 D18C ; # small soft sign + D9 D18B ; # small y + DA D0B7 ; # small z + DB D188 ; # small sh + DC D18D ; # small e + DD D189 ; # small shch + DE D187 ; # small ch + DF D18A ; # small hard sign + + E0 D0AE ; # capital YU + E1 D090 ; # capital A + E2 D091 ; # capital B + E3 D0A6 ; # capital TS + E4 D094 ; # capital D + E5 D095 ; # capital YE + E6 D0A4 ; # capital F + E7 D093 ; # capital G + E8 D0A5 ; # capital KH + E9 D098 ; # capital I + EA D099 ; # capital J + EB D09A ; # capital K + EC D09B ; # capital L + ED D09C ; # capital M + EE D09D ; # capital N + EF D09E ; # capital O + + F0 D09F ; # capital P + F1 D0AF ; # capital YA + F2 D0A0 ; # capital R + F3 D0A1 ; # capital S + F4 D0A2 ; # capital T + F5 D0A3 ; # capital U + F6 D096 ; # capital ZH + F7 D092 ; # capital V + F8 D0AC ; # capital soft sign + F9 D0AB ; # capital Y + FA D097 ; # capital Z + FB D0A8 ; # capital SH + FC D0AD ; # capital E + FD D0A9 ; # capital SHCH + FE D0A7 ; # capital CH + FF D0AA ; # capital hard sign +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/koi-win b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/koi-win new file mode 100644 index 000000000..72afabe89 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/koi-win @@ -0,0 +1,103 @@ + +charset_map koi8-r windows-1251 { + + 80 88 ; # euro + + 95 95 ; # bullet + + 9A A0 ; #   + + 9E B7 ; # · + + A3 B8 ; # small yo + A4 BA ; # small Ukrainian ye + + A6 B3 ; # small Ukrainian i + A7 BF ; # small Ukrainian yi + + AD B4 ; # small Ukrainian soft g + AE A2 ; # small Byelorussian short u + + B0 B0 ; # ° + + B3 A8 ; # capital YO + B4 AA ; # capital Ukrainian YE + + B6 B2 ; # capital Ukrainian I + B7 AF ; # capital Ukrainian YI + + B9 B9 ; # numero sign + + BD A5 ; # capital Ukrainian soft G + BE A1 ; # capital Byelorussian short U + + BF A9 ; # (C) + + C0 FE ; # small yu + C1 E0 ; # small a + C2 E1 ; # small b + C3 F6 ; # small ts + C4 E4 ; # small d + C5 E5 ; # small ye + C6 F4 ; # small f + C7 E3 ; # small g + C8 F5 ; # small kh + C9 E8 ; # small i + CA E9 ; # small j + CB EA ; # small k + CC EB ; # small l + CD EC ; # small m + CE ED ; # small n + CF EE ; # small o + + D0 EF ; # small p + D1 FF ; # small ya + D2 F0 ; # small r + D3 F1 ; # small s + D4 F2 ; # small t + D5 F3 ; # small u + D6 E6 ; # small zh + D7 E2 ; # small v + D8 FC ; # small soft sign + D9 FB ; # small y + DA E7 ; # small z + DB F8 ; # small sh + DC FD ; # small e + DD F9 ; # small shch + DE F7 ; # small ch + DF FA ; # small hard sign + + E0 DE ; # capital YU + E1 C0 ; # capital A + E2 C1 ; # capital B + E3 D6 ; # capital TS + E4 C4 ; # capital D + E5 C5 ; # capital YE + E6 D4 ; # capital F + E7 C3 ; # capital G + E8 D5 ; # capital KH + E9 C8 ; # capital I + EA C9 ; # capital J + EB CA ; # capital K + EC CB ; # capital L + ED CC ; # capital M + EE CD ; # capital N + EF CE ; # capital O + + F0 CF ; # capital P + F1 DF ; # capital YA + F2 D0 ; # capital R + F3 D1 ; # capital S + F4 D2 ; # capital T + F5 D3 ; # capital U + F6 C6 ; # capital ZH + F7 C2 ; # capital V + F8 DC ; # capital soft sign + F9 DB ; # capital Y + FA C7 ; # capital Z + FB D8 ; # capital SH + FC DD ; # capital E + FD D9 ; # capital SHCH + FE D7 ; # capital CH + FF DA ; # capital hard sign +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/map_https_fcgi.conf b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/map_https_fcgi.conf new file mode 100644 index 000000000..a8d62223a --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/map_https_fcgi.conf @@ -0,0 +1,7 @@ +# -*- mode: conf; mode: flyspell-prog; ispell-local-dictionary: "american" -*- +### Implement the $https_if_not_empty variable for Nginx versions below 1.1.11. + +map $scheme $https { + default ''; + https on; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/mime.types b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/mime.types new file mode 100644 index 000000000..618b8f8e7 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/mime.types @@ -0,0 +1,77 @@ +# -*- mode: nginx; mode: flyspell-prog; mode: autopair; ispell-current-dictionary: american -*- +types { + text/html html htm shtml; + text/css css; + text/xml xml rss; + image/gif gif; + image/jpeg jpeg jpg; + application/x-javascript js; + application/atom+xml atom; + + text/mathml mml; + text/plain txt; + text/vnd.sun.j2me.app-descriptor jad; + text/vnd.wap.wml wml; + text/x-component htc; + + image/png png; + image/tiff tif tiff; + image/vnd.wap.wbmp wbmp; + image/x-icon ico; + image/x-jng jng; + image/x-ms-bmp bmp; + image/svg+xml svg svgz; + + application/java-archive jar war ear; + application/mac-binhex40 hqx; + application/msword doc; + application/pdf pdf; + application/postscript ps eps ai; + application/rtf rtf; + application/vnd.ms-excel xls; + application/vnd.ms-powerpoint ppt; + application/vnd.wap.wmlc wmlc; + application/vnd.wap.xhtml+xml xhtml; + application/x-7z-compressed 7z; + application/x-cocoa cco; + application/x-java-archive-diff jardiff; + application/x-java-jnlp-file jnlp; + application/x-makeself run; + application/x-perl pl pm; + application/x-pilot prc pdb; + application/x-rar-compressed rar; + application/x-redhat-package-manager rpm; + application/x-sea sea; + application/x-shockwave-flash swf; + application/x-stuffit sit; + application/x-tcl tcl tk; + application/x-x509-ca-cert der pem crt; + application/x-xpinstall xpi; + application/zip zip; + + # Mime types for web fonts. Stolen from here: + # http://seconddrawer.com.au/blog/ in part. + application/x-font-ttf ttf; + font/opentype otf; + application/vnd.ms-fontobject eot; + application/x-woff woff; + + application/octet-stream bin exe dll; + application/octet-stream deb; + application/octet-stream dmg; + application/octet-stream iso img; + application/octet-stream msi msp msm; + + audio/midi mid midi kar; + audio/mpeg mp3; + audio/x-realaudio ra; + + video/3gpp 3gpp 3gp; + video/mpeg mpeg mpg; + video/quicktime mov; + video/x-flv flv; + video/x-mng mng; + video/x-ms-asf asx asf; + video/x-ms-wmv wmv; + video/x-msvideo avi; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/nginx.conf b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/nginx.conf new file mode 100644 index 000000000..22ad4c317 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/nginx.conf @@ -0,0 +1,119 @@ +# -*- mode: nginx; mode: flyspell-prog; mode: autopair; ispell-local-dictionary: "american" -*- +user www-data; +worker_processes 4; + +error_log /var/log/nginx/error.log; +pid /var/run/nginx.pid; + +worker_rlimit_nofile 8192; + +events { + worker_connections 4096; + ## epoll is preferred on 2.6 Linux + ## kernels. Cf. http://www.kegel.com/c10k.html#nb.epoll + use epoll; + ## Accept as many connections as possible. + multi_accept on; +} + +http { + ## MIME types. + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ## FastCGI. + include /etc/nginx/fastcgi.conf; + + ## Default log and error files. + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + ## Use sendfile() syscall to speed up I/O operations and speed up + ## static file serving. + sendfile on; + ## Handling of IPs in proxied and load balancing situations. + set_real_ip_from 0.0.0.0/32; # all addresses get a real IP. + real_ip_header X-Forwarded-For; # the ip is forwarded from the load balancer/proxy + + ## Define a zone for limiting the number of simultaneous + ## connections nginx accepts. 1m means 32000 simultaneous + ## sessions. We need to define for each server the limit_conn + ## value refering to this or other zones. + ## ** This syntax requires nginx version >= + ## ** 1.1.8. Cf. http://nginx.org/en/CHANGES. If using an older + ## ** version then use the limit_zone directive below + ## ** instead. Comment out this + ## ** one if not using nginx version >= 1.1.8. + limit_conn_zone $binary_remote_addr zone=arbeit:10m; + + ## Timeouts. + client_body_timeout 60; + client_header_timeout 60; + keepalive_timeout 10 10; + send_timeout 60; + + ## Reset lingering timed out connections. Deflect DDoS. + reset_timedout_connection on; + + ## Body size. + client_max_body_size 10m; + + ## TCP options. + tcp_nodelay on; + tcp_nopush on; + + ## Compression. + gzip on; + gzip_buffers 16 8k; + gzip_comp_level 1; + gzip_http_version 1.1; + gzip_min_length 10; + gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript image/x-icon application/vnd.ms-fontobject font/opentype application/x-font-ttf; + gzip_vary on; + gzip_proxied any; # Compression for all requests. + ## No need for regexps. See + ## http://wiki.nginx.org/NginxHttpGzipModule#gzip_disable + gzip_disable "msie6"; + + ## Serve already compressed files directly, bypassing on-the-fly + ## compression. + gzip_static on; + + ## Hide the Nginx version number. + server_tokens off; + + ## Use a SSL/TLS cache for SSL session resume. This needs to be + ## here (in this context, for session resumption to work. See this + ## thread on the Nginx mailing list: + ## http://nginx.org/pipermail/nginx/2010-November/023736.html. + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + ## For the filefield_nginx_progress module to work. From the + ## README. Reserve 1MB under the name 'uploads' to track uploads. + upload_progress uploads 1m; + + ## Enable clickjacking protection in modern browsers. Available in + ## IE8 also. See + ## https://developer.mozilla.org/en/The_X-FRAME-OPTIONS_response_header + add_header X-Frame-Options sameorigin; + + ## Include the upstream servers for PHP FastCGI handling config. + include upstream_phpcgi.conf; + + ## If using Nginx version >= 1.1.11 then there's a $https variable + ## that has the value 'on' if the used scheme is https and '' if not. + ## See: http://trac.nginx.org/nginx/changeset/4380/nginx + ## http://trac.nginx.org/nginx/changeset/4333/nginx and + ## http://trac.nginx.org/nginx/changeset/4334/nginx. If using a + ## previous version then uncomment out the line below. + #include map_https_fcgi.conf; + + ## Include the upstream servers for Apache handling the PHP + ## processes. In this case Nginx functions as a reverse proxy. + #include reverse_proxy.conf; + #include upstream_phpapache.conf; + + ## Include all vhosts. + include /etc/nginx/sites-enabled/*; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/reverse_proxy.conf b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/reverse_proxy.conf new file mode 100644 index 000000000..ee0faadd7 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/reverse_proxy.conf @@ -0,0 +1,10 @@ +# -*- mode: nginx; mode: flyspell-prog; mode: autopair; ispell-local-dictionary: "american" -*- + +### Configuration for reverse proxy. Passing the necessary headers to +### the backend. Nginx doesn't tunnel the connection, it opens a new +### one. Hence whe need to send these headers to the backend so that +### the client(s) IP is available to them. The host is also sent. + +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header Host $http_host; diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/sites-available/000-default b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/sites-available/000-default new file mode 100644 index 000000000..9dbaa44ff --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/sites-available/000-default @@ -0,0 +1,19 @@ +# -*-mode: nginx; mode: flyspell-prog; mode: autopair; ispell-local-dictionary: "american" -*- +### Block all illegal host headers. Taken from a discussion on nginx +### forums. Cf. http://forum.nginx.org/read.php?2,3482,3518 following +### a suggestion by Maxim Dounin. Also suggested in +### http://nginx.org/en/docs/http/request_processing.html. +server { + listen [::]:80 default_server; + # Uncomment the line below and comment the above if you're + # running a Nginx version less than 0.8.20. + # listen [::]:80 default; + + # Accept redirects based on the value of the Host header. If + # there's no valid vhost configuration file with a + # corresponding server_name directive then signal an error and + # fail silently. See: + # http://wiki.nginx.org/NginxHttpCoreModule#server_name_in_redirect + server_name_in_redirect off; + return 444; +} diff --git a/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/sites-available/chive.example.com.conf b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/sites-available/chive.example.com.conf new file mode 100644 index 000000000..e77024456 --- /dev/null +++ b/certbot-compatibility-test/nginx/nginx-roundtrip-testdata/chive/chive-nginx-master/sites-available/chive.example.com.conf @@ -0,0 +1,102 @@ +# -*- mode: nginx; mode: flyspell-prog; mode: autopair; ispell-local-dictionary: "american" -*- +### Nginx configuration for Chive. + +server { + ## This is to avoid the spurious if for sub-domain name + ## rewriting. See http://wiki.nginx.org/Pitfalls#Server_Name. + listen 80; # IPv4 + + ## Replace the IPv6 address by your own address. The address below + ## was stolen from the wikipedia page on IPv6. + listen [fe80::202:b3ff:fe1e:8329]:80 ipv6only=on; + + server_name www.chive.example.com; + + return 301 $scheme://chive.example.com$request_uri; + +} # server domain rewrite. + +server { + listen 80; # IPv4 + + ## Replace the IPv6 address by your own address. The address below + ## was stolen from the wikipedia page on IPv6. + listen [fe80::202:b3ff:fe1e:8329]:80 ipv6only=on; + + limit_conn arbeit 32; + server_name chive.example.com; + + ## Parameterization using hostname of access and log filenames. + access_log /var/log/nginx/chive.example.com_access.log; + error_log /var/log/nginx/chive.example.com_error.log; + + root /var/www/sites/chive.example.com; + index index.php index.html; + + ## Support for favicon. Return a 204 (No Content) if the favicon + ## doesn't exist. + location = /favicon.ico { + try_files /favicon.ico =204; + } + + ## The main location is accessed using Basic Auth. + location / { + ## Access is restricted. + auth_basic "Restricted Access"; # auth realm + auth_basic_user_file .htpasswd-users; # htpasswd file + + ## Use PATH_INFO for translating the requests to the + ## FastCGI. This config follows Igor's suggestion here: + ## http://forum.nginx.org/read.php?2,124378,124582. + ## This is preferable to using: + ## fastcgi_split_path_info ^(.+\.php)(.*)$ + ## It saves one regex in the location. Hence it's faster. + location ~ ^(?