Merge remote-tracking branch 'upstream/master' into multios_apache

This commit is contained in:
Joona Hoikkala
2015-12-16 17:49:04 +02:00
6 changed files with 115 additions and 29 deletions
+20 -15
View File
@@ -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
@@ -58,8 +63,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 +178,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 +357,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
+9 -7
View File
@@ -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)
@@ -660,7 +662,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)
@@ -668,13 +670,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"):
@@ -767,7 +769,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()
@@ -880,12 +882,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):
@@ -897,7 +899,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):
+38 -1
View File
@@ -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.
@@ -250,7 +253,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 []
+3 -1
View File
@@ -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
+7 -5
View File
@@ -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)
+38
View File
@@ -397,6 +397,44 @@ 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
# 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(), [])
# 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
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