From 16c81250452bb29655d06fbe926594a7cb2183d1 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Mon, 7 Dec 2015 22:01:08 +1300 Subject: [PATCH 01/11] Use print_function not print_statement Change the print statements used into print functions. The print satement is not valid in Python 3, however the print function is valid in at least 2.6+. --- letsencrypt/cli.py | 16 +++++++++------- letsencrypt/renewer.py | 4 +++- letsencrypt/reporter.py | 12 +++++++----- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 348818368..61cde7a3f 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -1,4 +1,6 @@ """Let's Encrypt CLI.""" +from __future__ import print_function + # TODO: Sanity check all input. Be sure to avoid shell code etc... # pylint: disable=too-many-lines # (TODO: split this file into main.py and cli.py) @@ -574,7 +576,7 @@ def plugins_cmd(args, config, plugins): # TODO: Use IDisplay rather than print logger.debug("Filtered plugins: %r", filtered) if not args.init and not args.prepare: - print str(filtered) + print(str(filtered)) return filtered.init(config) @@ -582,13 +584,13 @@ def plugins_cmd(args, config, plugins): # TODO: Use IDisplay rather than print logger.debug("Verified plugins: %r", verified) if not args.prepare: - print str(verified) + print(str(verified)) return verified.prepare() available = verified.available() logger.debug("Prepared plugins: %s", available) - print str(available) + print(str(available)) def read_file(filename, mode="rb"): @@ -681,7 +683,7 @@ class HelpfulArgumentParser(object): self.help_arg = max(help1, help2) if self.help_arg is True: # just --help with no topic; avoid argparse altogether - print usage + print(usage) sys.exit(0) self.visible_topics = self.determine_help_topics(self.help_arg) self.groups = {} # elements are added by .add_group() @@ -785,12 +787,12 @@ class HelpfulArgumentParser(object): """ if self.visible_topics[topic]: - #print "Adding visible group " + topic + #print("Adding visible group " + topic) group = self.parser.add_argument_group(topic, **kwargs) self.groups[topic] = group return group else: - #print "Invisible group " + topic + #print("Invisible group " + topic) return self.silent_parser def add_plugin_args(self, plugins): @@ -802,7 +804,7 @@ class HelpfulArgumentParser(object): """ for name, plugin_ep in plugins.iteritems(): parser_or_group = self.add_group(name, description=plugin_ep.description) - #print parser_or_group + #print(parser_or_group) plugin_ep.plugin_cls.inject_parser_options(parser_or_group, name) def determine_help_topics(self, chosen_topic): diff --git a/letsencrypt/renewer.py b/letsencrypt/renewer.py index 0a490d447..3996cfe67 100644 --- a/letsencrypt/renewer.py +++ b/letsencrypt/renewer.py @@ -7,6 +7,8 @@ within lineages of successor certificates, according to configuration. .. todo:: Call new installer API to restart servers after deployment """ +from __future__ import print_function + import argparse import logging import os @@ -169,7 +171,7 @@ def main(cli_args=sys.argv[1:]): constants.CONFIG_DIRS_MODE, uid) for renewal_file in os.listdir(cli_config.renewal_configs_dir): - print "Processing", renewal_file + print("Processing " + renewal_file) try: # TODO: Before trying to initialize the RenewableCert object, # we could check here whether the combination of the config diff --git a/letsencrypt/reporter.py b/letsencrypt/reporter.py index 0905dfa54..c0c7856a7 100644 --- a/letsencrypt/reporter.py +++ b/letsencrypt/reporter.py @@ -1,4 +1,6 @@ """Collects and displays information to the user.""" +from __future__ import print_function + import collections import logging import os @@ -75,8 +77,8 @@ class Reporter(object): no_exception = sys.exc_info()[0] is None bold_on = sys.stdout.isatty() if bold_on: - print le_util.ANSI_SGR_BOLD - print 'IMPORTANT NOTES:' + print(le_util.ANSI_SGR_BOLD) + print('IMPORTANT NOTES:') first_wrapper = textwrap.TextWrapper( initial_indent=' - ', subsequent_indent=(' ' * 3)) next_wrapper = textwrap.TextWrapper( @@ -89,9 +91,9 @@ class Reporter(object): sys.stdout.write(le_util.ANSI_SGR_RESET) bold_on = False lines = msg.text.splitlines() - print first_wrapper.fill(lines[0]) + print(first_wrapper.fill(lines[0])) if len(lines) > 1: - print "\n".join( - next_wrapper.fill(line) for line in lines[1:]) + print("\n".join( + next_wrapper.fill(line) for line in lines[1:])) if bold_on: sys.stdout.write(le_util.ANSI_SGR_RESET) From 1d3cb57aef450556cadf9bba52b1bdcf39c710cd Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Wed, 9 Dec 2015 10:36:22 +0200 Subject: [PATCH 02/11] Display meaningful error messages in manual domain entry, and give user an option to retry --- letsencrypt/display/ops.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/letsencrypt/display/ops.py b/letsencrypt/display/ops.py index 102dbe3a0..1e0585879 100644 --- a/letsencrypt/display/ops.py +++ b/letsencrypt/display/ops.py @@ -250,7 +250,41 @@ def _choose_names_manually(): "Please enter in your domain name(s) (comma and/or space separated) ") if code == display_util.OK: - return display_util.separate_list_input(input_) + invalid_domains = dict() + retry_message = "" + try: + domain_list = display_util.separate_list_input(input_) + except UnicodeEncodeError: + domain_list = [] + retry_message = ( + "Internationalized domain names are not presently " + "supported.{0}{0}Would you like to re-enter the " + "names?{0}").format(os.linesep) + + for domain in domain_list: + try: + le_util.check_domain_sanity(domain) + except errors.ConfigurationError as e: + invalid_domains[domain] = e.message + + if len(invalid_domains): + retry_message = ( + "One or more of the entered domain names was not valid:" + "{0}{0}").format(os.linesep) + for domain in invalid_domains: + retry_message = retry_message + "{1}: {2}{0}".format( + os.linesep, domain, invalid_domains[domain]) + retry_message = retry_message + ( + "{0}Would you like to re-enter the names?{0}").format( + os.linesep) + + if retry_message: + # We had error in input + retry = util(interfaces.IDisplay).yesno(retry_message) + if retry: + return _choose_names_manually() + else: + return domain_list return [] From 64f3d518a415e0cffe1690e455dda822036ec31b Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Wed, 9 Dec 2015 13:22:39 +0200 Subject: [PATCH 03/11] Test cases for manual domain validation --- letsencrypt/tests/display/ops_test.py | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/letsencrypt/tests/display/ops_test.py b/letsencrypt/tests/display/ops_test.py index 30183b955..4adc572aa 100644 --- a/letsencrypt/tests/display/ops_test.py +++ b/letsencrypt/tests/display/ops_test.py @@ -397,6 +397,39 @@ class ChooseNamesTest(unittest.TestCase): self.assertEqual(get_valid_domains(all_invalid), []) self.assertEqual(len(get_valid_domains(two_valid)), 2) + @mock.patch("letsencrypt.display.ops.util") + def test_choose_manually(self, mock_util): + from letsencrypt.display.ops import _choose_names_manually + from letsencrypt.display import util as display_util + #No retry + mock_util().yesno.return_value = False + #IDN and no retry + mock_util().input.return_value = (display_util.OK, + "uniçodé.com") + self.assertEqual(_choose_names_manually(), []) + #Punycode and no retry + 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 + mock_util().input.return_value = (display_util.OK, + ("example.com," + "valid.example.com")) + self.assertEqual(_choose_names_manually(), + ["example.com", "valid.example.com"]) + #Three iterations + mock_util().input.return_value = (display_util.OK, + "notFQDN") + yn = mock.MagicMock() + yn.side_effect = [True, True, False] + mock_util().yesno = yn + _choose_names_manually() + self.assertEqual(mock_util().yesno.call_count, 3) + class SuccessInstallationTest(unittest.TestCase): # pylint: disable=too-few-public-methods From 5348af6559c87a8065cee4e66421243265bf94b5 Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Wed, 9 Dec 2015 15:03:14 +0200 Subject: [PATCH 04/11] Better coverage and test fixes --- letsencrypt/tests/display/ops_test.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/letsencrypt/tests/display/ops_test.py b/letsencrypt/tests/display/ops_test.py index 4adc572aa..31db47cce 100644 --- a/letsencrypt/tests/display/ops_test.py +++ b/letsencrypt/tests/display/ops_test.py @@ -400,28 +400,33 @@ class ChooseNamesTest(unittest.TestCase): @mock.patch("letsencrypt.display.ops.util") def test_choose_manually(self, mock_util): from letsencrypt.display.ops import _choose_names_manually - from letsencrypt.display import util as display_util - #No retry + # No retry mock_util().yesno.return_value = False - #IDN and no retry + # IDN and no retry mock_util().input.return_value = (display_util.OK, "uniçodé.com") self.assertEqual(_choose_names_manually(), []) - #Punycode and no retry + # IDN exception with previous mocks + with mock.patch("letsencrypt.display.util") as mock_sl: + uerror = UnicodeEncodeError('mock', u'', + 0, 1, 'mock') + mock_sl.separate_list_input.side_effect = uerror + self.assertEqual(_choose_names_manually(), []) + # Punycode and no retry mock_util().input.return_value = (display_util.OK, "xn--ls8h.tld") self.assertEqual(_choose_names_manually(), []) - #non-FQDN and no retry + # non-FQDN and no retry mock_util().input.return_value = (display_util.OK, "notFQDN") self.assertEqual(_choose_names_manually(), []) - #Two valid domains + # Two valid domains mock_util().input.return_value = (display_util.OK, ("example.com," "valid.example.com")) self.assertEqual(_choose_names_manually(), ["example.com", "valid.example.com"]) - #Three iterations + # Three iterations mock_util().input.return_value = (display_util.OK, "notFQDN") yn = mock.MagicMock() From 1ee9435db75092cb0715548bf33f6f6d5a8fe2d2 Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Wed, 9 Dec 2015 15:18:04 +0200 Subject: [PATCH 05/11] PEP8 --- letsencrypt/display/ops.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/letsencrypt/display/ops.py b/letsencrypt/display/ops.py index 1e0585879..5ceb7fcfc 100644 --- a/letsencrypt/display/ops.py +++ b/letsencrypt/display/ops.py @@ -123,6 +123,7 @@ def pick_configurator( config, default, plugins, question, (interfaces.IAuthenticator, interfaces.IInstaller)) + def get_email(more=False, invalid=False): """Prompt for valid email address. @@ -209,6 +210,7 @@ def choose_names(installer): else: return [] + def get_valid_domains(domains): """Helper method for choose_names that implements basic checks on domain names @@ -226,6 +228,7 @@ def get_valid_domains(domains): continue return valid_domains + def _filter_names(names): """Determine which names the user would like to select from a list. From e9a0c90e0f56839b109ccbd2bd34076370ee2036 Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Wed, 9 Dec 2015 16:37:23 +0200 Subject: [PATCH 06/11] Travis bump --- travis_bump.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 travis_bump.txt diff --git a/travis_bump.txt b/travis_bump.txt new file mode 100644 index 000000000..f43876b53 --- /dev/null +++ b/travis_bump.txt @@ -0,0 +1 @@ +bump From dae52e8db387ba44111340f633ac70d54f4f2c3f Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Wed, 9 Dec 2015 16:37:36 +0200 Subject: [PATCH 07/11] Revert "Travis bump" This reverts commit e9a0c90e0f56839b109ccbd2bd34076370ee2036. --- travis_bump.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 travis_bump.txt diff --git a/travis_bump.txt b/travis_bump.txt deleted file mode 100644 index f43876b53..000000000 --- a/travis_bump.txt +++ /dev/null @@ -1 +0,0 @@ -bump From f299646bdb75038cc855efa069580913bb1dca9c Mon Sep 17 00:00:00 2001 From: Patrick Figel Date: Wed, 9 Dec 2015 23:11:55 +0100 Subject: [PATCH 08/11] Add staging server hint to avoid rate limit issues --- docs/using.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 51426183d..694eac9fe 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -31,16 +31,21 @@ Firstly, please `install Git`_ and run the following commands: .. _`install Git`: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git +.. note:: On RedHat/CentOS 6 you will need to enable the EPEL_ + repository before install. + +.. _EPEL: http://fedoraproject.org/wiki/EPEL + To install and run the client you just need to type: .. code-block:: shell ./letsencrypt-auto -.. note:: On RedHat/CentOS 6 you will need to enable the EPEL_ - repository before install. - -.. _EPEL: http://fedoraproject.org/wiki/EPEL +.. hint:: During the beta phase, Let's Encrypt enforces strict rate limits on + the number of certificates issued for one domain. It is recommended to + initially use the test server via `--test-cert` until you get the desired + certificates. Throughout the documentation, whenever you see references to ``letsencrypt`` script/binary, you can substitute in From faa7946a3acd27b8c4c231fe32c8e59aae663339 Mon Sep 17 00:00:00 2001 From: Harlan Lieberman-Berg Date: Sun, 13 Dec 2015 18:14:12 -0500 Subject: [PATCH 09/11] Update Debian using instructions. --- docs/using.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 687901191..1d947f00c 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -58,8 +58,8 @@ or for full help, type: ``letsencrypt-auto`` is the recommended method of running the Let's Encrypt -client beta releases on systems that don't have a packaged version. Debian -experimental, Arch linux and FreeBSD now have native packages, so on those +client beta releases on systems that don't have a packaged version. Debian, +Arch linux and FreeBSD now have native packages, so on those systems you can just install ``letsencrypt`` (and perhaps ``letsencrypt-apache``). If you'd like to run the latest copy from Git, or run your own locally modified copy of the client, follow the instructions in @@ -173,10 +173,10 @@ Renewal In order to renew certificates simply call the ``letsencrypt`` (or letsencrypt-auto_) again, and use the same values when prompted. You can automate it slightly by passing necessary flags on the CLI (see -`--help all`), or even further using the :ref:`config-file`. The -``--renew-by-default`` flag may be helpful for automating renewal. If -you're sure that UI doesn't prompt for any details you can add the -command to ``crontab`` (make it less than every 90 days to avoid +`--help all`), or even further using the :ref:`config-file`. The +``--renew-by-default`` flag may be helpful for automating renewal. If +you're sure that UI doesn't prompt for any details you can add the +command to ``crontab`` (make it less than every 90 days to avoid problems, say every month). Please note that the CA will send notification emails to the address @@ -352,20 +352,20 @@ Operating System Packages sudo pacman -S letsencrypt letsencrypt-apache -**Debian Experimental** +**Debian** -If you run Debian unstable, you can install experimental letsencrypt packages. -Add the line ``deb http://ftp.us.debian.org/debian/ experimental main`` (or -the equivalent for your country) to ``/etc/apt/sources.list``, then run +If you run Debian Stretch or Debian Sid, you can install letsencrypt packages. .. code-block:: shell sudo apt-get update - sudo apt-get -t experimental install letsencrypt python-letsencrypt-apache + sudo apt-get install letsencrypt python-letsencrypt-apache If you don't want to use the Apache plugin, you can ommit the ``python-letsencrypt-apache`` package. +Packages for Debian Jessie are coming in the next few weeks. + **Other Operating Systems** OS packaging is an ongoing effort. If you'd like to package From bbd2d0b996d8b7ae453a2653c453101605b32fee Mon Sep 17 00:00:00 2001 From: bmw Date: Tue, 15 Dec 2015 11:28:02 -0800 Subject: [PATCH 10/11] Revert "Add staging server hint to avoid rate limit issues" --- docs/using.rst | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 931b56164..687901191 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -31,21 +31,16 @@ Firstly, please `install Git`_ and run the following commands: .. _`install Git`: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git -.. note:: On RedHat/CentOS 6 you will need to enable the EPEL_ - repository before install. - -.. _EPEL: http://fedoraproject.org/wiki/EPEL - To install and run the client you just need to type: .. code-block:: shell ./letsencrypt-auto -.. hint:: During the beta phase, Let's Encrypt enforces strict rate limits on - the number of certificates issued for one domain. It is recommended to - initially use the test server via `--test-cert` until you get the desired - certificates. +.. note:: On RedHat/CentOS 6 you will need to enable the EPEL_ + repository before install. + +.. _EPEL: http://fedoraproject.org/wiki/EPEL Throughout the documentation, whenever you see references to ``letsencrypt`` script/binary, you can substitute in From 353ae045e8134870eb74f7a1a2ddad1ff7787577 Mon Sep 17 00:00:00 2001 From: bmw Date: Tue, 15 Dec 2015 17:15:37 -0800 Subject: [PATCH 11/11] Revert "Revert "Add staging server hint to avoid rate limit issues"" --- docs/using.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 1d947f00c..1423d6eba 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -31,16 +31,21 @@ Firstly, please `install Git`_ and run the following commands: .. _`install Git`: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git +.. note:: On RedHat/CentOS 6 you will need to enable the EPEL_ + repository before install. + +.. _EPEL: http://fedoraproject.org/wiki/EPEL + To install and run the client you just need to type: .. code-block:: shell ./letsencrypt-auto -.. note:: On RedHat/CentOS 6 you will need to enable the EPEL_ - repository before install. - -.. _EPEL: http://fedoraproject.org/wiki/EPEL +.. hint:: During the beta phase, Let's Encrypt enforces strict rate limits on + the number of certificates issued for one domain. It is recommended to + initially use the test server via `--test-cert` until you get the desired + certificates. Throughout the documentation, whenever you see references to ``letsencrypt`` script/binary, you can substitute in