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

This commit is contained in:
sagi 2016-05-23 23:13:43 +00:00
commit 4e41e65bfc
29 changed files with 798 additions and 166 deletions

View file

@ -21,6 +21,7 @@ WORKDIR /opt/certbot
# If <dest> doesn't exist, it is created along with all missing
# directories in its path.
ENV DEBIAN_FRONTEND=noninteractive
COPY letsencrypt-auto-source/letsencrypt-auto /opt/certbot/src/letsencrypt-auto-source/letsencrypt-auto
RUN /opt/certbot/src/letsencrypt-auto-source/letsencrypt-auto --os-packages-only && \

View file

@ -31,14 +31,17 @@ Contributing
If you'd like to contribute to this project please read `Developer Guide
<https://certbot.eff.org/docs/contributing.html>`_.
.. _installation:
Installation
------------
If ``certbot`` (or ``letsencrypt``) is packaged for your Unix OS, you can install
it from there, and run it by typing ``certbot`` (or ``letsencrypt``).
Because not all operating systems have packages yet, we provide a temporary
solution via the ``certbot-auto`` wrapper script, which obtains some
dependencies from your OS and puts others in a python virtual environment::
If ``certbot`` (or ``letsencrypt``) is packaged for your Unix OS (visit
certbot.eff.org_ to find out), you can install it
from there, and run it by typing ``certbot`` (or ``letsencrypt``). Because
not all operating systems have packages yet, we provide a temporary solution
via the ``certbot-auto`` wrapper script, which obtains some dependencies from
your OS and puts others in a python virtual environment::
user@webserver:~$ wget https://dl.eff.org/certbot-auto
user@webserver:~$ chmod a+x ./certbot-auto
@ -188,3 +191,4 @@ Current Features
.. _Freenode: https://webchat.freenode.net?channels=%23letsencrypt
.. _OFTC: https://webchat.oftc.net?channels=%23certbot
.. _client-dev: https://groups.google.com/a/letsencrypt.org/forum/#!forum/client-dev
.. _certbot.eff.org: https://certbot.eff.org/

View file

