From bd8b908f5011c572026a64283387952f3e90737c Mon Sep 17 00:00:00 2001 From: James Kasten Date: Thu, 29 Jan 2015 19:35:31 -0800 Subject: [PATCH 1/9] patch auth_handler cleanup function --- letsencrypt/client/auth_handler.py | 28 +++++++++++++++++++++++----- letsencrypt/client/errors.py | 14 +++++++++++--- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/letsencrypt/client/auth_handler.py b/letsencrypt/client/auth_handler.py index b85996818..7ede54c94 100644 --- a/letsencrypt/client/auth_handler.py +++ b/letsencrypt/client/auth_handler.py @@ -123,7 +123,12 @@ class AuthHandler(object): # pylint: disable=too-many-instance-attributes self._cleanup_challenges(domain) def _satisfy_challenges(self): - """Attempt to satisfy all saved challenge messages.""" + """Attempt to satisfy all saved challenge messages. + + .. todo:: It might be worth it to try different challenges to + find one that doesn't throw an exception + + """ logging.info("Performing the following challenges:") for dom in self.domains: self.paths[dom] = gen_challenge_path( @@ -143,8 +148,19 @@ class AuthHandler(object): # pylint: disable=too-many-instance-attributes flat_client.extend(ichall.chall for ichall in self.client_c[dom]) flat_auth.extend(ichall.chall for ichall in self.dv_c[dom]) - client_resp = self.client_auth.perform(flat_client) - dv_resp = self.dv_auth.perform(flat_auth) + try: + client_resp = self.client_auth.perform(flat_client) + dv_resp = self.dv_auth.perform(flat_auth) + # This will catch both specific types of errors. + except errors.LetsEncryptAuthHandlerError as err: + logging.critical("Failure in setting up challenges:") + logging.critical(str(err)) + logging.info("Attempting to clean up outstanding challenges...") + for dom in self.domains: + self._cleanup_challenges(dom) + + raise errors.LetsEncryptAuthHandlerError( + "Unable to perform challenges") logging.info("Ready for verification...") @@ -191,8 +207,10 @@ class AuthHandler(object): # pylint: disable=too-many-instance-attributes """ logging.info("Cleaning up challenges for %s", domain) - self.dv_auth.cleanup(self.dv_c[domain]) - self.client_auth.cleanup(self.client_c[domain]) + # These are indexed challenges... give just the challenges to the auth + self.dv_auth.cleanup(ichall.chall for ichall in self.dv_c[domain]) + self.client_auth.cleanup( + ichall.chall for ichall in self.client_c[domain]) def _cleanup_state(self, delete_list): """Cleanup state after an authorization is received. diff --git a/letsencrypt/client/errors.py b/letsencrypt/client/errors.py index 6a3739832..d49611ce7 100644 --- a/letsencrypt/client/errors.py +++ b/letsencrypt/client/errors.py @@ -9,6 +9,7 @@ class LetsEncryptReverterError(LetsEncryptClientError): """Let's Encrypt Reverter error.""" +# Auth Handler Errors class LetsEncryptAuthHandlerError(LetsEncryptClientError): """Let's Encrypt Auth Handler error.""" @@ -17,6 +18,16 @@ class LetsEncryptClientAuthError(LetsEncryptAuthHandlerError): """Let's Encrypt Client Authenticator error.""" +class LetsEncryptDvAuthError(LetsEncryptAuthHandlerError): + """Let's Encrypt DV Authenticator error.""" + + +# Authenticator - Challenge specific errors +class LetsEncryptDvsniError(LetsEncryptDvAuthError): + """Let's Encrypt DVSNI error.""" + + +# Configurator Errors class LetsEncryptConfiguratorError(LetsEncryptClientError): """Let's Encrypt Configurator error.""" @@ -28,6 +39,3 @@ class LetsEncryptNoInstallationError(LetsEncryptConfiguratorError): class LetsEncryptMisconfigurationError(LetsEncryptConfiguratorError): """Let's Encrypt Misconfiguration error.""" - -class LetsEncryptDvsniError(LetsEncryptConfiguratorError): - """Let's Encrypt DVSNI error.""" From 2cb4ab936d00e16aae143e199e9308d9cb94655c Mon Sep 17 00:00:00 2001 From: James Kasten Date: Thu, 29 Jan 2015 20:07:29 -0800 Subject: [PATCH 2/9] generator to list to conform to API --- letsencrypt/client/auth_handler.py | 6 +- letsencrypt/client/tests/auth_handler_test.py | 84 ++++++++++++++++--- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/letsencrypt/client/auth_handler.py b/letsencrypt/client/auth_handler.py index 7ede54c94..7c72980ed 100644 --- a/letsencrypt/client/auth_handler.py +++ b/letsencrypt/client/auth_handler.py @@ -208,9 +208,11 @@ class AuthHandler(object): # pylint: disable=too-many-instance-attributes """ logging.info("Cleaning up challenges for %s", domain) # These are indexed challenges... give just the challenges to the auth - self.dv_auth.cleanup(ichall.chall for ichall in self.dv_c[domain]) + # Chose to make these lists instead of a generator to make it easier to + # work with... + self.dv_auth.cleanup([ichall.chall for ichall in self.dv_c[domain]]) self.client_auth.cleanup( - ichall.chall for ichall in self.client_c[domain]) + [ichall.chall for ichall in self.client_c[domain]]) def _cleanup_state(self, delete_list): """Cleanup state after an authorization is received. diff --git a/letsencrypt/client/tests/auth_handler_test.py b/letsencrypt/client/tests/auth_handler_test.py index b80c3c61d..33dfb6907 100644 --- a/letsencrypt/client/tests/auth_handler_test.py +++ b/letsencrypt/client/tests/auth_handler_test.py @@ -1,4 +1,5 @@ """Tests for letsencrypt.client.auth_handler.""" +import logging import unittest import mock @@ -35,6 +36,11 @@ class SatisfyChallengesTest(unittest.TestCase): self.handler = AuthHandler( self.mock_dv_auth, self.mock_client_auth, None) + logging.disable(logging.CRITICAL) + + def tearDown(self): + logging.disable(logging.NOTSET) + def test_name1_dvsni1(self): dom = "0" challenge = [acme_util.CHALLENGES["dvsni"]] @@ -54,7 +60,7 @@ class SatisfyChallengesTest(unittest.TestCase): def test_name5_dvsni5(self): challenge = [acme_util.CHALLENGES["dvsni"]] - for i in range(5): + for i in xrange(5): self.handler.add_chall_msg( str(i), acme_util.get_chall_msg(str(i), "nonce%d" % i, challenge), @@ -67,7 +73,7 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertEqual(len(self.handler.client_c), 5) # Each message contains 1 auth, 0 client - for i in range(5): + for i in xrange(5): dom = str(i) self.assertEqual(len(self.handler.responses[dom]), 1) self.assertEqual(self.handler.responses[dom][0], "DvsniChall%d" % i) @@ -140,7 +146,7 @@ class SatisfyChallengesTest(unittest.TestCase): def test_name5_all(self, mock_chall_path): challenges = acme_util.get_challenges() combos = acme_util.gen_combos(challenges) - for i in range(5): + for i in xrange(5): self.handler.add_chall_msg( str(i), acme_util.get_chall_msg( @@ -153,7 +159,7 @@ class SatisfyChallengesTest(unittest.TestCase): self.handler._satisfy_challenges() # pylint: disable=protected-access self.assertEqual(len(self.handler.responses), 5) - for i in range(5): + for i in xrange(5): self.assertEqual( len(self.handler.responses[str(i)]), len(challenges)) self.assertEqual(len(self.handler.dv_c), 5) @@ -188,7 +194,7 @@ class SatisfyChallengesTest(unittest.TestCase): acme_util.get_challenges()] # Combos doesn't matter since I am overriding the gen_path function - for i in range(5): + for i in xrange(5): dom = str(i) paths.append(gen_path(chosen_chall[i], challenge_list[i])) self.handler.add_chall_msg( @@ -205,7 +211,7 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertEqual(len(self.handler.dv_c), 5) self.assertEqual(len(self.handler.client_c), 5) - for i in range(5): + for i in xrange(5): dom = str(i) resp = self._get_exp_response(i, paths[i], challenge_list[i]) self.assertEqual(self.handler.responses[dom], resp) @@ -229,6 +235,49 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertEqual( type(self.handler.client_c["4"][0].chall).__name__, "RecTokenChall") + @mock.patch("letsencrypt.client.auth_handler.gen_challenge_path") + def test_perform_exception_cleanup(self, mock_chall_path): + """3 Challenge messages... fail perform... clean up.""" + # pylint: disable=protected-access + self.mock_dv_auth.perform.side_effect = errors.LetsEncryptDvsniError + + challenges = acme_util.get_challenges() + combos = acme_util.gen_combos(challenges) + + for i in xrange(3): + self.handler.add_chall_msg( + str(i), + acme_util.get_chall_msg( + str(i), "nonce%d" % i, challenges, combos), + "dummy_key") + + path = gen_path(["dvsni", "proofOfPossession"], challenges) + mock_chall_path.return_value = path + + # This may change in the future... but for now catch the error + self.assertRaises(errors.LetsEncryptAuthHandlerError, + self.handler._satisfy_challenges) + + # Verify cleanup is actually run correctly + self.assertEqual(self.mock_dv_auth.cleanup.call_count, 3) + self.assertEqual(self.mock_client_auth.cleanup.call_count, 3) + + # Check DV cleanup + mock_cleanup_args = self.mock_dv_auth.cleanup.call_args_list + for i in xrange(3): + # Assert length of arg list was 1 + arg_chall_list = mock_cleanup_args[i][0][0] + self.assertEqual(len(arg_chall_list), 1) + self.assertEqual(type(arg_chall_list[0]).__name__, "DvsniChall") + + # Check Auth cleanup + mock_cleanup_args = self.mock_client_auth.cleanup.call_args_list + for i in xrange(3): + arg_chall_list = mock_cleanup_args[i][0][0] + self.assertEqual(len(arg_chall_list), 1) + self.assertEqual(type(arg_chall_list[0]).__name__, "PopChall") + + def _get_exp_response(self, domain, path, challenges): # pylint: disable=no-self-use exp_resp = ["null"] * len(challenges) for i in path: @@ -259,7 +308,7 @@ class GetAuthorizationsTest(unittest.TestCase): def test_solved3_at_once(self): # Set 3 DVSNI challenges challenge = [acme_util.CHALLENGES["dvsni"]] - for i in range(3): + for i in xrange(3): self.handler.add_chall_msg( str(i), acme_util.get_chall_msg(str(i), "nonce%d" % i, challenge), @@ -277,7 +326,7 @@ class GetAuthorizationsTest(unittest.TestCase): self._test_finished() def _sat_solved_at_once(self): - for i in range(3): + for i in xrange(3): dom = str(i) self.handler.responses[dom] = ["DvsniChall%d" % i] self.handler.paths[dom] = [0] @@ -314,7 +363,7 @@ class GetAuthorizationsTest(unittest.TestCase): challs = [] challs.append(acme_util.get_challenges()) challs.append(acme_util.get_dv_challenges()) - for i in range(2): + for i in xrange(2): dom = str(i) self.handler.add_chall_msg( dom, @@ -388,7 +437,7 @@ class PathSatisfiedTest(unittest.TestCase): self.handler.paths[dom[4]] = [] self.handler.responses[dom[4]] = ["respond... sure"] - for i in range(5): + for i in xrange(5): self.assertTrue(self.handler._path_satisfied(dom[i])) def test_not_satisfied(self): @@ -405,16 +454,25 @@ class PathSatisfiedTest(unittest.TestCase): self.handler.paths[dom[3]] = [0] self.handler.responses[dom[3]] = ["null"] - for i in range(4): + for i in xrange(4): self.assertFalse(self.handler._path_satisfied(dom[i])) -def gen_auth_resp(chall_list): # pylint: disable=missing-docstring +def gen_auth_resp(chall_list): + """Generate a dummy authorization response.""" return ["%s%s" % (type(chall).__name__, chall.domain) for chall in chall_list] -def gen_path(str_list, challenges): # pylint: disable=missing-docstring +def gen_path(str_list, challenges): + """Generate a path for challenge messages + + :param list str_list: list of str, challenge message types + :param dict challenges: ACME challenge messages + + :return: list of int + + """ path = [] for i, chall in enumerate(challenges): for str_chall in str_list: From 44c2b38cdef0a2f8bda14df36717bec2c4aae0cd Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Sat, 31 Jan 2015 06:01:52 +0100 Subject: [PATCH 3/9] use version from package init also for sphinx docs, insert toplevel dir into sys.path --- docs/conf.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index fbcd61065..dce5e21d9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,13 +12,28 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys +import codecs import os +import re +import sys + + +def read_file(filename, encoding='utf8'): + """Read unicode from given file.""" + with codecs.open(filename, encoding=encoding) as fd: + return fd.read() + + +here = os.path.abspath(os.path.dirname(__file__)) + +# read version number (and other metadata) from package init +init_fn = os.path.join(here, '..', 'letsencrypt', '__init__.py') +meta = dict(re.findall(r"""__([a-z]+)__ = "([^"]+)""", read_file(init_fn))) # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join(here, '..'))) # -- General configuration ------------------------------------------------ @@ -58,9 +73,9 @@ copyright = u'2014, Let\'s Encrypt Project' # built documents. # # The short X.Y version. -version = '0.1' +version = '.'.join(meta['version'].split('.')[:2]) # The full version, including alpha/beta/rc tags. -release = '0.1' +release = meta['version'] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From c42f512c2a3c099461979be406503e6aa29278aa Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Sun, 1 Feb 2015 03:15:39 +0100 Subject: [PATCH 4/9] refactor conf.py, add comment about version syntax --- docs/conf.py | 10 ++-------- letsencrypt/__init__.py | 1 + 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index dce5e21d9..018d2afed 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,18 +17,12 @@ import os import re import sys - -def read_file(filename, encoding='utf8'): - """Read unicode from given file.""" - with codecs.open(filename, encoding=encoding) as fd: - return fd.read() - - here = os.path.abspath(os.path.dirname(__file__)) # read version number (and other metadata) from package init init_fn = os.path.join(here, '..', 'letsencrypt', '__init__.py') -meta = dict(re.findall(r"""__([a-z]+)__ = "([^"]+)""", read_file(init_fn))) +with codecs.open(init_fn, encoding='utf8') as fd: + meta = dict(re.findall(r"""__([a-z]+)__ = "([^"]+)""", fd.read())) # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the diff --git a/letsencrypt/__init__.py b/letsencrypt/__init__.py index 9fe93c4db..b36747b5f 100644 --- a/letsencrypt/__init__.py +++ b/letsencrypt/__init__.py @@ -1,2 +1,3 @@ """Let's Encrypt.""" +# version number like 1.2.3a0, must have at least 2 parts, like 1.2 __version__ = "0.1" From 4d247fa6a157aa3a699b23733d498f87d352c4e5 Mon Sep 17 00:00:00 2001 From: James Kasten Date: Mon, 2 Feb 2015 00:47:39 -0800 Subject: [PATCH 5/9] formatting fixes for testing code --- letsencrypt/client/tests/auth_handler_test.py | 70 ++++++++++--------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/letsencrypt/client/tests/auth_handler_test.py b/letsencrypt/client/tests/auth_handler_test.py index 33dfb6907..c1655ea05 100644 --- a/letsencrypt/client/tests/auth_handler_test.py +++ b/letsencrypt/client/tests/auth_handler_test.py @@ -4,6 +4,7 @@ import unittest import mock +from letsencrypt.client import challenge_util from letsencrypt.client import errors from letsencrypt.client.tests import acme_util @@ -79,8 +80,8 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertEqual(self.handler.responses[dom][0], "DvsniChall%d" % i) self.assertEqual(len(self.handler.dv_c[dom]), 1) self.assertEqual(len(self.handler.client_c[dom]), 0) - self.assertEqual( - type(self.handler.dv_c[dom][0].chall).__name__, "DvsniChall") + self.assertTrue(isinstance(self.handler.dv_c[dom][0].chall, + challenge_util.DvsniChall)) @mock.patch("letsencrypt.client.auth_handler.gen_challenge_path") def test_name1_auth(self, mock_chall_path): @@ -108,8 +109,8 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertEqual(len(self.handler.dv_c[dom]), 1) self.assertEqual(len(self.handler.client_c[dom]), 0) - self.assertEqual( - type(self.handler.dv_c[dom][0].chall).__name__, "SimpleHttpsChall") + self.assertTrue(isinstance(self.handler.dv_c[dom][0].chall, + challenge_util.SimpleHttpsChall)) @mock.patch("letsencrypt.client.auth_handler.gen_challenge_path") def test_name1_all(self, mock_chall_path): @@ -122,7 +123,7 @@ class SatisfyChallengesTest(unittest.TestCase): acme_util.get_chall_msg(dom, "nonce0", challenges, combos), "dummy_key") - path = gen_path(["simpleHttps", "recoveryToken"], challenges) + path =gen_path(["simpleHttps", "recoveryToken"], challenges) mock_chall_path.return_value = path self.handler._satisfy_challenges() # pylint: disable=protected-access @@ -137,10 +138,10 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertEqual( self.handler.responses[dom], self._get_exp_response(dom, path, challenges)) - self.assertEqual( - type(self.handler.dv_c[dom][0].chall).__name__, "SimpleHttpsChall") - self.assertEqual( - type(self.handler.client_c[dom][0].chall).__name__, "RecTokenChall") + self.assertTrue(isinstance(self.handler.dv_c[dom][0].chall, + challenge_util.SimpleHttpsChall)) + self.assertTrue(isinstance(self.handler.client_c[dom][0].chall, + challenge_util.RecTokenChall)) @mock.patch("letsencrypt.client.auth_handler.gen_challenge_path") def test_name5_all(self, mock_chall_path): @@ -173,11 +174,10 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertEqual(len(self.handler.dv_c[dom]), 1) self.assertEqual(len(self.handler.client_c[dom]), 1) - self.assertEqual( - type(self.handler.dv_c[dom][0].chall).__name__, "DvsniChall") - self.assertEqual( - type(self.handler.client_c[dom][0].chall).__name__, - "RecContactChall") + self.assertTrue(isinstance(self.handler.dv_c[dom][0].chall, + challenge_util.DvsniChall)) + self.assertTrue(isinstance(self.handler.client_c[dom][0].chall, + challenge_util.RecContactChall)) @mock.patch("letsencrypt.client.auth_handler.gen_challenge_path") def test_name5_mix(self, mock_chall_path): @@ -219,21 +219,21 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertEqual( len(self.handler.client_c[dom]), len(chosen_chall[i]) - 1) - self.assertEqual( - type(self.handler.dv_c["0"][0].chall).__name__, "DnsChall") - self.assertEqual( - type(self.handler.dv_c["1"][0].chall).__name__, "DvsniChall") - self.assertEqual( - type(self.handler.dv_c["2"][0].chall).__name__, "SimpleHttpsChall") - self.assertEqual( - type(self.handler.dv_c["3"][0].chall).__name__, "SimpleHttpsChall") - self.assertEqual( - type(self.handler.dv_c["4"][0].chall).__name__, "DnsChall") + self.assertTrue(isinstance(self.handler.dv_c["0"][0].chall, + challenge_util.DnsChall)) + self.assertTrue(isinstance(self.handler.dv_c["1"][0].chall, + challenge_util.DvsniChall)) + self.assertTrue(isinstance(self.handler.dv_c["2"][0].chall, + challenge_util.SimpleHttpsChall)) + self.assertTrue(isinstance(self.handler.dv_c["3"][0].chall, + challenge_util.SimpleHttpsChall)) + self.assertTrue(isinstance(self.handler.dv_c["4"][0].chall, + challenge_util.DnsChall)) - self.assertEqual( - type(self.handler.client_c["2"][0].chall).__name__, "PopChall") - self.assertEqual( - type(self.handler.client_c["4"][0].chall).__name__, "RecTokenChall") + self.assertTrue(isinstance(self.handler.client_c["2"][0].chall, + challenge_util.PopChall)) + self.assertTrue(isinstance(self.handler.client_c["4"][0].chall, + challenge_util.RecTokenChall)) @mock.patch("letsencrypt.client.auth_handler.gen_challenge_path") def test_perform_exception_cleanup(self, mock_chall_path): @@ -251,8 +251,8 @@ class SatisfyChallengesTest(unittest.TestCase): str(i), "nonce%d" % i, challenges, combos), "dummy_key") - path = gen_path(["dvsni", "proofOfPossession"], challenges) - mock_chall_path.return_value = path + mock_chall_path.return_value = gen_path( + ["dvsni", "proofOfPossession"], challenges) # This may change in the future... but for now catch the error self.assertRaises(errors.LetsEncryptAuthHandlerError, @@ -268,14 +268,16 @@ class SatisfyChallengesTest(unittest.TestCase): # Assert length of arg list was 1 arg_chall_list = mock_cleanup_args[i][0][0] self.assertEqual(len(arg_chall_list), 1) - self.assertEqual(type(arg_chall_list[0]).__name__, "DvsniChall") + self.assertTrue(isinstance(arg_chall_list[0], + challenge_util.DvsniChall)) # Check Auth cleanup mock_cleanup_args = self.mock_client_auth.cleanup.call_args_list for i in xrange(3): arg_chall_list = mock_cleanup_args[i][0][0] self.assertEqual(len(arg_chall_list), 1) - self.assertEqual(type(arg_chall_list[0]).__name__, "PopChall") + self.assertTrue(isinstance(arg_chall_list[0], + challenge_util.PopChall)) def _get_exp_response(self, domain, path, challenges): # pylint: disable=no-self-use @@ -467,10 +469,10 @@ def gen_auth_resp(chall_list): def gen_path(str_list, challenges): """Generate a path for challenge messages - :param list str_list: list of str, challenge message types + :param list str_list: challenge message types (:class:`str`) :param dict challenges: ACME challenge messages - :return: list of int + :return: :class:`list` of :class:`int` """ path = [] From 687668ec7529b4c19adebd9c60b2ba81c7b9c0c3 Mon Sep 17 00:00:00 2001 From: James Kasten Date: Mon, 2 Feb 2015 01:52:54 -0800 Subject: [PATCH 6/9] indentation pylint fixes --- letsencrypt/client/tests/auth_handler_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/letsencrypt/client/tests/auth_handler_test.py b/letsencrypt/client/tests/auth_handler_test.py index c1655ea05..9c3effe1b 100644 --- a/letsencrypt/client/tests/auth_handler_test.py +++ b/letsencrypt/client/tests/auth_handler_test.py @@ -123,7 +123,7 @@ class SatisfyChallengesTest(unittest.TestCase): acme_util.get_chall_msg(dom, "nonce0", challenges, combos), "dummy_key") - path =gen_path(["simpleHttps", "recoveryToken"], challenges) + path = gen_path(["simpleHttps", "recoveryToken"], challenges) mock_chall_path.return_value = path self.handler._satisfy_challenges() # pylint: disable=protected-access @@ -141,7 +141,7 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertTrue(isinstance(self.handler.dv_c[dom][0].chall, challenge_util.SimpleHttpsChall)) self.assertTrue(isinstance(self.handler.client_c[dom][0].chall, - challenge_util.RecTokenChall)) + challenge_util.RecTokenChall)) @mock.patch("letsencrypt.client.auth_handler.gen_challenge_path") def test_name5_all(self, mock_chall_path): @@ -175,9 +175,9 @@ class SatisfyChallengesTest(unittest.TestCase): self.assertEqual(len(self.handler.client_c[dom]), 1) self.assertTrue(isinstance(self.handler.dv_c[dom][0].chall, - challenge_util.DvsniChall)) + challenge_util.DvsniChall)) self.assertTrue(isinstance(self.handler.client_c[dom][0].chall, - challenge_util.RecContactChall)) + challenge_util.RecContactChall)) @mock.patch("letsencrypt.client.auth_handler.gen_challenge_path") def test_name5_mix(self, mock_chall_path): @@ -220,7 +220,7 @@ class SatisfyChallengesTest(unittest.TestCase): len(self.handler.client_c[dom]), len(chosen_chall[i]) - 1) self.assertTrue(isinstance(self.handler.dv_c["0"][0].chall, - challenge_util.DnsChall)) + challenge_util.DnsChall)) self.assertTrue(isinstance(self.handler.dv_c["1"][0].chall, challenge_util.DvsniChall)) self.assertTrue(isinstance(self.handler.dv_c["2"][0].chall, From 860a9a77b01a370ae2554cd3ad87bde6b3da124d Mon Sep 17 00:00:00 2001 From: James Kasten Date: Mon, 2 Feb 2015 02:02:11 -0800 Subject: [PATCH 7/9] Fix DnsChall --- letsencrypt/client/auth_handler.py | 3 +-- letsencrypt/client/challenge_util.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/letsencrypt/client/auth_handler.py b/letsencrypt/client/auth_handler.py index 7c72980ed..f53c2f1cc 100644 --- a/letsencrypt/client/auth_handler.py +++ b/letsencrypt/client/auth_handler.py @@ -299,8 +299,7 @@ class AuthHandler(object): # pylint: disable=too-many-instance-attributes elif chall["type"] == "dns": logging.info(" DNS challenge for name %s.", domain) - return challenge_util.DnsChall( - domain, str(chall["token"]), self.authkey[domain]) + return challenge_util.DnsChall(domain, str(chall["token"])) else: raise errors.LetsEncryptClientError( diff --git a/letsencrypt/client/challenge_util.py b/letsencrypt/client/challenge_util.py index b5d1cf38d..6c70263d7 100644 --- a/letsencrypt/client/challenge_util.py +++ b/letsencrypt/client/challenge_util.py @@ -13,7 +13,7 @@ from letsencrypt.client import le_util DvsniChall = collections.namedtuple("DvsniChall", "domain, r_b64, nonce, key") SimpleHttpsChall = collections.namedtuple( "SimpleHttpsChall", "domain, token, key") -DnsChall = collections.namedtuple("DnsChall", "domain, token, key") +DnsChall = collections.namedtuple("DnsChall", "domain, token") # Client Challenges RecContactChall = collections.namedtuple( From 42cd153ac4822678a70f5c7e11b12598feb9a464 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 3 Feb 2015 02:10:11 +0100 Subject: [PATCH 8/9] add mode checking to 2 unit tests --- letsencrypt/client/tests/le_util_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/letsencrypt/client/tests/le_util_test.py b/letsencrypt/client/tests/le_util_test.py index 5cc71a1ef..e7331e769 100644 --- a/letsencrypt/client/tests/le_util_test.py +++ b/letsencrypt/client/tests/le_util_test.py @@ -1,6 +1,7 @@ """Tests for letsencrypt.client.le_util.""" import os import shutil +import stat import tempfile import unittest @@ -33,11 +34,11 @@ class MakeOrVerifyDirTest(unittest.TestCase): path = os.path.join(self.root_path, 'bar') self._call(path, 0o650) self.assertTrue(os.path.isdir(path)) - # TODO: check mode + self.assertEqual(stat.S_IMODE(os.stat(path).st_mode), 0o650) def test_existing_correct_mode_does_not_fail(self): self._call(self.path, 0o400) - # TODO: check mode + self.assertEqual(stat.S_IMODE(os.stat(self.path).st_mode), 0o400) def test_existing_wrong_mode_fails(self): self.assertRaises(Exception, self._call, self.path, 0o600) From 337974e67546455513c3e32b0c04b6353132557d Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Fri, 6 Feb 2015 23:41:28 +0000 Subject: [PATCH 9/9] No pylint in py2.6 tox --- docs/project.rst | 1 - setup.cfg | 3 +-- setup.py | 6 +++--- tox.ini | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/project.rst b/docs/project.rst index fa59c1af3..5da350cfb 100644 --- a/docs/project.rst +++ b/docs/project.rst @@ -69,7 +69,6 @@ In order to generate the Sphinx documentation, run the following commands. :: - ./venv/bin/python setup.py docs cd docs make clean html SPHINXBUILD=../venv/bin/sphinx-build diff --git a/setup.cfg b/setup.cfg index 677247955..3369f2993 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,8 +2,7 @@ zip_ok = false [aliases] -dev = develop easy_install letsencrypt[testing] -docs = develop easy_install letsencrypt[docs] +dev = develop easy_install letsencrypt[testing,dev] [nosetests] nocapture=1 diff --git a/setup.py b/setup.py index 5501c7dd6..27d1e3fb7 100755 --- a/setup.py +++ b/setup.py @@ -36,7 +36,8 @@ install_requires = [ 'M2Crypto', ] -docs_extras = [ +dev_extras = [ + 'pylint>=1.4.0', # upstream #248 'repoze.sphinx.autointerface', 'Sphinx', ] @@ -45,7 +46,6 @@ testing_extras = [ 'coverage', 'nose', 'nosexcover', - 'pylint>=1.4.0', # upstream #248 'tox', ] @@ -69,7 +69,7 @@ setup( tests_require=install_requires, test_suite='letsencrypt', extras_require={ - 'docs': docs_extras, + 'dev': dev_extras, 'testing': testing_extras, }, entry_points={ diff --git a/tox.ini b/tox.ini index 4049c78a0..cd81c0125 100644 --- a/tox.ini +++ b/tox.ini @@ -7,13 +7,13 @@ envlist = py26,py27,cover,lint [testenv] commands = - python setup.py dev + python setup.py develop easy_install letsencrypt[testing] python setup.py test -q # -q does not suppress errors [testenv:cover] basepython = python2.7 commands = - python setup.py dev + python setup.py develop easy_install letsencrypt[testing] python setup.py nosetests --with-coverage --cover-min-percentage=66 [testenv:lint]