@ -1,4 +1,5 @@
"""Crypto utilities."""
import binascii
import contextlib
import logging
import re
@ -203,7 +204,7 @@ def gen_ss_cert(key, domains, not_before=None,
"""
assert domains, "Must provide one or more hostnames for the cert."
cert = OpenSSL.crypto.X509()
cert.set_serial_number(1337)
cert.set_serial_number(int(binascii.hexlify(OpenSSL.rand.bytes(16)), 16))
cert.set_version(2)
extensions = [

View file

@ -8,6 +8,8 @@ import unittest
import six
from six.moves import socketserver # pylint: disable=import-error
import OpenSSL
from acme import errors
from acme import jose
from acme import test_util
@ -126,5 +128,23 @@ class PyOpenSSLCertOrReqSANTest(unittest.TestCase):
self._get_idn_names())
class RandomSnTest(unittest.TestCase):
"""Test for random certificate serial numbers."""
def setUp(self):
self.cert_count = 5
self.serial_num = []
self.key = OpenSSL.crypto.PKey()
self.key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
def test_sn_collisions(self):
from acme.crypto_util import gen_ss_cert
for _ in range(self.cert_count):
cert = gen_ss_cert(self.key, ['dummy'], force_san=True)
self.serial_num.append(cert.get_serial_number())
self.assertTrue(len(set(self.serial_num)) > 1)
if __name__ == '__main__':
unittest.main() # pragma: no cover

View file

@ -124,13 +124,16 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.assoc = dict()
# Outstanding challenges
self._chall_out = set()
# Maps enhancements to vhosts we've enabled the enhancement for
self._enhanced_vhosts = defaultdict(set)
# These will be set in the prepare function
self.parser = None
self.version = version
self.vhosts = None
self._enhance_func = {"redirect": self._enable_redirect,
"ensure-http-header": self._set_http_header}
"ensure-http-header": self._set_http_header,
"staple-ocsp": self._enable_ocsp_stapling}
@property
def mod_ssl_conf(self):
@ -593,8 +596,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:type addr: :class:`~certbot_apache.obj.Addr`
"""
loc = parser.get_aug_path(self.parser.loc["name"])
loc = parser.get_aug_path(self.parser.loc["name"])
if addr.get_port() == "443":
path = self.parser.add_dir_to_ifmodssl(
loc, "NameVirtualHost", [str(addr)])
@ -944,7 +947,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
######################################################################
def supported_enhancements(self): # pylint: disable=no-self-use
"""Returns currently supported enhancements."""
return ["redirect", "ensure-http-header"]
return ["redirect", "ensure-http-header", "staple-ocsp"]
def enhance(self, domain, enhancement, options=None):
"""Enhance configuration.
@ -971,6 +974,68 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
logger.warn("Failed %s for %s", enhancement, domain)
raise
def _enable_ocsp_stapling(self, ssl_vhost, unused_options):
"""Enables OCSP Stapling
In OCSP, each client (e.g. browser) would have to query the
OCSP Responder to validate that the site certificate was not revoked.
Enabling OCSP Stapling, would allow the web-server to query the OCSP
Responder, and staple its response to the offered certificate during
TLS. i.e. clients would not have to query the OCSP responder.
OCSP Stapling enablement on Apache implicitly depends on
SSLCertificateChainFile being set by other code.
.. note:: This function saves the configuration
:param ssl_vhost: Destination of traffic, an ssl enabled vhost
:type ssl_vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:param unused_options: Not currently used
:type unused_options: Not Available
:returns: Success, general_vhost (HTTP vhost)
:rtype: (bool, :class:`~letsencrypt_apache.obj.VirtualHost`)
"""
min_apache_ver = (2, 3, 3)
if self.get_version() < min_apache_ver:
raise errors.PluginError(
"Unable to set OCSP directives.\n"
"Apache version is below 2.3.3.")
if "socache_shmcb_module" not in self.parser.modules:
self.enable_mod("socache_shmcb")
# Check if there's an existing SSLUseStapling directive on.
use_stapling_aug_path = self.parser.find_dir("SSLUseStapling",
"on", start=ssl_vhost.path)
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)
# Check if there's an existing SSLStaplingCache directive.
stapling_cache_aug_path = self.parser.find_dir('SSLStaplingCache',
None, ssl_vhost_aug_path)
# We'll simply delete the directive, so that we'll have a
# consistent OCSP cache path.
if stapling_cache_aug_path:
self.aug.remove(
re.sub(r"/\w*$", "", stapling_cache_aug_path[0]))
self.parser.add_dir_to_ifmodssl(ssl_vhost_aug_path,
"SSLStaplingCache",
["shmcb:/var/run/apache2/stapling_cache(128000)"])
msg = "OCSP Stapling was enabled on SSL Vhost: %s.\n"%(
ssl_vhost.filep)
self.save_notes += msg
self.save()
logger.info(msg)
def _set_http_header(self, ssl_vhost, header_substring):
"""Enables header that is identified by header_substring on ssl_vhost.
@ -1058,9 +1123,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param unused_options: Not currently used
:type unused_options: Not Available
:returns: Success, general_vhost (HTTP vhost)
:rtype: (bool, :class:`~certbot_apache.obj.VirtualHost`)
:raises .errors.PluginError: If no viable HTTP host can be created or
used for the redirect.
@ -1083,6 +1145,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"redirection")
self._create_redirect_vhost(ssl_vhost)
else:
if general_vh in self._enhanced_vhosts["redirect"]:
logger.debug("Already enabled redirect for this vhost")
return
# Check if Certbot redirection already exists
self._verify_no_certbot_redirect(general_vh)
@ -1118,6 +1184,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
(general_vh.filep, ssl_vhost.filep))
self.save()
self._enhanced_vhosts["redirect"].add(general_vh)
logger.info("Redirecting vhost in %s to ssl vhost in %s",
general_vh.filep, ssl_vhost.filep)
@ -1177,10 +1244,14 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:type vhost: :class:`~certbot_apache.obj.VirtualHost`
"""
rewrite_engine_path = self.parser.find_dir("RewriteEngine", "on",
rewrite_engine_path_list = self.parser.find_dir("RewriteEngine", "on",
start=vhost.path)
if rewrite_engine_path:
return self.parser.get_arg(rewrite_engine_path[0])
if rewrite_engine_path_list:
for re_path in rewrite_engine_path_list:
# A RewriteEngine directive may also be included in per
# directory .htaccess files. We only care about the VirtualHost.
if 'VirtualHost' in re_path:
return self.parser.get_arg(re_path)
return False
def _create_redirect_vhost(self, ssl_vhost):
@ -1202,6 +1273,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Make a new vhost data structure and add it to the lists
new_vhost = self._create_vhost(parser.get_aug_path(redirect_filepath))
self.vhosts.append(new_vhost)
self._enhanced_vhosts["redirect"].add(new_vhost)
# Finally create documentation for the change
self.save_notes += ("Created a port 80 vhost, %s, for redirection to "

View file

@ -15,6 +15,7 @@ from certbot import errors
from certbot.tests import acme_util
from certbot_apache import configurator
from certbot_apache import parser
from certbot_apache import obj
from certbot_apache.tests import util
@ -85,7 +86,8 @@ class MultipleVhostsTest(util.ApacheTest):
mock_getutility.notification = mock.MagicMock(return_value=True)
names = self.config.get_all_names()
self.assertEqual(names, set(
["certbot.demo", "encryption-example.demo", "ip-172-30-0-17", "*.blue.purple.com"]))
["certbot.demo", "ocspvhost.com", "encryption-example.demo",
"ip-172-30-0-17", "*.blue.purple.com"]))
@mock.patch("zope.component.getUtility")
@mock.patch("certbot_apache.configurator.socket.gethostbyaddr")
@ -100,14 +102,24 @@ class MultipleVhostsTest(util.ApacheTest):
obj.Addr(("zombo.com",)),
obj.Addr(("192.168.1.2"))]),
True, False)
self.config.vhosts.append(vhost)
names = self.config.get_all_names()
self.assertEqual(len(names), 6)
self.assertEqual(len(names), 7)
self.assertTrue("zombo.com" in names)
self.assertTrue("google.com" in names)
self.assertTrue("certbot.demo" in names)
def test_bad_servername_alias(self):
ssl_vh1 = obj.VirtualHost(
"fp1", "ap1", set([obj.Addr(("*", "443"))]),
True, False)
# pylint: disable=protected-access
self.config._add_servernames(ssl_vh1)
self.assertTrue(
self.config._add_servername_alias("oy_vey", ssl_vh1) is None)
def test_add_servernames_alias(self):
self.config.parser.add_dir(
self.vh_truth[2].path, "ServerAlias", ["*.le.co"])
@ -124,7 +136,7 @@ class MultipleVhostsTest(util.ApacheTest):
"""
vhs = self.config.get_virtual_hosts()
self.assertEqual(len(vhs), 7)
self.assertEqual(len(vhs), 8)
found = 0
for vhost in vhs:
@ -135,7 +147,7 @@ class MultipleVhostsTest(util.ApacheTest):
else:
raise Exception("Missed: %s" % vhost) # pragma: no cover
self.assertEqual(found, 7)
self.assertEqual(found, 8)
# Handle case of non-debian layout get_virtual_hosts
with mock.patch(
@ -143,7 +155,7 @@ class MultipleVhostsTest(util.ApacheTest):
) as mock_conf:
mock_conf.return_value = False
vhs = self.config.get_virtual_hosts()
self.assertEqual(len(vhs), 7)
self.assertEqual(len(vhs), 8)
@mock.patch("certbot_apache.display_ops.select_vhost")
def test_choose_vhost_none_avail(self, mock_select):
@ -224,16 +236,18 @@ class MultipleVhostsTest(util.ApacheTest):
# Assume only the two default vhosts.
self.config.vhosts = [
vh for vh in self.config.vhosts
if vh.name not in ["certbot.demo", "encryption-example.demo"]
if vh.name not in ["certbot.demo",
"encryption-example.demo",
"ocspvhost.com"]
and "*.blue.purple.com" not in vh.aliases
]
self.assertEqual(
self.config._find_best_vhost("example.demo"), self.vh_truth[2])
self.config._find_best_vhost("encryption-example.demo"),
self.vh_truth[2])
def test_non_default_vhosts(self):
# pylint: disable=protected-access
self.assertEqual(len(self.config._non_default_vhosts()), 5)
self.assertEqual(len(self.config._non_default_vhosts()), 6)
def test_is_site_enabled(self):
"""Test if site is enabled.
@ -539,7 +553,7 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertEqual(self.config.is_name_vhost(self.vh_truth[0]),
self.config.is_name_vhost(ssl_vhost))
self.assertEqual(len(self.config.vhosts), 8)
self.assertEqual(len(self.config.vhosts), 9)
def test_clean_vhost_ssl(self):
# pylint: disable=protected-access
@ -726,16 +740,15 @@ class MultipleVhostsTest(util.ApacheTest):
def test_get_all_certs_keys(self):
c_k = self.config.get_all_certs_keys()
self.assertEqual(len(c_k), 2)
self.assertEqual(len(c_k), 3)
cert, key, path = next(iter(c_k))
self.assertTrue("cert" in cert)
self.assertTrue("key" in key)
self.assertTrue("default-ssl" in path)
self.assertTrue("default-ssl" in path or "ocsp-ssl" in path)
def test_get_all_certs_keys_malformed_conf(self):
self.config.parser.find_dir = mock.Mock(
side_effect=[["path"], [], ["path"], []])
side_effect=[["path"], [], ["path"], [], ["path"], []])
c_k = self.config.get_all_certs_keys()
self.assertFalse(c_k)
@ -756,15 +769,20 @@ class MultipleVhostsTest(util.ApacheTest):
def test_supported_enhancements(self):
self.assertTrue(isinstance(self.config.supported_enhancements(), list))
@mock.patch("certbot_apache.configurator.ApacheConfigurator._get_http_vhost")
@mock.patch("certbot_apache.display_ops.select_vhost")
@mock.patch("certbot.le_util.exe_exists")
def test_enhance_unknown_vhost(self, mock_exe):
def test_enhance_unknown_vhost(self, mock_exe, mock_sel_vhost, mock_get):
self.config.parser.modules.add("rewrite_module")
mock_exe.return_value = True
ssl_vh = obj.VirtualHost(
"fp", "ap", set([obj.Addr(("*", "443"))]),
ssl_vh1 = obj.VirtualHost(
"fp1", "ap1", set([obj.Addr(("*", "443"))]),
True, False)
ssl_vh.name = "satoshi.com"
self.config.vhosts.append(ssl_vh)
ssl_vh1.name = "satoshi.com"
self.config.vhosts.append(ssl_vh1)
mock_sel_vhost.return_value = None
mock_get.return_value = None
self.assertRaises(
errors.PluginError,
self.config.enhance, "satoshi.com", "redirect")
@ -774,6 +792,85 @@ class MultipleVhostsTest(util.ApacheTest):
errors.PluginError,
self.config.enhance, "certbot.demo", "unknown_enhancement")
@mock.patch("certbot.le_util.run_script")
@mock.patch("certbot.le_util.exe_exists")
def test_ocsp_stapling(self, mock_exe, mock_run_script):
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
self.config.get_version = mock.Mock(return_value=(2, 4, 7))
mock_exe.return_value = True
# This will create an ssl vhost for certbot.demo
self.config.enhance("certbot.demo", "staple-ocsp")
self.assertTrue("socache_shmcb_module" in self.config.parser.modules)
self.assertTrue(mock_run_script.called)
# Get the ssl vhost for certbot.demo
ssl_vhost = self.config.assoc["certbot.demo"]
ssl_use_stapling_aug_path = self.config.parser.find_dir(
"SSLUseStapling", "on", ssl_vhost.path)
self.assertEqual(len(ssl_use_stapling_aug_path), 1)
ssl_vhost_aug_path = parser.get_aug_path(ssl_vhost.filep)
stapling_cache_aug_path = self.config.parser.find_dir('SSLStaplingCache',
"shmcb:/var/run/apache2/stapling_cache(128000)",
ssl_vhost_aug_path)
self.assertEqual(len(stapling_cache_aug_path), 1)
@mock.patch("certbot.le_util.exe_exists")
def test_ocsp_stapling_twice(self, mock_exe):
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
self.config.parser.modules.add("socache_shmcb_module")
self.config.get_version = mock.Mock(return_value=(2, 4, 7))
mock_exe.return_value = True
# Checking the case with already enabled ocsp stapling configuration
self.config.enhance("ocspvhost.com", "staple-ocsp")
# Get the ssl vhost for letsencrypt.demo
ssl_vhost = self.config.assoc["ocspvhost.com"]
ssl_use_stapling_aug_path = self.config.parser.find_dir(
"SSLUseStapling", "on", ssl_vhost.path)
self.assertEqual(len(ssl_use_stapling_aug_path), 1)
ssl_vhost_aug_path = parser.get_aug_path(ssl_vhost.filep)
stapling_cache_aug_path = self.config.parser.find_dir('SSLStaplingCache',
"shmcb:/var/run/apache2/stapling_cache(128000)",
ssl_vhost_aug_path)
self.assertEqual(len(stapling_cache_aug_path), 1)
@mock.patch("certbot.le_util.exe_exists")
def test_ocsp_unsupported_apache_version(self, mock_exe):
mock_exe.return_value = True
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
self.config.parser.modules.add("socache_shmcb_module")
self.config.get_version = mock.Mock(return_value=(2, 2, 0))
self.assertRaises(errors.PluginError,
self.config.enhance, "certbot.demo", "staple-ocsp")
def test_get_http_vhost_third_filter(self):
ssl_vh = obj.VirtualHost(
"fp", "ap", set([obj.Addr(("*", "443"))]),
True, False)
ssl_vh.name = "satoshi.com"
self.config.vhosts.append(ssl_vh)
# pylint: disable=protected-access
http_vh = self.config._get_http_vhost(ssl_vh)
self.assertTrue(http_vh.ssl == False)
@mock.patch("certbot.le_util.run_script")
@mock.patch("certbot.le_util.exe_exists")
def test_http_header_hsts(self, mock_exe, _):
@ -899,7 +996,7 @@ class MultipleVhostsTest(util.ApacheTest):
def test_redirect_with_existing_rewrite(self, mock_exe, _):
self.config.parser.update_runtime_variables = mock.Mock()
mock_exe.return_value = True
self.config.get_version = mock.Mock(return_value=(2, 2))
self.config.get_version = mock.Mock(return_value=(2, 2, 0))
# Create a preexisting rewrite rule
self.config.parser.add_dir(
@ -938,15 +1035,31 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertRaises(
errors.PluginError, self.config._enable_redirect, ssl_vh, "")
def test_redirect_twice(self):
def test_redirect_two_domains_one_vhost(self):
# Skip the enable mod
self.config.parser.modules.add("rewrite_module")
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
self.config.enhance("encryption-example.demo", "redirect")
self.config.enhance("red.blue.purple.com", "redirect")
verify_no_redirect = ("certbot_apache.configurator."
"ApacheConfigurator._verify_no_certbot_redirect")
with mock.patch(verify_no_redirect) as mock_verify:
self.config.enhance("green.blue.purple.com", "redirect")
self.assertFalse(mock_verify.called)
def test_redirect_from_previous_run(self):
# Skip the enable mod
self.config.parser.modules.add("rewrite_module")
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
self.config.enhance("red.blue.purple.com", "redirect")
# Clear state about enabling redirect on this run
# pylint: disable=protected-access
self.config._enhanced_vhosts["redirect"].clear()
self.assertRaises(
errors.PluginEnhancementAlreadyPresent,
self.config.enhance, "encryption-example.demo", "redirect")
self.config.enhance, "green.blue.purple.com", "redirect")
def test_create_own_redirect(self):
self.config.parser.modules.add("rewrite_module")
@ -957,7 +1070,7 @@ class MultipleVhostsTest(util.ApacheTest):
# pylint: disable=protected-access
self.config._enable_redirect(self.vh_truth[1], "")
self.assertEqual(len(self.config.vhosts), 8)
self.assertEqual(len(self.config.vhosts), 9)
def test_create_own_redirect_for_old_apache_version(self):
self.config.parser.modules.add("rewrite_module")
@ -968,7 +1081,7 @@ class MultipleVhostsTest(util.ApacheTest):
# pylint: disable=protected-access
self.config._enable_redirect(self.vh_truth[1], "")
self.assertEqual(len(self.config.vhosts), 8)
self.assertEqual(len(self.config.vhosts), 9)
def test_sift_line(self):
# pylint: disable=protected-access

View file

@ -0,0 +1,36 @@
<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
<VirtualHost 10.2.3.4:443>
# 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
</VirtualHost>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
</IfModule>

View file

@ -0,0 +1 @@
../sites-available/ocsp-ssl.conf

View file

@ -1,2 +1,3 @@
sites-available/certbot.conf, certbot.demo
sites-available/encryption-example.conf, encryption-example.demo
sites-available/ocsp-ssl.conf, ocspvhost.com

View file

@ -156,8 +156,12 @@ def get_vh_truth(temp_dir, config_name):
os.path.join(prefix, "wildcard.conf"),
os.path.join(aug_pre, "wildcard.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]), False, False,
"ip-172-30-0-17", aliases=["*.blue.purple.com"])
]
"ip-172-30-0-17", aliases=["*.blue.purple.com"]),
obj.VirtualHost(
os.path.join(prefix, "ocsp-ssl.conf"),
os.path.join(aug_pre, "ocsp-ssl.conf/IfModule/VirtualHost"),
set([obj.Addr.fromstring("10.2.3.4:443")]), True, True,
"ocspvhost.com")]
return vh_truth
return None # pragma: no cover

View file

@ -731,9 +731,20 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False):
" https:// for every http:// resource.", dest="uir", default=None)
helpful.add(
"security", "--no-uir", action="store_false",
help=" Do not automatically set the \"Content-Security-Policy:"
help="Do not automatically set the \"Content-Security-Policy:"
" upgrade-insecure-requests\" header to every HTTP response.",
dest="uir", default=None)
helpful.add(
"security", "--staple-ocsp", action="store_true",
help="Enables OCSP Stapling. A valid OCSP response is stapled to"
" the certificate that the server offers during TLS.",
dest="staple", default=None)
helpful.add(
"security", "--no-staple-ocsp", action="store_false",
help="Do not automatically enable OCSP Stapling.",
dest="staple", default=None)
helpful.add(
"security", "--strict-permissions", action="store_true",
help="Require that all configuration files are owned by the current "
@ -748,7 +759,8 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False):
" certificate lineage. You can try it with `--dry-run` first. For"
" more fine-grained control, you can renew individual lineages with"
" the `certonly` subcommand. Hooks are available to run commands "
" before and after renewal; see XXX for more information on these.")
" before and after renewal; see"
" https://certbot.eff.org/docs/using.html#renewal for more information on these.")
helpful.add(
"renew", "--pre-hook",
@ -760,7 +772,8 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False):
"renew", "--post-hook",
help="Command to be run in a shell after attempting to obtain/renew "
" certificates. Can be used to deploy renewed certificates, or to restart"
" any servers that were stopped by --pre-hook.")
" any servers that were stopped by --pre-hook. This is only run if"
" an attempt was made to obtain/renew a certificate.")
helpful.add(
"renew", "--renew-hook",
help="Command to be run in a shell once for each successfully renewed certificate."

View file

@ -402,7 +402,8 @@ class Client(object):
supported = self.installer.supported_enhancements()
redirect = config.redirect if "redirect" in supported else False
hsts = config.hsts if "ensure-http-header" in supported else False
uir = config.uir if "ensure-http-header" in supported else False
uir = config.uir if "ensure-http-header" in supported else False
staple = config.staple if "staple-ocsp" in supported else False
if redirect is None:
redirect = enhancements.ask("redirect")
@ -416,9 +417,11 @@ class Client(object):
if uir:
self.apply_enhancement(domains, "ensure-http-header",
"Upgrade-Insecure-Requests")
if staple:
self.apply_enhancement(domains, "staple-ocsp")
msg = ("We were unable to restart web server")
if redirect or hsts or uir:
if redirect or hsts or uir or staple:
with error_handler.ErrorHandler(self._rollback_and_restart, msg):
self.installer.restart()

View file

@ -27,7 +27,7 @@ def _validate_hook(shell_cmd, hook_name):
:raises .errors.HookCommandNotFound: if the command is not found
"""
if shell_cmd:
cmd = shell_cmd.partition(" ")[0]
cmd = shell_cmd.split(None, 1)[0]
if not _prog(cmd):
path = os.environ["PATH"]
msg = "Unable to find {2}-hook command {0} in the PATH.\n(PATH is {1})".format(
@ -39,7 +39,7 @@ def pre_hook(config):
if config.pre_hook and not pre_hook.already:
logger.info("Running pre-hook command: %s", config.pre_hook)
_run_hook(config.pre_hook)
pre_hook.already = True
pre_hook.already = True
pre_hook.already = False
@ -50,6 +50,11 @@ def post_hook(config, final=False):
we're called with final=True before actually doing anything.
"""
if config.post_hook:
if not pre_hook.already:
logger.info("No renewals attempted, so not running post-hook")
if config.verb != "renew":
logger.warn("Sanity failure in renewal hooks")
return
if final or config.verb != "renew":
logger.info("Running post-hook command: %s", config.post_hook)
_run_hook(config.post_hook)

View file

@ -94,10 +94,10 @@ def _auth_from_domains(le_client, config, domains, lineage=None):
if lineage is False:
raise errors.Error("Certificate could not be obtained")
finally:
hooks.post_hook(config)
hooks.post_hook(config, final=False)
if not config.dry_run and not config.verb == "renew":
_report_new_cert(lineage.cert, lineage.fullchain)
_report_new_cert(config, lineage.cert, lineage.fullchain)
return lineage, action
@ -267,7 +267,7 @@ def _find_domains(config, installer):
return domains
def _report_new_cert(cert_path, fullchain_path):
def _report_new_cert(config, cert_path, fullchain_path):
"""Reports the creation of a new certificate to the user.
:param str cert_path: path to cert
@ -285,12 +285,15 @@ def _report_new_cert(cert_path, fullchain_path):
# Unless we're in .csr mode and there really isn't one
and_chain = "has "
path = cert_path
verbswitch = ' with the "certonly" option' if config.verb == "run" else ""
# XXX Perhaps one day we could detect the presence of known old webservers
# and say something more informative here.
msg = ("Congratulations! Your certificate {0} been saved at {1}."
" Your cert will expire on {2}. To obtain a new version of the "
"certificate in the future, simply run Certbot again."
.format(and_chain, path, expiry))
msg = ('Congratulations! Your certificate {0} been saved at {1}.'
' Your cert will expire on {2}. To obtain a new or tweaked version of this '
'certificate in the future, simply run {3} again{4}. '
'To non-interactively renew *all* of your ceriticates, run "{3} renew"'
.format(and_chain, path, expiry, cli.cli_command, verbswitch))
reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
@ -485,7 +488,7 @@ def _csr_obtain_cert(config, le_client):
else:
cert_path, _, cert_fullchain = le_client.save_certificate(
certr, chain, config.cert_path, config.chain_path, config.fullchain_path)
_report_new_cert(cert_path, cert_fullchain)
_report_new_cert(config, cert_path, cert_fullchain)
def obtain_cert(config, plugins, lineage=None):

View file

@ -301,7 +301,10 @@ def _renew_describe_results(config, renew_successes, renew_failures,
def renew_all_lineages(config):
"""Examine each lineage; renew if due and report results"""
if config.domains != []:
# This is trivially False if config.domains is empty
if any(domain not in config.webroot_map for domain in config.domains):
# If more plugins start using cli.add_domains,
# we may want to only log a warning here
raise errors.Error("Currently, the renew verb is only capable of "
"renewing all installed certificates that are due "
"to be renewed; individual domains cannot be "

View file

@ -712,6 +712,12 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
self._test_renew_common(renewalparams=renewalparams,
assert_oc_called=True)
def test_renew_with_webroot_map(self):
renewalparams = {'authenticator': 'webroot'}
self._test_renew_common(
renewalparams=renewalparams, assert_oc_called=True,
args=['renew', '--webroot-map', '{"example.com": "/tmp"}'])
def test_renew_reconstitute_error(self):
# pylint: disable=protected-access
with mock.patch('certbot.main.renewal._reconstitute') as mock_reconstitute:

View file

@ -56,14 +56,22 @@ class HookTest(unittest.TestCase):
return mock_logger.warning
def test_pre_hook(self):
hooks.pre_hook.already = False
config = mock.MagicMock(pre_hook="true")
self._test_a_hook(config, hooks.pre_hook, 1)
config = mock.MagicMock(pre_hook="")
self._test_a_hook(config, hooks.pre_hook, 0)
def test_post_hook(self):
hooks.pre_hook.already = False
# if pre-hook isn't called, post-hook shouldn't be
config = mock.MagicMock(post_hook="true", verb="splonk")
self._test_a_hook(config, hooks.post_hook, 0)
config = mock.MagicMock(post_hook="true", verb="splonk")
self._test_a_hook(config, hooks.pre_hook, 1)
self._test_a_hook(config, hooks.post_hook, 2)
config = mock.MagicMock(post_hook="true", verb="renew")
self._test_a_hook(config, hooks.post_hook, 0)

340
docs/cli-help.txt Normal file
View file

@ -0,0 +1,340 @@
usage:
certbot [SUBCOMMAND] [options] [-d domain] [-d domain] ...
Certbot can obtain and install HTTPS/TLS/SSL certificates. By default,
it will attempt to use a webserver both for obtaining and installing the
cert. Major SUBCOMMANDS are:
(default) run Obtain & install a cert in your current webserver
certonly Obtain cert, but do not install it (aka "auth")
install Install a previously obtained cert in a server
renew Renew previously obtained certs that are near expiry
revoke Revoke a previously obtained certificate
rollback Rollback server configuration changes made during install
config_changes Show changes made to server config during installation
plugins Display information about installed plugins
optional arguments:
-h, --help show this help message and exit
-c CONFIG_FILE, --config CONFIG_FILE
config file path (default: None)
-v, --verbose This flag can be used multiple times to incrementally
increase the verbosity of output, e.g. -vvv. (default:
-3)
-t, --text Use the text output instead of the curses UI.
(default: False)
-n, --non-interactive, --noninteractive
Run without ever asking for user input. This may
require additional command line flags; the client will
try to explain which ones are required if it finds one
missing (default: False)
--dry-run Perform a test run of the client, obtaining test
(invalid) certs but not saving them to disk. This can
currently only be used with the 'certonly' and 'renew'
subcommands. Note: Although --dry-run tries to avoid
making any persistent changes on a system, it is not
completely side-effect free: if used with webserver
authenticator plugins like apache and nginx, it makes
and then reverts temporary config changes in order to
obtain test certs, and reloads webservers to deploy
and then roll back those changes. It also calls --pre-
hook and --post-hook commands if they are defined
because they may be necessary to accurately simulate
renewal. --renew-hook commands are not called.
(default: False)
--register-unsafely-without-email
Specifying this flag enables registering an account
with no email address. This is strongly discouraged,
because in the event of key loss or account compromise
you will irrevocably lose access to your account. You
will also be unable to receive notice about impending
expiration or revocation of your certificates. Updates
to the Subscriber Agreement will still affect you, and
will be effective 14 days after posting an update to
the web site. (default: False)
-m EMAIL, --email EMAIL
Email used for registration and recovery contact.
(default: None)
-d DOMAIN, --domains DOMAIN, --domain DOMAIN
Domain names to apply. For multiple domains you can
use multiple -d flags or enter a comma separated list
of domains as a parameter. (default: [])
--user-agent USER_AGENT
Set a custom user agent string for the client. User
agent strings allow the CA to collect high level
statistics about success rates by OS and plugin. If
you wish to hide your server OS version from the Let's
Encrypt server, set this to "". (default: None)
automation:
Arguments for automating execution & other tweaks
--keep-until-expiring, --keep, --reinstall
If the requested cert matches an existing cert, always
keep the existing one until it is due for renewal (for
the 'run' subcommand this means reinstall the existing
cert) (default: False)
--expand If an existing cert covers some subset of the
requested names, always expand and replace it with the
additional names. (default: False)
--version show program's version number and exit
--force-renewal, --renew-by-default
If a certificate already exists for the requested
domains, renew it now, regardless of whether it is
near expiry. (Often --keep-until-expiring is more
appropriate). Also implies --expand. (default: False)
--allow-subset-of-names
When performing domain validation, do not consider it
a failure if authorizations can not be obtained for a
strict subset of the requested domains. This may be
useful for allowing renewals for multiple domains to
succeed even if some domains no longer point at this
system. This option cannot be used with --csr.
(default: False)
--agree-tos Agree to the ACME Subscriber Agreement (default:
False)
--account ACCOUNT_ID Account ID to use (default: None)
--duplicate Allow making a certificate lineage that duplicates an
existing one (both can be renewed in parallel)
(default: False)
--os-packages-only (letsencrypt-auto only) install OS package
dependencies and then stop (default: False)
--no-self-upgrade (letsencrypt-auto only) prevent the letsencrypt-auto
script from upgrading itself to newer released
versions (default: False)
-q, --quiet Silence all output except errors. Useful for
automation via cron. Implies --non-interactive.
(default: False)
testing:
The following flags are meant for testing purposes only! Do NOT change
them, unless you really know what you're doing!
--debug Show tracebacks in case of errors, and allow
letsencrypt-auto execution on experimental platforms
(default: False)
--no-verify-ssl Disable SSL certificate verification. (default: False)
--tls-sni-01-port TLS_SNI_01_PORT
Port number to perform tls-sni-01 challenge. Boulder
in testing mode defaults to 5001. (default: 443)
--http-01-port HTTP01_PORT
Port used in the SimpleHttp challenge. (default: 80)
--break-my-certs Be willing to replace or renew valid certs with
invalid (testing/staging) certs (default: False)
--test-cert, --staging
Use the staging server to obtain test (invalid) certs;
equivalent to --server https://acme-
staging.api.letsencrypt.org/directory (default: False)
security:
Security parameters & server settings
--rsa-key-size N Size of the RSA key. (default: 2048)
--redirect Automatically redirect all HTTP traffic to HTTPS for
the newly authenticated vhost. (default: None)
--no-redirect Do not automatically redirect all HTTP traffic to
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
the domain. Defends against SSL Stripping. (default:
False)
--no-hsts Do not automatically add the Strict-Transport-Security
header to every HTTP response. (default: False)
--uir Add the "Content-Security-Policy: upgrade-insecure-
requests" header to every HTTP response. Forcing the
browser to use https:// for every http:// resource.
(default: None)
--no-uir Do not automatically set the "Content-Security-Policy:
upgrade-insecure-requests" header to every HTTP
response. (default: None)
--strict-permissions Require that all configuration files are owned by the
current user; only needed if your config is somewhere
unsafe like /tmp/ (default: False)
renew:
The 'renew' subcommand will attempt to renew all certificates (or more
precisely, certificate lineages) you have previously obtained if they are
close to expiry, and print a summary of the results. By default, 'renew'
will reuse the options used to create obtain or most recently successfully
renew each certificate lineage. You can try it with `--dry-run` first. For
more fine-grained control, you can renew individual lineages with the
`certonly` subcommand. Hooks are available to run commands before and
after renewal; see https://certbot.eff.org/docs/using.html#renewal for
more information on these.
--pre-hook PRE_HOOK Command to be run in a shell before obtaining any
certificates. Intended primarily for renewal, where it
can be used to temporarily shut down a webserver that
might conflict with the standalone plugin. This will
only be called if a certificate is actually to be
obtained/renewed. (default: None)
--post-hook POST_HOOK
Command to be run in a shell after attempting to
obtain/renew certificates. Can be used to deploy
renewed certificates, or to restart any servers that
were stopped by --pre-hook. (default: None)
--renew-hook RENEW_HOOK
Command to be run in a shell once for each
successfully renewed certificate.For this command, the
shell variable $RENEWED_LINEAGE will point to
theconfig live subdirectory containing the new certs
and keys; the shell variable $RENEWED_DOMAINS will
contain a space-delimited list of renewed cert domains
(default: None)
certonly:
Options for modifying how a cert is obtained
--csr CSR Path to a Certificate Signing Request (CSR) in DER
format; note that the .csr file *must* contain a
Subject Alternative Name field for each domain you
want certified. Currently --csr only works with the
'certonly' subcommand' (default: None)
install:
Options for modifying how a cert is deployed
revoke:
Options for revocation of certs
rollback:
Options for reverting config changes
--checkpoints N Revert configuration N number of checkpoints.
(default: 1)
plugins:
Plugin options
--init Initialize plugins. (default: False)
--prepare Initialize and prepare plugins. (default: False)
--authenticators Limit to authenticator plugins only. (default: None)
--installers Limit to installer plugins only. (default: None)
config_changes:
Options for showing a history of config changes
--num NUM How many past revisions you want to be displayed
(default: None)
paths:
Arguments changing execution paths & servers
--cert-path CERT_PATH
Path to where cert is saved (with auth --csr),
installed from or revoked. (default: None)
--key-path KEY_PATH Path to private key for cert installation or
revocation (if account key is missing) (default: None)
--fullchain-path FULLCHAIN_PATH
Accompanying path to a full certificate chain (cert
plus chain). (default: None)
--chain-path CHAIN_PATH
Accompanying path to a certificate chain. (default:
None)
--config-dir CONFIG_DIR
Configuration directory. (default: /etc/letsencrypt)
--work-dir WORK_DIR Working directory. (default: /var/lib/letsencrypt)
--logs-dir LOGS_DIR Logs directory. (default: /var/log/letsencrypt)
--server SERVER ACME Directory Resource URI. (default:
https://acme-v01.api.letsencrypt.org/directory)
plugins:
Certbot client supports an extensible plugins architecture. See 'certbot
plugins' for a list of all installed plugins and their names. You can
force a particular plugin by setting options provided below. Running
--help <plugin_name> will list flags specific to that plugin.
-a AUTHENTICATOR, --authenticator AUTHENTICATOR
Authenticator plugin name. (default: None)
-i INSTALLER, --installer INSTALLER
Installer plugin name (also used to find domains).
(default: None)
--configurator CONFIGURATOR
Name of the plugin that is both an authenticator and
an installer. Should not be used together with
--authenticator or --installer. (default: None)
--apache Obtain and install certs using Apache (default: False)
--nginx Obtain and install certs using Nginx (default: False)
--standalone Obtain certs using a "standalone" webserver. (default:
False)
--manual Provide laborious manual instructions for obtaining a
cert (default: False)
--webroot Obtain certs by placing files in a webroot directory.
(default: False)
nginx:
Nginx Web Server - currently doesn't work
--nginx-server-root NGINX_SERVER_ROOT
Nginx server root directory. (default: /etc/nginx)
--nginx-ctl NGINX_CTL
Path to the 'nginx' binary, used for 'configtest' and
retrieving nginx version number. (default: nginx)
standalone:
Automatically use a temporary webserver
--standalone-supported-challenges STANDALONE_SUPPORTED_CHALLENGES
Supported challenges. Preferred in the order they are
listed. (default: tls-sni-01,http-01)
manual:
Manually configure an HTTP server
--manual-test-mode Test mode. Executes the manual command in subprocess.
(default: False)
--manual-public-ip-logging-ok
Automatically allows public IP logging. (default:
False)
webroot:
Place files in webroot directory
--webroot-path WEBROOT_PATH, -w WEBROOT_PATH
public_html / webroot path. This can be specified
multiple times to handle different domains; each
domain will have the webroot path that preceded it.
For instance: `-w /var/www/example -d example.com -d
www.example.com -w /var/www/thing -d thing.net -d
m.thing.net` (default: [])
--webroot-map WEBROOT_MAP
JSON dictionary mapping domains to webroot paths; this
implies -d for each entry. You may need to escape this
from your shell. E.g.: --webroot-map
'{"eg1.is,m.eg1.is":"/www/eg1/", "eg2.is":"/www/eg2"}'
This option is merged with, but takes precedence over,
-w / -d entries. At present, if you put webroot-map in
a config file, it needs to be on a single line, like:
webroot-map = {"example.com":"/var/www"}. (default:
{})
apache:
Apache Web Server - Alpha
--apache-enmod APACHE_ENMOD
Path to the Apache 'a2enmod' binary. (default:
a2enmod)
--apache-dismod APACHE_DISMOD
Path to the Apache 'a2dismod' binary. (default:
a2dismod)
--apache-le-vhost-ext APACHE_LE_VHOST_EXT
SSL vhost configuration extension. (default: -le-
ssl.conf)
--apache-server-root APACHE_SERVER_ROOT
Apache server root directory. (default: /etc/apache2)
--apache-vhost-root APACHE_VHOST_ROOT
Apache server VirtualHost configuration root (default:
/etc/apache2/sites-available)
--apache-challenge-location APACHE_CHALLENGE_LOCATION
Directory path for challenge configuration. (default:
/etc/apache2)
--apache-handle-modules APACHE_HANDLE_MODULES
Let installer handle enabling required modules for
you.(Only Ubuntu/Debian currently) (default: True)
--apache-handle-sites APACHE_HANDLE_SITES
Let installer handle enabling sites for you.(Only
Ubuntu/Debian currently) (default: True)
null:
Null Installer

View file

@ -333,7 +333,7 @@ commands:
.. code-block:: shell
make -C docs clean html
make -C docs clean html man
This should generate documentation in the ``docs/_build/html``
directory.

View file

@ -1,6 +1,6 @@
============
Introduction
============
=====================
README / Introduction
=====================
.. include:: ../README.rst
.. include:: ../CHANGES.rst

View file

@ -1 +1 @@
.. program-output:: certbot --help all
.. literalinclude:: cli-help.txt

View file

@ -5,56 +5,28 @@ User Guide
.. contents:: Table of Contents
:local:
.. _installation:
Getting Certbot
===============
Installation
============
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
instructions `in the README / Introduction <intro.html#installation>`__
__ installation_
.. _certbot.eff.org: https://certbot.eff.org
.. _certbot-auto:
certbot-auto
----------------
The name of the certbot command
-------------------------------
``certbot-auto`` is a wrapper which installs some dependencies
from your OS standard package repositories (e.g. using `apt-get` or
`yum`), and for other dependencies it sets up a virtualized Python
environment with packages downloaded from PyPI [#venv]_. It also
provides automated updates.
To install and run the client, just type...
.. code-block:: shell
./certbot-auto
.. hint:: The Let's Encrypt servers enforce 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
``certbot`` script/binary, you can substitute in
``certbot-auto``. For example, to get basic help you would type:
.. code-block:: shell
./certbot-auto --help
or for full help, type:
.. code-block:: shell
./certbot-auto --help all
``certbot-auto`` is the recommended method of running the Certbot
client beta releases on systems that don't have a packaged version. Debian,
Arch Linux, Gentoo, FreeBSD, and OpenBSD now have native packages, so on those
systems you can just install ``certbot`` (and perhaps
``certbot-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
the :doc:`contributing`. Some `other methods of installation`_ are discussed
below.
Many platforms now have native packages that give you a ``certbot`` or (for
older packages) ``letsencrypt`` command you can run. On others, the
``certbot-auto`` / ``letsencrypt-auto`` installer and wrapper script is a
stand-in. Throughout the documentation, whenever you see references to
``certbot`` script/binary, you should substitute in the name of the command
that certbot.eff.org_ told you to use on your system (``certbot``,
``letsencrypt``, or ``certbot-auto``).
Plugins
@ -291,17 +263,21 @@ Certbot is working hard on improving the renewal process, and we
apologize for any inconveniences you encounter in integrating these
commands into your individual environment.
.. _command-line:
Command line options
====================
Certbot supports a lot of command line options. Here's the full list, from
``certbot --help all``:
.. literalinclude:: cli-help.txt
.. _where-certs:
Where are my certificates?
==========================
First of all, we encourage you to use Apache or nginx installers, both
which perform the certificate management automatically. If, however,
you prefer to manage everything by hand, this section provides
information on where to find necessary files.
All generated keys and issued certificates can be found in
``/etc/letsencrypt/live/$domain``. Rather than copying, please point
your (web) server configuration directly to those files (or create
@ -361,8 +337,8 @@ will cause nasty errors served through the browsers!
.. note:: All files are PEM-encoded (as the filename suffix
suggests). If you need other format, such as DER or PFX, then you
could convert using ``openssl``, but this means you will not
benefit from automatic renewal_!
could convert using ``openssl``. You can automate that with
``--renew-hook`` if you're using automatic renewal_.
.. _config-file:
@ -407,7 +383,7 @@ give us as much information as possible:
also might contain personally identifiable information)
- copy and paste ``certbot --version`` output
- your operating system, including specific version
- specify which installation_ method you've chosen
- specify which installation method you've chosen
Other methods of installation
=============================
@ -484,7 +460,7 @@ repo, if you have not already done so. Then run:
.. code-block:: shell
sudo apt-get install certbot python-certbot-apache -t jessie-backports
sudo apt-get install letsencrypt python-letsencrypt-apache -t jessie-backports
**Fedora**

View file

@ -38,17 +38,6 @@ Help for certbot itself cannot be provided until it is installed.
All arguments are accepted and forwarded to the Certbot client when run."
while getopts ":hnv" arg; do
case $arg in
h)
HELP=1;;
n)
ASSUME_YES=1;;
v)
VERBOSE=1;;
esac
done
for arg in "$@" ; do
case "$arg" in
--debug)
@ -65,9 +54,26 @@ for arg in "$@" ; do
ASSUME_YES=1;;
--verbose)
VERBOSE=1;;
-[!-]*)
while getopts ":hnv" short_arg $arg; do
case "$short_arg" in
h)
HELP=1;;
n)
ASSUME_YES=1;;
v)
VERBOSE=1;;
esac
done;;
esac
done
if [ $BASENAME = "letsencrypt-auto" ]; then
# letsencrypt-auto does not respect --help or --yes for backwards compatibility
ASSUME_YES=1
HELP=0
fi
# certbot-auto needs root access to bootstrap OS dependencies, and
# certbot itself needs root access for almost all modes of operation
# The "normal" case is that sudo is used for the steps that need root, but
@ -107,12 +113,6 @@ else
SUDO=
fi
if [ $BASENAME = "letsencrypt-auto" ]; then
# letsencrypt-auto does not respect --help or --yes for backwards compatibility
ASSUME_YES=1
HELP=0
fi
ExperimentalBootstrap() {
# Arguments: Platform name, bootstrap function name
if [ "$DEBUG" = 1 ]; then
@ -435,7 +435,8 @@ BootstrapMac() {
# Workaround for _dlopen not finding augeas on OS X
if [ "$pkgman" = "port" ] && ! [ -e "/usr/local/lib/libaugeas.dylib" ] && [ -e "/opt/local/lib/libaugeas.dylib" ]; then
echo "Applying augeas workaround"
$SUDO ln -s /opt/local/lib/libaugeas.dylib /usr/local/lib
$SUDO mkdir -p /usr/local/lib/
$SUDO ln -s /opt/local/lib/libaugeas.dylib /usr/local/lib/
fi
if ! hash pip 2>/dev/null; then
@ -451,6 +452,11 @@ BootstrapMac() {
fi
}
BootstrapSmartOS() {
pkgin update
pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv'
}
# Install required OS packages:
Bootstrap() {
@ -483,8 +489,10 @@ Bootstrap() {
ExperimentalBootstrap "FreeBSD" BootstrapFreeBsd
elif uname | grep -iq Darwin ; then
ExperimentalBootstrap "Mac OS X" BootstrapMac
elif grep -iq "Amazon Linux" /etc/issue ; then
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
ExperimentalBootstrap "Joyent SmartOS Zone" BootstrapSmartOS
else
echo "Sorry, I don't know how to bootstrap Certbot on your operating system!"
echo
@ -890,14 +898,16 @@ UNLIKELY_EOF
fi
echo "Installation succeeded."
fi
echo "Requesting root privileges to run certbot..."
if [ -n "$SUDO" ]; then
# SUDO is su wrapper or sudo
echo "Requesting root privileges to run certbot..."
echo " $VENV_BIN/letsencrypt" "$@"
fi
if [ -z "$SUDO_ENV" ] ; then
# SUDO is su wrapper / noop
echo " " $SUDO "$VENV_BIN/letsencrypt" "$@"
$SUDO "$VENV_BIN/letsencrypt" "$@"
else
# sudo
echo " " $SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
$SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
fi
@ -923,7 +933,6 @@ else
fi
if [ "$NO_SELF_UPGRADE" != 1 ]; then
echo "Checking for new version..."
TEMP_DIR=$(TempDir)
# ---------------------------------------------------------------------------
cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py"
@ -1016,7 +1025,7 @@ def verified_new_le_auto(get, tag, temp_dir):
"""
le_auto_dir = environ.get(
'LE_AUTO_DIR_TEMPLATE',
'https://raw.githubusercontent.com/letsencrypt/letsencrypt/%s/'
'https://raw.githubusercontent.com/certbot/certbot/%s/'
'letsencrypt-auto-source/') % tag
write(get(le_auto_dir + 'letsencrypt-auto'), temp_dir, 'letsencrypt-auto')
write(get(le_auto_dir + 'letsencrypt-auto.sig'), temp_dir, 'letsencrypt-auto.sig')

View file

@ -38,17 +38,6 @@ Help for certbot itself cannot be provided until it is installed.
All arguments are accepted and forwarded to the Certbot client when run."
while getopts ":hnv" arg; do
case $arg in
h)
HELP=1;;
n)
ASSUME_YES=1;;
v)
VERBOSE=1;;
esac
done
for arg in "$@" ; do
case "$arg" in
--debug)
@ -65,9 +54,26 @@ for arg in "$@" ; do
ASSUME_YES=1;;
--verbose)
VERBOSE=1;;
-[!-]*)
while getopts ":hnv" short_arg $arg; do
case "$short_arg" in
h)
HELP=1;;
n)
ASSUME_YES=1;;
v)
VERBOSE=1;;
esac
done;;
esac
done
if [ $BASENAME = "letsencrypt-auto" ]; then
# letsencrypt-auto does not respect --help or --yes for backwards compatibility
ASSUME_YES=1
HELP=0
fi
# certbot-auto needs root access to bootstrap OS dependencies, and
# certbot itself needs root access for almost all modes of operation
# The "normal" case is that sudo is used for the steps that need root, but
@ -107,12 +113,6 @@ else
SUDO=
fi
if [ $BASENAME = "letsencrypt-auto" ]; then
# letsencrypt-auto does not respect --help or --yes for backwards compatibility
ASSUME_YES=1
HELP=0
fi
ExperimentalBootstrap() {
# Arguments: Platform name, bootstrap function name
if [ "$DEBUG" = 1 ]; then
@ -154,6 +154,7 @@ DeterminePythonVersion() {
{{ bootstrappers/gentoo_common.sh }}
{{ bootstrappers/free_bsd.sh }}
{{ bootstrappers/mac.sh }}
{{ bootstrappers/smartos.sh }}
# Install required OS packages:
Bootstrap() {
@ -186,8 +187,10 @@ Bootstrap() {
ExperimentalBootstrap "FreeBSD" BootstrapFreeBsd
elif uname | grep -iq Darwin ; then
ExperimentalBootstrap "Mac OS X" BootstrapMac
elif grep -iq "Amazon Linux" /etc/issue ; then
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
ExperimentalBootstrap "Joyent SmartOS Zone" BootstrapSmartOS
else
echo "Sorry, I don't know how to bootstrap Certbot on your operating system!"
echo
@ -252,14 +255,16 @@ UNLIKELY_EOF
fi
echo "Installation succeeded."
fi
echo "Requesting root privileges to run certbot..."
if [ -n "$SUDO" ]; then
# SUDO is su wrapper or sudo
echo "Requesting root privileges to run certbot..."
echo " $VENV_BIN/letsencrypt" "$@"
fi
if [ -z "$SUDO_ENV" ] ; then
# SUDO is su wrapper / noop
echo " " $SUDO "$VENV_BIN/letsencrypt" "$@"
$SUDO "$VENV_BIN/letsencrypt" "$@"
else
# sudo
echo " " $SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
$SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
fi
@ -285,7 +290,6 @@ else
fi
if [ "$NO_SELF_UPGRADE" != 1 ]; then
echo "Checking for new version..."
TEMP_DIR=$(TempDir)
# ---------------------------------------------------------------------------
cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py"

View file

@ -16,7 +16,8 @@ BootstrapMac() {
$pkgcmd augeas
$pkgcmd dialog
if [ "$(which python)" = "/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python" ]; then
if [ "$(which python)" = "/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python" \
-o "$(which python)" = "/usr/bin/python" ]; then
# We want to avoid using the system Python because it requires root to use pip.
# python.org, MacPorts or HomeBrew Python installations should all be OK.
echo "Installing python..."

View file

@ -0,0 +1,4 @@
BootstrapSmartOS() {
pkgin update
pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv'
}

View file

@ -87,7 +87,7 @@ def verified_new_le_auto(get, tag, temp_dir):
"""
le_auto_dir = environ.get(
'LE_AUTO_DIR_TEMPLATE',
'https://raw.githubusercontent.com/letsencrypt/letsencrypt/%s/'
'https://raw.githubusercontent.com/certbot/certbot/%s/'
'letsencrypt-auto-source/') % tag
write(get(le_auto_dir + 'letsencrypt-auto'), temp_dir, 'letsencrypt-auto')
write(get(le_auto_dir + 'letsencrypt-auto.sig'), temp_dir, 'letsencrypt-auto.sig')

View file

@ -71,6 +71,7 @@ dev_extras = [
'nose',
'nosexcover',
'pep8',
'pkginfo<=1.2.1',
'pylint==1.4.2', # upstream #248
'tox',
'twine',

View file

@ -145,6 +145,9 @@ pip install \
kill $!
cd ~-
# get a snapshot of the CLI help for the docs
certbot --help all > docs/cli-help.txt
# freeze before installing anything else, so that we know end-user KGS
# make sure "twine upload" doesn't catch "kgs"
if [ -d ../kgs ] ; then
@ -197,7 +200,7 @@ mv letsencrypt-auto-source/letsencrypt-auto.asc letsencrypt-auto-source/certbot-
cp -p letsencrypt-auto-source/letsencrypt-auto certbot-auto
cp -p letsencrypt-auto-source/letsencrypt-auto letsencrypt-auto
git add certbot-auto letsencrypt-auto letsencrypt-auto-source
git add certbot-auto letsencrypt-auto letsencrypt-auto-source docs/cli-help.txt
git diff --cached
git commit --gpg-sign="$RELEASE_GPG_KEY" -m "Release $version"
git tag --local-user "$RELEASE_GPG_KEY" --sign --message "Release $version" "$tag"