From 675e6e212a23d37cfd00e507c8e43c158721e2c4 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Tue, 15 Mar 2016 00:58:47 -0700 Subject: [PATCH 001/186] Add --must-staple flag. --- letsencrypt/cli.py | 3 +++ letsencrypt/crypto_util.py | 20 ++++++++++++++------ letsencrypt/interfaces.py | 2 ++ letsencrypt/tests/crypto_util_test.py | 19 +++++++++++++++++++ 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 8e545a5de..cbd3b0704 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -1589,6 +1589,9 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): helpful.add( "security", "--rsa-key-size", type=int, metavar="N", default=flag_default("rsa_key_size"), help=config_help("rsa_key_size")) + helpful.add( + "security", "--must-staple", action="store_true", + help=config_help("must_staple"), dest="must_staple", default=False) helpful.add( "security", "--redirect", action="store_true", help="Automatically redirect all HTTP traffic to HTTPS for the newly " diff --git a/letsencrypt/crypto_util.py b/letsencrypt/crypto_util.py index 5fdcba843..7856c13cc 100644 --- a/letsencrypt/crypto_util.py +++ b/letsencrypt/crypto_util.py @@ -75,9 +75,11 @@ def init_save_csr(privkey, names, path, csrname="csr-letsencrypt.pem"): :rtype: :class:`letsencrypt.le_util.CSR` """ - csr_pem, csr_der = make_csr(privkey.pem, names) - config = zope.component.getUtility(interfaces.IConfig) + + csr_pem, csr_der = make_csr(privkey.pem, names, + must_staple=config.must_staple) + # Save CSR le_util.make_or_verify_dir(path, 0o755, os.geteuid(), config.strict_permissions) @@ -92,7 +94,7 @@ def init_save_csr(privkey, names, path, csrname="csr-letsencrypt.pem"): # Lower level functions -def make_csr(key_str, domains): +def make_csr(key_str, domains, must_staple=False): """Generate a CSR. :param str key_str: PEM-encoded RSA key. @@ -111,13 +113,19 @@ def make_csr(key_str, domains): req.get_subject().CN = domains[0] # TODO: what to put into req.get_subject()? # TODO: put SAN if len(domains) > 1 - req.add_extensions([ + extensions = [ OpenSSL.crypto.X509Extension( "subjectAltName", critical=False, value=", ".join("DNS:%s" % d for d in domains) - ), - ]) + ) + ] + if must_staple: + extensions.append(OpenSSL.crypto.X509Extension( + "1.3.6.1.5.5.7.1.24", + critical=False, + value="DER:30:03:02:01:05")) + req.add_extensions(extensions) req.set_version(2) req.set_pubkey(pkey) req.sign(pkey, "sha256") diff --git a/letsencrypt/interfaces.py b/letsencrypt/interfaces.py index 1921b1e54..be82787b5 100644 --- a/letsencrypt/interfaces.py +++ b/letsencrypt/interfaces.py @@ -200,6 +200,8 @@ class IConfig(zope.interface.Interface): email = zope.interface.Attribute( "Email used for registration and recovery contact.") rsa_key_size = zope.interface.Attribute("Size of the RSA key.") + must_staple = zope.interface.Attribute( + "Whether to request the OCSP Must Staple extension.") config_dir = zope.interface.Attribute("Configuration directory.") work_dir = zope.interface.Attribute("Working directory.") diff --git a/letsencrypt/tests/crypto_util_test.py b/letsencrypt/tests/crypto_util_test.py index 1a9f39572..ec35fc688 100644 --- a/letsencrypt/tests/crypto_util_test.py +++ b/letsencrypt/tests/crypto_util_test.py @@ -95,6 +95,25 @@ class MakeCSRTest(unittest.TestCase): ['example.com', 'www.example.com'], get_sans_from_csr( csr_der, OpenSSL.crypto.FILETYPE_ASN1)) + def test_must_staple(self): + # TODO: Fails for RSA256_KEY + csr_pem, _ = self._call( + RSA512_KEY, ['example.com', 'www.example.com'], must_staple=True) + csr = OpenSSL.crypto.load_certificate_request( + OpenSSL.crypto.FILETYPE_PEM, csr_pem) + + # In pyopenssl 0.13 (used with TOXENV=py26-oldest and py27-oldest), csr + # objects don't have a get_extensions() method, so we skip this test if + # the method isn't available. + if hasattr(csr, 'get_extensions'): + # NOTE: Ideally we would filter by the TLS Feature OID, but + # OpenSSL.crypto.X509Extension doesn't give us the extension's raw OID, + # and the shortname field is just "UNDEF" + must_staple_exts = [e for e in csr.get_extensions() + if e.get_data() == "0\x03\x02\x01\x05"] + self.assertEqual(len(must_staple_exts), 1, + "Expected exactly one Must Staple extension") + class ValidCSRTest(unittest.TestCase): """Tests for letsencrypt.crypto_util.valid_csr.""" From 82beb6f705093f5e82b2c9bdb8013276dcb92939 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Wed, 16 Mar 2016 16:25:41 -0700 Subject: [PATCH 002/186] Update must-staple help. --- letsencrypt/interfaces.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/letsencrypt/interfaces.py b/letsencrypt/interfaces.py index be82787b5..a2e8506e6 100644 --- a/letsencrypt/interfaces.py +++ b/letsencrypt/interfaces.py @@ -201,7 +201,9 @@ class IConfig(zope.interface.Interface): "Email used for registration and recovery contact.") rsa_key_size = zope.interface.Attribute("Size of the RSA key.") must_staple = zope.interface.Attribute( - "Whether to request the OCSP Must Staple extension.") + "Whether to request the OCSP Must Staple certificate extension. " + "Additional setup may be required after issuance. This does not " + "currently autoconfigure web servers for OCSP stapling. ") config_dir = zope.interface.Attribute("Configuration directory.") work_dir = zope.interface.Attribute("Working directory.") From 15502bb64e50b75a4a5e46a29179492c1b5c9fda Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 17 Mar 2016 16:14:29 -0700 Subject: [PATCH 003/186] renew implies noninteractive should be a property of config Not a property of the config we change later --- letsencrypt/cli.py | 3 +++ letsencrypt/main.py | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 017e0a62e..d3ffd3441 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -409,6 +409,9 @@ class HelpfulArgumentParser(object): # Do any post-parsing homework here + if self.verb == "renew": + self.noninteractive_mode = True + # we get domains from -d, but also from the webroot map... if parsed_args.webroot_map: for domain in parsed_args.webroot_map.keys(): diff --git a/letsencrypt/main.py b/letsencrypt/main.py index 8d59993df..0148bdeca 100644 --- a/letsencrypt/main.py +++ b/letsencrypt/main.py @@ -685,9 +685,6 @@ def main(cli_args=sys.argv[1:]): displayer = display_util.NoninteractiveDisplay(sys.stdout) elif config.text_mode: displayer = display_util.FileDisplay(sys.stdout) - elif config.verb == "renew": - config.noninteractive_mode = True - displayer = display_util.NoninteractiveDisplay(sys.stdout) else: displayer = display_util.NcursesDisplay() zope.component.provideUtility(displayer) From bd7d85fd601eab333d83bd7264bc5bc2bef4c3e9 Mon Sep 17 00:00:00 2001 From: Maikel Date: Mon, 21 Mar 2016 13:52:56 +0100 Subject: [PATCH 004/186] Fix symlink webroot paths When using symlinks for webroot folders and requesting SSL for same websites with symlink domains. The challenges files and acme-challenge directory are removed on the first domain and on second domain the acme-challenge directory is already removed and tries to remove it again. --- letsencrypt/plugins/webroot.py | 3 +++ letsencrypt/plugins/webroot_test.py | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/letsencrypt/plugins/webroot.py b/letsencrypt/plugins/webroot.py index 6d2899511..6254719ed 100644 --- a/letsencrypt/plugins/webroot.py +++ b/letsencrypt/plugins/webroot.py @@ -155,5 +155,8 @@ to serve all files under specified web root ({0}).""" elif exc.errno == errno.EACCES: logger.debug("Challenges cleaned up but no permissions for %s", root_path) + elif exc.errno == errno.ENOENT: + logger.debug("Challenges cleaned up, %s does not exists", + root_path) else: raise diff --git a/letsencrypt/plugins/webroot_test.py b/letsencrypt/plugins/webroot_test.py index ed0326555..b39e3912a 100644 --- a/letsencrypt/plugins/webroot_test.py +++ b/letsencrypt/plugins/webroot_test.py @@ -176,12 +176,25 @@ class AuthenticatorTest(unittest.TestCase): self.auth.perform([self.achall]) os_error = OSError() - os_error.errno = errno.ENOENT + os_error.errno = errno.EPERM mock_rmdir.side_effect = os_error self.assertRaises(OSError, self.auth.cleanup, [self.achall]) self.assertFalse(os.path.exists(self.validation_path)) self.assertTrue(os.path.exists(self.root_challenge_path)) + @mock.patch('os.rmdir') + def test_cleanup_file_not_exists(self, mock_rmdir): + self.auth.prepare() + self.auth.perform([self.achall]) + + os_error = OSError() + os_error.errno = errno.ENOENT + mock_rmdir.side_effect = os_error + + self.auth.cleanup([self.achall]) + self.assertFalse(os.path.exists(self.validation_path)) + self.assertTrue(os.path.exists(self.root_challenge_path)) + if __name__ == "__main__": unittest.main() # pragma: no cover From e2af5ab9b495ca22009b5b251cd2d1df48635872 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Fri, 1 Apr 2016 16:42:44 -0700 Subject: [PATCH 005/186] updated docs with s/letsencrypt/certbot/g and more --- docs/api/account.rst | 4 +- docs/api/achallenges.rst | 4 +- docs/api/auth_handler.rst | 4 +- docs/api/cb_util.rst | 5 ++ docs/api/client.rst | 4 +- docs/api/configuration.rst | 4 +- docs/api/constants.rst | 4 +- docs/api/continuity_auth.rst | 4 +- docs/api/crypto_util.rst | 4 +- docs/api/display.rst | 16 ++-- docs/api/errors.rst | 4 +- docs/api/index.rst | 4 +- docs/api/interfaces.rst | 4 +- docs/api/le_util.rst | 5 -- docs/api/log.rst | 4 +- docs/api/plugins/common.rst | 4 +- docs/api/plugins/disco.rst | 4 +- docs/api/plugins/manual.rst | 4 +- docs/api/plugins/standalone.rst | 4 +- docs/api/plugins/util.rst | 4 +- docs/api/plugins/webroot.rst | 4 +- docs/api/proof_of_possession.rst | 4 +- docs/api/reporter.rst | 4 +- docs/api/reverter.rst | 4 +- docs/api/storage.rst | 4 +- docs/ciphers.rst | 80 ++++++++--------- docs/contributing.rst | 60 ++++++------- docs/index.rst | 2 +- docs/man/certbot.rst | 1 + docs/man/letsencrypt.rst | 1 - docs/packaging.rst | 2 +- docs/using.rst | 146 +++++++++++++++---------------- 32 files changed, 201 insertions(+), 205 deletions(-) create mode 100644 docs/api/cb_util.rst delete mode 100644 docs/api/le_util.rst create mode 100644 docs/man/certbot.rst delete mode 100644 docs/man/letsencrypt.rst diff --git a/docs/api/account.rst b/docs/api/account.rst index 16c2061a8..fd90230ea 100644 --- a/docs/api/account.rst +++ b/docs/api/account.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.account` +:mod:`certbot.account` -------------------------- -.. automodule:: letsencrypt.account +.. automodule:: certbot.account :members: diff --git a/docs/api/achallenges.rst b/docs/api/achallenges.rst index 09cec1702..90dda3f06 100644 --- a/docs/api/achallenges.rst +++ b/docs/api/achallenges.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.achallenges` +:mod:`certbot.achallenges` ------------------------------ -.. automodule:: letsencrypt.achallenges +.. automodule:: certbot.achallenges :members: diff --git a/docs/api/auth_handler.rst b/docs/api/auth_handler.rst index 3b168faf8..8819bb1bd 100644 --- a/docs/api/auth_handler.rst +++ b/docs/api/auth_handler.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.auth_handler` +:mod:`certbot.auth_handler` ------------------------------- -.. automodule:: letsencrypt.auth_handler +.. automodule:: certbot.auth_handler :members: diff --git a/docs/api/cb_util.rst b/docs/api/cb_util.rst new file mode 100644 index 000000000..066fa906c --- /dev/null +++ b/docs/api/cb_util.rst @@ -0,0 +1,5 @@ +:mod:`certbot.cb_util` +-------------------------- + +.. automodule:: certbot.cb_util + :members: diff --git a/docs/api/client.rst b/docs/api/client.rst index 7fe44df50..00a443cd9 100644 --- a/docs/api/client.rst +++ b/docs/api/client.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.client` +:mod:`certbot.client` ------------------------- -.. automodule:: letsencrypt.client +.. automodule:: certbot.client :members: diff --git a/docs/api/configuration.rst b/docs/api/configuration.rst index e92392b99..4e99c73d2 100644 --- a/docs/api/configuration.rst +++ b/docs/api/configuration.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.configuration` +:mod:`certbot.configuration` -------------------------------- -.. automodule:: letsencrypt.configuration +.. automodule:: certbot.configuration :members: diff --git a/docs/api/constants.rst b/docs/api/constants.rst index 3a2815b5e..e225056a2 100644 --- a/docs/api/constants.rst +++ b/docs/api/constants.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.constants` +:mod:`certbot.constants` ----------------------------------- -.. automodule:: letsencrypt.constants +.. automodule:: certbot.constants :members: diff --git a/docs/api/continuity_auth.rst b/docs/api/continuity_auth.rst index 82869e6f4..3276220f5 100644 --- a/docs/api/continuity_auth.rst +++ b/docs/api/continuity_auth.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.continuity_auth` +:mod:`certbot.continuity_auth` ---------------------------------- -.. automodule:: letsencrypt.continuity_auth +.. automodule:: certbot.continuity_auth :members: diff --git a/docs/api/crypto_util.rst b/docs/api/crypto_util.rst index 5d4c77538..2f473944c 100644 --- a/docs/api/crypto_util.rst +++ b/docs/api/crypto_util.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.crypto_util` +:mod:`certbot.crypto_util` ------------------------------ -.. automodule:: letsencrypt.crypto_util +.. automodule:: certbot.crypto_util :members: diff --git a/docs/api/display.rst b/docs/api/display.rst index 117a91708..1a18e6534 100644 --- a/docs/api/display.rst +++ b/docs/api/display.rst @@ -1,23 +1,23 @@ -:mod:`letsencrypt.display` +:mod:`certbot.display` -------------------------- -.. automodule:: letsencrypt.display +.. automodule:: certbot.display :members: -:mod:`letsencrypt.display.util` +:mod:`certbot.display.util` =============================== -.. automodule:: letsencrypt.display.util +.. automodule:: certbot.display.util :members: -:mod:`letsencrypt.display.ops` +:mod:`certbot.display.ops` ============================== -.. automodule:: letsencrypt.display.ops +.. automodule:: certbot.display.ops :members: -:mod:`letsencrypt.display.enhancements` +:mod:`certbot.display.enhancements` ======================================= -.. automodule:: letsencrypt.display.enhancements +.. automodule:: certbot.display.enhancements :members: diff --git a/docs/api/errors.rst b/docs/api/errors.rst index 1ad13235c..a9324765b 100644 --- a/docs/api/errors.rst +++ b/docs/api/errors.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.errors` +:mod:`certbot.errors` ------------------------- -.. automodule:: letsencrypt.errors +.. automodule:: certbot.errors :members: diff --git a/docs/api/index.rst b/docs/api/index.rst index a2475eeae..be94214c9 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt` +:mod:`certbot` ------------------ -.. automodule:: letsencrypt +.. automodule:: certbot :members: diff --git a/docs/api/interfaces.rst b/docs/api/interfaces.rst index 00b0a1e50..2988b3b87 100644 --- a/docs/api/interfaces.rst +++ b/docs/api/interfaces.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.interfaces` +:mod:`certbot.interfaces` ----------------------------- -.. automodule:: letsencrypt.interfaces +.. automodule:: certbot.interfaces :members: diff --git a/docs/api/le_util.rst b/docs/api/le_util.rst deleted file mode 100644 index 8c6b717cf..000000000 --- a/docs/api/le_util.rst +++ /dev/null @@ -1,5 +0,0 @@ -:mod:`letsencrypt.le_util` --------------------------- - -.. automodule:: letsencrypt.le_util - :members: diff --git a/docs/api/log.rst b/docs/api/log.rst index f41c6c4b1..41311de90 100644 --- a/docs/api/log.rst +++ b/docs/api/log.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.log` +:mod:`certbot.log` ---------------------- -.. automodule:: letsencrypt.log +.. automodule:: certbot.log :members: diff --git a/docs/api/plugins/common.rst b/docs/api/plugins/common.rst index ca55ba8fb..7cfaf8d70 100644 --- a/docs/api/plugins/common.rst +++ b/docs/api/plugins/common.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.plugins.common` +:mod:`certbot.plugins.common` --------------------------------- -.. automodule:: letsencrypt.plugins.common +.. automodule:: certbot.plugins.common :members: diff --git a/docs/api/plugins/disco.rst b/docs/api/plugins/disco.rst index 7bf2b76b4..1a27f0f69 100644 --- a/docs/api/plugins/disco.rst +++ b/docs/api/plugins/disco.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.plugins.disco` +:mod:`certbot.plugins.disco` -------------------------------- -.. automodule:: letsencrypt.plugins.disco +.. automodule:: certbot.plugins.disco :members: diff --git a/docs/api/plugins/manual.rst b/docs/api/plugins/manual.rst index 4661ab7df..eea443499 100644 --- a/docs/api/plugins/manual.rst +++ b/docs/api/plugins/manual.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.plugins.manual` +:mod:`certbot.plugins.manual` --------------------------------- -.. automodule:: letsencrypt.plugins.manual +.. automodule:: certbot.plugins.manual :members: diff --git a/docs/api/plugins/standalone.rst b/docs/api/plugins/standalone.rst index f5b9d9c24..60aa48b4f 100644 --- a/docs/api/plugins/standalone.rst +++ b/docs/api/plugins/standalone.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.plugins.standalone` +:mod:`certbot.plugins.standalone` ------------------------------------- -.. automodule:: letsencrypt.plugins.standalone +.. automodule:: certbot.plugins.standalone :members: diff --git a/docs/api/plugins/util.rst b/docs/api/plugins/util.rst index 6bc8995db..30ab3d49f 100644 --- a/docs/api/plugins/util.rst +++ b/docs/api/plugins/util.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.plugins.util` +:mod:`certbot.plugins.util` ------------------------------- -.. automodule:: letsencrypt.plugins.util +.. automodule:: certbot.plugins.util :members: diff --git a/docs/api/plugins/webroot.rst b/docs/api/plugins/webroot.rst index 339d546a5..e1f4523f7 100644 --- a/docs/api/plugins/webroot.rst +++ b/docs/api/plugins/webroot.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.plugins.webroot` +:mod:`certbot.plugins.webroot` ---------------------------------- -.. automodule:: letsencrypt.plugins.webroot +.. automodule:: certbot.plugins.webroot :members: diff --git a/docs/api/proof_of_possession.rst b/docs/api/proof_of_possession.rst index db8c6c563..2e7642a45 100644 --- a/docs/api/proof_of_possession.rst +++ b/docs/api/proof_of_possession.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.proof_of_possession` +:mod:`certbot.proof_of_possession` -------------------------------------- -.. automodule:: letsencrypt.proof_of_possession +.. automodule:: certbot.proof_of_possession :members: diff --git a/docs/api/reporter.rst b/docs/api/reporter.rst index 03260f9cd..ad71dbb69 100644 --- a/docs/api/reporter.rst +++ b/docs/api/reporter.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.reporter` +:mod:`certbot.reporter` --------------------------- -.. automodule:: letsencrypt.reporter +.. automodule:: certbot.reporter :members: diff --git a/docs/api/reverter.rst b/docs/api/reverter.rst index 4c220124f..3e0ac750b 100644 --- a/docs/api/reverter.rst +++ b/docs/api/reverter.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.reverter` +:mod:`certbot.reverter` --------------------------- -.. automodule:: letsencrypt.reverter +.. automodule:: certbot.reverter :members: diff --git a/docs/api/storage.rst b/docs/api/storage.rst index 198d85b46..34e3a45c0 100644 --- a/docs/api/storage.rst +++ b/docs/api/storage.rst @@ -1,5 +1,5 @@ -:mod:`letsencrypt.storage` +:mod:`certbot.storage` -------------------------- -.. automodule:: letsencrypt.storage +.. automodule:: certbot.storage :members: diff --git a/docs/ciphers.rst b/docs/ciphers.rst index ef644b7a0..be6784276 100644 --- a/docs/ciphers.rst +++ b/docs/ciphers.rst @@ -17,15 +17,13 @@ Autoupdates Within certain limits, TLS server software can choose what kind of cryptography to use when a client connects. These choices can affect security, compatibility, and performance in complex ways. Most of -these options are independent of a particular certificate. The Let's -Encrypt client tries to provide defaults that we think are most useful -to our users. +these options are independent of a particular certificate. Certbot +tries to provide defaults that we think are most useful to our users. -As described below, the Let's Encrypt client will default to modifying +As described below, Certbot will default to modifying server software's cryptographic settings to keep these up-to-date with -what we think are appropriate defaults when new versions of the Let's -Encrypt client are installed (for example, by an operating system package -manager). +what we think are appropriate defaults when new versions of the Certbot +are installed (for example, by an operating system package manager). When this feature is implemented, this document will be updated to describe how to disable these automatic changes. @@ -54,7 +52,7 @@ improve, others' security. But important information that improves our understanding of the state of the art is published regularly. When enabling TLS support in a compatible web server (which is a separate -step from obtaining a certificate), Let's Encrypt has the ability to +step from obtaining a certificate), Certbot has the ability to update that web server's TLS configuration. Again, this is *different from the cryptographic particulars of the certificate itself*; the certificate as of the initial release will be RSA-signed using one of @@ -80,30 +78,29 @@ art. However, the Let's Encrypt certificate authority does *not* dictate end-users' security policy, and any site is welcome to change its preferences in accordance with its own policy or its administrators' preferences, and use different cryptographic mechanisms or parameters, -or a different priority order, than the defaults provided by the Let's -Encrypt client. +or a different priority order, than the defaults provided by Certbot. -If you don't use the Let's Encrypt client to configure your server -directly, because the client doesn't integrate with your server software -or because you chose not to use this integration, then the cryptographic -defaults haven't been modified, and the cryptography chosen by the server -will still be whatever the default for your software was. For example, -if you obtain a certificate using *standalone* mode and then manually -install it in an IMAP or LDAP server, your cryptographic settings will -not be modified by the client in any way. +If you don't use Certbot to configure your server directly, because the +client doesn't integrate with your server software or because you chose +not to use this integration, then the cryptographic defaults haven't been +modified, and the cryptography chosen by the server will still be whatever +the default for your software was. For example, if you obtain a +certificate using *standalone* mode and then manually install it in an IMAP +or LDAP server, your cryptographic settings will not be modified by the +client in any way. Sources of defaults ------------------- -Initially, the Let's Encrypt client will configure users' servers to -use the cryptographic defaults recommended by the Mozilla project. -These settings are well-reasoned recommendations that carefully -consider client software compatibility. They are described at +Initially, Certbot will configure users' servers to use the cryptographic +defaults recommended by the Mozilla project. These settings are well-reasoned +recommendations that carefully consider client software compatibility. They +are described at https://wiki.mozilla.org/Security/Server_Side_TLS -and the version implemented by the Let's Encrypt client will be the +and the version implemented by Certbot will be the version that was most current as of the release date of each client version. Mozilla offers three separate sets of cryptographic options, which trade off security and compatibility differently. These are @@ -113,12 +110,12 @@ to most-backwards compatible). The client will follow the Mozilla defaults for the *Intermediate* configuration by default, at least with regards to ciphersuites and TLS versions. Mozilla's web site describes which client software will be compatible with each configuration. You can also use -the Qualys SSL Labs site, which the Let's Encrypt software will suggest +the Qualys SSL Labs site, which Certbot will suggest when installing a certificate, to test your server and see whether it will be compatible with particular software versions. -It will be possible to ask the Let's Encrypt client to instead apply -(and track) Modern or Old configurations. +It will be possible to ask Certbot to instead apply (and track) Modern +or Old configurations. The Let's Encrypt project expects to follow the Mozilla recommendations in the future as those recommendations are updated. (For example, some @@ -127,15 +124,15 @@ which uses the ChaCha and Poly1305 algorithms, and which is already implemented by the Chrome browser. Mozilla has delayed recommending ``0xcc13`` over compatibility and standardization concerns, but is likely to recommend it in the future once these concerns have been addressed. At -that point, the Let's Encrypt client would likely follow the Mozilla -recommendations and favor the use of this ciphersuite as well.) +that point, Certbot would likely follow the Mozilla recommendations and favor +the use of this ciphersuite as well.) The Let's Encrypt project may deviate from the Mozilla recommendations in the future if good cause is shown and we believe our users' priorities would be well-served by doing so. In general, please address relevant proposals for changing priorities to the Mozilla security -team first, before asking the Let's Encrypt project to change the -client's priorities. The Mozilla security team is likely to have more +team first, before asking the Let's Encrypt project to change +Certbot's priorities. The Mozilla security team is likely to have more resources and expertise to bring to bear on evaluating reasons why its recommendations should be updated. @@ -144,8 +141,8 @@ small number of alternative configurations (apart from Modern, Intermediate, and Old) that there's reason to believe would be widely used by sysadmins; this would usually be a preferable course to modifying an existing configuration. For example, if many sysadmins want their -servers configured to track a different expert recommendation, Let's -Encrypt could add an option to do so. +servers configured to track a different expert recommendation, Certbot +could add an option to do so. Resources for recommendations @@ -156,9 +153,9 @@ recommendations with sources of expert guidance on ciphersuites and other cryptographic parameters. We're grateful to everyone who contributed suggestions. The recommendations we received are available at -https://github.com/letsencrypt/letsencrypt/wiki/Ciphersuite-guidance +https://github.com/certbot/certbot/wiki/Ciphersuite-guidance -Let's Encrypt client users are welcome to review these authorities to +Certbot users are welcome to review these authorities to better inform their own cryptographic parameter choices. We also welcome suggestions of other resources to add to this list. Please keep in mind that different recommendations may reflect different priorities @@ -172,23 +169,22 @@ This will probably look something like .. code-block:: shell - letsencrypt --cipher-recommendations mozilla-secure - letsencrypt --cipher-recommendations mozilla-intermediate - letsencrypt --cipher-recommendations mozilla-old + certbot --cipher-recommendations mozilla-secure + certbot --cipher-recommendations mozilla-intermediate + certbot --cipher-recommendations mozilla-old to track Mozilla's *Secure*, *Intermediate*, or *Old* recommendations, and .. code-block:: shell - letsencrypt --update-ciphers on + certbot --update-ciphers on -to enable updating ciphers with each new Let's Encrypt client release, -or +to enable updating ciphers with each new Certbot release, or .. code-block:: shell - letsencrypt --update-ciphers off + certbot --update-ciphers off to disable automatic configuration updates. These features have not yet been implemented and this syntax may change then they are implemented. @@ -200,7 +196,7 @@ TODO The status of this feature is tracked as part of issue #1123 in our bug tracker. -https://github.com/letsencrypt/letsencrypt/issues/1123 +https://github.com/certbot/certbot/issues/1123 Prior to implementation of #1123, the client does not actually modify ciphersuites (this is intended to be implemented as a "configuration diff --git a/docs/contributing.rst b/docs/contributing.rst index 69604780c..5a9afd5c5 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -15,14 +15,14 @@ Running a local copy of the client ---------------------------------- Running the client in developer mode from your local tree is a little -different than running ``letsencrypt-auto``. To get set up, do these things +different than running ``certbot-auto``. To get set up, do these things once: .. code-block:: shell - git clone https://github.com/letsencrypt/letsencrypt - cd letsencrypt - ./letsencrypt-auto-source/letsencrypt-auto --os-packages-only + git clone https://github.com/certbot/certbot + cd certbot + ./certbot-auto-source/certbot-auto --os-packages-only ./tools/venv.sh Then in each shell where you're working on the client, do: @@ -36,7 +36,7 @@ client by typing: .. code-block:: shell - letsencrypt + certbot Activating a shell in this way makes it easier to run unit tests with ``tox`` and integration tests, as described below. To reverse this, you @@ -57,8 +57,8 @@ your pull request must have thorough unit test coverage, pass our `integration`_ tests, and be compliant with the :ref:`coding style `. -.. _github issue tracker: https://github.com/letsencrypt/letsencrypt/issues -.. _Good Volunteer Task: https://github.com/letsencrypt/letsencrypt/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+Volunteer+Task%22 +.. _github issue tracker: https://github.com/certbot/certbot/issues +.. _Good Volunteer Task: https://github.com/certbot/certbot/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+Volunteer+Task%22 Testing ------- @@ -97,7 +97,7 @@ Generally it is sufficient to open a pull request and let Github and Travis run integration tests for you. However, if you prefer to run tests, you can use Vagrant, using the Vagrantfile -in Let's Encrypt's repository. To execute the tests on a Vagrant box, the only +in Certbot's repository. To execute the tests on a Vagrant box, the only command you are required to run is:: ./tests/boulder-integration.sh @@ -141,12 +141,12 @@ and ``nginx.wtf`` to 127.0.0.1. You may now run (in a separate terminal):: ./tests/boulder-integration.sh && echo OK || echo FAIL -If you would like to test `letsencrypt_nginx` plugin (highly +If you would like to test `certbot_nginx` plugin (highly encouraged) make sure to install prerequisites as listed in -``letsencrypt-nginx/tests/boulder-integration.sh`` and rerun +``certbot-nginx/tests/boulder-integration.sh`` and rerun the integration tests suite. -.. _Boulder: https://github.com/letsencrypt/boulder +.. _Boulder: https://github.com/certbot/boulder .. _Go: https://golang.org @@ -155,28 +155,28 @@ Code components and layout acme contains all protocol specific code -letsencrypt +certbot all client code Plugin-architecture ------------------- -Let's Encrypt has a plugin architecture to facilitate support for +Certbot has a plugin architecture to facilitate support for different webservers, other TLS servers, and operating systems. The interfaces available for plugins to implement are defined in `interfaces.py`_ and `plugins/common.py`_. The most common kind of plugin is a "Configurator", which is likely to -implement the `~letsencrypt.interfaces.IAuthenticator` and -`~letsencrypt.interfaces.IInstaller` interfaces (though some +implement the `~certbot.interfaces.IAuthenticator` and +`~certbot.interfaces.IInstaller` interfaces (though some Configurators may implement just one of those). -There are also `~letsencrypt.interfaces.IDisplay` plugins, +There are also `~certbot.interfaces.IDisplay` plugins, which implement bindings to alternative UI libraries. -.. _interfaces.py: https://github.com/letsencrypt/letsencrypt/blob/master/letsencrypt/interfaces.py -.. _plugins/common.py: https://github.com/letsencrypt/letsencrypt/blob/master/letsencrypt/plugins/common.py#L34 +.. _interfaces.py: https://github.com/certbot/certbot/blob/master/certbot/interfaces.py +.. _plugins/common.py: https://github.com/certbot/certbot/blob/master/certbot/plugins/common.py#L34 Authenticators @@ -232,7 +232,7 @@ Installer Development --------------------- There are a few existing classes that may be beneficial while -developing a new `~letsencrypt.interfaces.IInstaller`. +developing a new `~certbot.interfaces.IInstaller`. Installers aimed to reconfigure UNIX servers may use Augeas for configuration parsing and can inherit from `~.AugeasConfigurator` class to handle much of the interface. Installers that are unable to use @@ -244,7 +244,7 @@ Display ~~~~~~~ We currently offer a pythondialog and "text" mode for displays. Display -plugins implement the `~letsencrypt.interfaces.IDisplay` +plugins implement the `~certbot.interfaces.IDisplay` interface. .. _dev-plugin: @@ -252,10 +252,10 @@ interface. Writing your own plugin ======================= -Let's Encrypt client supports dynamic discovery of plugins through the +Certbot supports dynamic discovery of plugins through the `setuptools entry points`_. This way you can, for example, create a -custom implementation of `~letsencrypt.interfaces.IAuthenticator` or -the `~letsencrypt.interfaces.IInstaller` without having to merge it +custom implementation of `~certbot.interfaces.IAuthenticator` or +the `~certbot.interfaces.IInstaller` without having to merge it with the core upstream source code. An example is provided in ``examples/plugins/`` directory. @@ -323,7 +323,7 @@ Steps: See `Known Issues`_. If it's not a known issue, fix any errors. .. _Known Issues: - https://github.com/letsencrypt/letsencrypt/wiki/Known-issues + https://github.com/certbot/certbot/wiki/Known-issues Updating the documentation ========================== @@ -345,7 +345,7 @@ Other methods for running the client Vagrant ------- -If you are a Vagrant user, Let's Encrypt comes with a Vagrantfile that +If you are a Vagrant user, Certbot comes with a Vagrantfile that automates setting up a development environment in an Ubuntu 14.04 LTS VM. To set it up, simply run ``vagrant up``. The repository is synced to ``/vagrant``, so you can get started with: @@ -354,7 +354,7 @@ synced to ``/vagrant``, so you can get started with: vagrant ssh cd /vagrant - sudo ./venv/bin/letsencrypt + sudo ./venv/bin/certbot Support for other Linux distributions coming soon. @@ -373,19 +373,19 @@ Docker ------ OSX users will probably find it easiest to set up a Docker container for -development. Let's Encrypt comes with a Dockerfile (``Dockerfile-dev``) +development. Certbot comes with a Dockerfile (``Dockerfile-dev``) for doing so. To use Docker on OSX, install and setup docker-machine using the instructions at https://docs.docker.com/installation/mac/. To build the development Docker image:: - docker build -t letsencrypt -f Dockerfile-dev . + docker build -t certbot -f Dockerfile-dev . Now run tests inside the Docker image: .. code-block:: shell - docker run -it letsencrypt bash + docker run -it certbot bash cd src tox -e py27 @@ -399,7 +399,7 @@ OS-level dependencies can be installed like so: .. code-block:: shell - letsencrypt-auto-source/letsencrypt-auto --os-packages-only + certbot-auto-source/certbot-auto --os-packages-only In general... diff --git a/docs/index.rst b/docs/index.rst index 68289d760..b541e376e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,4 +1,4 @@ -Welcome to the Let's Encrypt client documentation! +Welcome to the Certbot documentation! ================================================== .. toctree:: diff --git a/docs/man/certbot.rst b/docs/man/certbot.rst new file mode 100644 index 000000000..7382d7811 --- /dev/null +++ b/docs/man/certbot.rst @@ -0,0 +1 @@ +.. program-output:: certbot --help all diff --git a/docs/man/letsencrypt.rst b/docs/man/letsencrypt.rst deleted file mode 100644 index 30f33c890..000000000 --- a/docs/man/letsencrypt.rst +++ /dev/null @@ -1 +0,0 @@ -.. program-output:: letsencrypt --help all diff --git a/docs/packaging.rst b/docs/packaging.rst index 5f09b65fa..bd366dbaa 100644 --- a/docs/packaging.rst +++ b/docs/packaging.rst @@ -3,4 +3,4 @@ Packaging Guide =============== Documentation can be found at -https://github.com/letsencrypt/letsencrypt/wiki/Packaging. +https://github.com/certbot/certbot/wiki/Packaging. diff --git a/docs/using.rst b/docs/using.rst index 66c5907ae..2b16e9a27 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -10,12 +10,12 @@ User Guide Installation ============ -.. _letsencrypt-auto: +.. _certbot-auto: -letsencrypt-auto +certbot-auto ---------------- -``letsencrypt-auto`` is a wrapper which installs some dependencies +``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 @@ -25,33 +25,33 @@ To install and run the client, just type... .. code-block:: shell - ./letsencrypt-auto + ./certbot-auto -.. hint:: During the beta phase, Let's Encrypt enforces strict rate limits on +.. hint:: During the beta phase, Certbot 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 -``letsencrypt-auto``. For example, to get basic help you would type: +``certbot`` script/binary, you can substitute in +``certbot-auto``. For example, to get basic help you would type: .. code-block:: shell - ./letsencrypt-auto --help + ./certbot-auto --help or for full help, type: .. code-block:: shell - ./letsencrypt-auto --help all + ./certbot-auto --help all -``letsencrypt-auto`` is the recommended method of running the Let's Encrypt +``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 ``letsencrypt`` (and perhaps -``letsencrypt-apache``). If you'd like to run the latest copy from Git, or +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. @@ -60,11 +60,11 @@ below. Plugins ======= -The Let's Encrypt client supports a number of different "plugins" that can be +The Certbot client supports a number of different "plugins" that can be used to obtain and/or install certificates. Plugins that can obtain a cert are called "authenticators" and can be used with the "certonly" command. Plugins that can install a cert are called "installers". Plugins that do both -can be used with the "letsencrypt run" command, which is the default. +can be used with the "certbot run" command, which is the default. =========== ==== ==== =============================================================== Plugin Auth Inst Notes @@ -79,7 +79,7 @@ standalone_ Y N Uses a "standalone" webserver to obtain a cert. Requires webserver is not supported or not desired. manual_ Y N Helps you obtain a cert by giving you instructions to perform domain validation yourself. -nginx_ Y Y Very experimental and not included in letsencrypt-auto_. +nginx_ Y Y Very experimental and not included in certbot-auto_. =========== ==== ==== =============================================================== There are also a number of third-party plugins for the client, provided by other developers: @@ -93,10 +93,10 @@ s3front_ Y Y Integration with Amazon CloudFront distribution of S3 buck gandi_ Y Y Integration with Gandi's hosting products and API =========== ==== ==== =============================================================== -.. _plesk: https://github.com/plesk/letsencrypt-plesk -.. _haproxy: https://code.greenhost.net/open/letsencrypt-haproxy -.. _s3front: https://github.com/dlapiduz/letsencrypt-s3front -.. _gandi: https://github.com/Gandi/letsencrypt-gandi +.. _plesk: https://github.com/plesk/certbot-plesk +.. _haproxy: https://code.greenhost.net/open/certbot-haproxy +.. _s3front: https://github.com/dlapiduz/certbot-s3front +.. _gandi: https://github.com/Gandi/certbot-gandi Future plugins for IMAP servers, SMTP servers, IRC servers, etc, are likely to be installers but not authenticators. @@ -130,21 +130,21 @@ specified ``--webroot-path``. So, for instance, :: - letsencrypt certonly --webroot -w /var/www/example/ -d www.example.com -d example.com -w /var/www/other -d other.example.net -d another.other.example.net + certbot certonly --webroot -w /var/www/example/ -d www.example.com -d example.com -w /var/www/other -d other.example.net -d another.other.example.net would obtain a single certificate for all of those names, using the ``/var/www/example`` webroot directory for the first two, and ``/var/www/other`` for the second two. The webroot plugin works by creating a temporary file for each of your requested -domains in ``${webroot-path}/.well-known/acme-challenge``. Then the Let's -Encrypt validation server makes HTTP requests to validate that the DNS for each -requested domain resolves to the server running letsencrypt. An example request +domains in ``${webroot-path}/.well-known/acme-challenge``. Then the Certbot +validation server makes HTTP requests to validate that the DNS for each +requested domain resolves to the server running certbot. An example request made to your web server would look like: :: - 66.133.109.36 - - [05/Jan/2016:20:11:24 -0500] "GET /.well-known/acme-challenge/HGr8U1IeTW4kY_Z6UIyaakzOkyQgPr_7ArlLgtZE8SX HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)" + 66.133.109.36 - - [05/Jan/2016:20:11:24 -0500] "GET /.well-known/acme-challenge/HGr8U1IeTW4kY_Z6UIyaakzOkyQgPr_7ArlLgtZE8SX HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Certbot validation server; +https://www.certbot.com)" Note that to use the webroot plugin, your server must be configured to serve files from hidden directories. If ``/.well-known`` is treated specially by @@ -173,7 +173,7 @@ specified port using each requested domain name. Manual ------ -If you'd like to obtain a cert running ``letsencrypt`` on a machine +If you'd like to obtain a cert running ``certbot`` on a machine other than your target webserver or perform the steps for domain validation yourself, you can use the manual plugin. While hidden from the UI, you can use the plugin to obtain a cert by specifying @@ -187,14 +187,14 @@ Nginx In the future, if you're running Nginx you can use this plugin to automatically obtain and install your certificate. The Nginx plugin is still experimental, however, and is not installed with -letsencrypt-auto_. If installed, you can select this plugin on the +certbot-auto_. If installed, you can select this plugin on the command line by including ``--nginx``. Third-party plugins ------------------- These plugins are listed at -https://github.com/letsencrypt/letsencrypt/wiki/Plugins. If you're +https://github.com/certbot/certbot/wiki/Plugins. If you're interested, you can also :ref:`write your own plugin `. Renewal @@ -204,11 +204,11 @@ Renewal days). Make sure you renew the certificates at least once in 3 months. -The ``letsencrypt`` client now supports a ``renew`` action to check +The ``certbot`` client now supports a ``renew`` action to check all installed certificates for impending expiry and attempt to renew them. The simplest form is simply -``letsencrypt renew`` +``certbot renew`` This will attempt to renew any previously-obtained certificates that expire in less than 30 days. The same plugin and options that were used @@ -229,9 +229,9 @@ certificate regardless of its age. (This form is not appropriate to run daily because each certificate will be renewed every day, which will quickly run into the certificate authority rate limit.) -Note that options provided to ``letsencrypt renew`` will apply to +Note that options provided to ``certbot renew`` will apply to *every* certificate for which renewal is attempted; for example, -``letsencrypt renew --rsa-key-size 4096`` would try to replace every +``certbot renew --rsa-key-size 4096`` would try to replace every near-expiry certificate with an equivalent certificate using a 4096-bit RSA public key. If a certificate is successfully renewed using specified options, those options will be saved and used for future @@ -240,10 +240,10 @@ renewals of that certificate. An alternative form that provides for more fine-grained control over the renewal process (while renewing specified certificates one at a time), -is ``letsencrypt certonly`` with the complete set of subject domains of +is ``certbot certonly`` with the complete set of subject domains of a specific certificate specified via `-d` flags, like -``letsencrypt certonly -d example.com -d www.example.com`` +``certbot certonly -d example.com -d www.example.com`` (All of the domains covered by the certificate must be specified in this case in order to renew and replace the old certificate rather @@ -256,7 +256,7 @@ The ``certonly`` form attempts to renew one individual certificate. Please note that the CA will send notification emails to the address you provide if you do not renew certificates that are about to expire. -Let's Encrypt is working hard on improving the renewal process, and we +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. @@ -272,14 +272,14 @@ 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 +``/etc/certbot/live/$domain``. Rather than copying, please point your (web) server configuration directly to those files (or create -symlinks). During the renewal_, ``/etc/letsencrypt/live`` is updated +symlinks). During the renewal_, ``/etc/certbot/live`` is updated with the latest necessary files. -.. note:: ``/etc/letsencrypt/archive`` and ``/etc/letsencrypt/keys`` +.. note:: ``/etc/certbot/archive`` and ``/etc/certbot/keys`` contain all previous keys and certificates, while - ``/etc/letsencrypt/live`` symlinks to the latest versions. + ``/etc/certbot/live`` symlinks to the latest versions. The following files are available: @@ -287,7 +287,7 @@ The following files are available: Private key for the certificate. .. warning:: This **must be kept secret at all times**! Never share - it with anyone, including Let's Encrypt developers. You cannot + it with anyone, including Certbot developers. You cannot put it into a safe, however - your server still needs to access this file in order for SSL/TLS to work. @@ -340,7 +340,7 @@ Configuration file ================== It is possible to specify configuration file with -``letsencrypt-auto --config cli.ini`` (or shorter ``-c cli.ini``). An +``certbot-auto --config cli.ini`` (or shorter ``-c cli.ini``). An example configuration file is shown below: .. include:: ../examples/cli.ini @@ -348,9 +348,9 @@ example configuration file is shown below: By default, the following locations are searched: -- ``/etc/letsencrypt/cli.ini`` -- ``$XDG_CONFIG_HOME/letsencrypt/cli.ini`` (or - ``~/.config/letsencrypt/cli.ini`` if ``$XDG_CONFIG_HOME`` is not +- ``/etc/certbot/cli.ini`` +- ``$XDG_CONFIG_HOME/certbot/cli.ini`` (or + ``~/.config/certbot/cli.ini`` if ``$XDG_CONFIG_HOME`` is not set). .. keep it up to date with constants.py @@ -359,21 +359,21 @@ By default, the following locations are searched: Getting help ============ -If you're having problems you can chat with us on `IRC (#letsencrypt @ -Freenode) `_ or -get support on our `forums `_. +If you're having problems you can chat with us on `IRC (#certbot @ +OFTC) `_ or +get support on our `forums `_. If you find a bug in the software, please do report it in our `issue tracker -`_. Remember to +`_. Remember to give us as much information as possible: - copy and paste exact command line used and the output (though mind that the latter might include some personally identifiable information, including your email and domains) -- copy and paste logs from ``/var/log/letsencrypt`` (though mind they +- copy and paste logs from ``/var/log/certbot`` (though mind they also might contain personally identifiable information) -- copy and paste ``letsencrypt --version`` output +- copy and paste ``certbot --version`` output - your operating system, including specific version - specify which installation_ method you've chosen @@ -390,10 +390,10 @@ plugins cannot reach it from inside the Docker container. You should definitely read the :ref:`where-certs` section, in order to know how to manage the certs -manually. https://github.com/letsencrypt/letsencrypt/wiki/Ciphersuite-guidance +manually. https://github.com/certbot/certbot/wiki/Ciphersuite-guidance provides some information about recommended ciphersuites. If none of these make much sense to you, you should definitely use the -letsencrypt-auto_ method, which enables you to use installer plugins +certbot-auto_ method, which enables you to use installer plugins that cover both of those hard topics. If you're still not convinced and have decided to use this method, @@ -402,14 +402,14 @@ to, `install Docker`_, then issue the following command: .. code-block:: shell - sudo docker run -it --rm -p 443:443 -p 80:80 --name letsencrypt \ - -v "/etc/letsencrypt:/etc/letsencrypt" \ - -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ - quay.io/letsencrypt/letsencrypt:latest auth + sudo docker run -it --rm -p 443:443 -p 80:80 --name certbot \ + -v "/etc/certbot:/etc/certbot" \ + -v "/var/lib/certbot:/var/lib/certbot" \ + quay.io/certbot/certbot:latest auth and follow the instructions (note that ``auth`` command is explicitly used - no installer plugins involved). Your new cert will be available -in ``/etc/letsencrypt/live`` on the host. +in ``/etc/certbot/live`` on the host. .. _Docker: https://docker.com .. _`install Docker`: https://docs.docker.com/userguide/ @@ -420,31 +420,31 @@ Operating System Packages **FreeBSD** - * Port: ``cd /usr/ports/security/py-letsencrypt && make install clean`` - * Package: ``pkg install py27-letsencrypt`` + * Port: ``cd /usr/ports/security/py-certbot make install clean`` + * Package: ``pkg install py27-certbot`` **OpenBSD** - * Port: ``cd /usr/ports/security/letsencrypt/client && make install clean`` - * Package: ``pkg_add letsencrypt`` + * Port: ``cd /usr/ports/security/certbot/client && make install clean`` + * Package: ``pkg_add certbot`` **Arch Linux** .. code-block:: shell - sudo pacman -S letsencrypt letsencrypt-apache + sudo pacman -S certbot certbot-apache **Debian** -If you run Debian Stretch or Debian Sid, you can install letsencrypt packages. +If you run Debian Stretch or Debian Sid, you can install certbot packages. .. code-block:: shell sudo apt-get update - sudo apt-get install letsencrypt python-letsencrypt-apache + sudo apt-get install certbot python-certbot-apache If you don't want to use the Apache plugin, you can omit the -``python-letsencrypt-apache`` package. +``python-certbot-apache`` package. Packages for Debian Jessie are coming in the next few weeks. @@ -452,17 +452,17 @@ Packages for Debian Jessie are coming in the next few weeks. .. code-block:: shell - sudo dnf install letsencrypt + sudo dnf install certbot **Gentoo** -The official Let's Encrypt client is available in Gentoo Portage. If you +The official Certbot client is available in Gentoo Portage. If you want to use the Apache plugin, it has to be installed separately: .. code-block:: shell - emerge -av app-crypt/letsencrypt - emerge -av app-crypt/letsencrypt-apache + emerge -av app-crypt/certbot + emerge -av app-crypt/certbot-apache Currently, only the Apache plugin is included in Portage. However, if you want the nginx plugin, you can use Layman to add the mrueg overlay which @@ -473,7 +473,7 @@ does include the nginx plugin package: emerge -av app-portage/layman layman -S layman -a mrueg - emerge -av app-crypt/letsencrypt-nginx + emerge -av app-crypt/certbot-nginx When using the Apache plugin, you will run into a "cannot find a cert or key directive" error if you're sporting the default Gentoo ``httpd.conf``. @@ -503,7 +503,7 @@ Note: this change is not required for the other plugins. **Other Operating Systems** OS packaging is an ongoing effort. If you'd like to package -Let's Encrypt client for your distribution of choice please have a +Certbot for your distribution of choice please have a look at the :doc:`packaging`. @@ -519,19 +519,19 @@ whole process is described in the :doc:`contributing`. environment, e.g. ``sudo python setup.py install``, ``sudo pip install``, ``sudo ./venv/bin/...``. These modes of operation might corrupt your operating system and are **not supported** by the - Let's Encrypt team! + Certbot team! Comparison of different methods ------------------------------- Unless you have a very specific requirements, we kindly ask you to use -the letsencrypt-auto_ method. It's the fastest, the most thoroughly +the certbot-auto_ method. It's the fastest, the most thoroughly tested and the most reliable way of getting our software and the free SSL certificates! Beyond the methods discussed here, other methods may be possible, such as -installing Let's Encrypt directly with pip from PyPI or downloading a ZIP +installing Certbot directly with pip from PyPI or downloading a ZIP archive from GitHub may be technically possible but are not presently recommended or supported. From b8ea2c19a38d870556496b980de2472b4e369d32 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 6 Apr 2016 16:57:52 -0700 Subject: [PATCH 006/186] Lintian bug fix --- letsencrypt/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index f2ad50d45..adcc32a5e 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -272,7 +272,7 @@ class HelpfulArgumentParser(object): # Do any post-parsing homework here if self.verb == "renew": - self.noninteractive_mode = True + parsed_args.noninteractive_mode = True # we get domains from -d, but also from the webroot map... if parsed_args.webroot_map: From 0bcc80756d16de6aed3365b0fa3d27c2e2e98855 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 6 Apr 2016 17:10:30 -0700 Subject: [PATCH 007/186] Refactor config.server complexity out of parse_args --- letsencrypt/cli.py | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 8c2cd839a..75c7e116f 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -318,24 +318,7 @@ class HelpfulArgumentParser(object): parsed_args.noninteractive_mode = True if parsed_args.staging or parsed_args.dry_run: - if parsed_args.server not in (flag_default("server"), constants.STAGING_URI): - conflicts = ["--staging"] if parsed_args.staging else [] - conflicts += ["--dry-run"] if parsed_args.dry_run else [] - raise errors.Error("--server value conflicts with {0}".format( - " and ".join(conflicts))) - - parsed_args.server = constants.STAGING_URI - - if parsed_args.dry_run: - if self.verb not in ["certonly", "renew"]: - raise errors.Error("--dry-run currently only works with the " - "'certonly' or 'renew' subcommands (%r)" % self.verb) - parsed_args.break_my_certs = parsed_args.staging = True - if glob.glob(os.path.join(parsed_args.config_dir, constants.ACCOUNTS_DIR, "*")): - # The user has a prod account, but might not have a staging - # one; we don't want to start trying to perform interactive registration - parsed_args.tos = True - parsed_args.register_unsafely_without_email = True + self.set_test_server(parsed_args) if parsed_args.csr: if parsed_args.allow_subset_of_names: @@ -347,6 +330,30 @@ class HelpfulArgumentParser(object): return parsed_args + + def set_test_server(self, parsed_args): + "We have --staging/--dry-run; perform sanity check and set config.server" + + if parsed_args.server not in (flag_default("server"), constants.STAGING_URI): + conflicts = ["--staging"] if parsed_args.staging else [] + conflicts += ["--dry-run"] if parsed_args.dry_run else [] + raise errors.Error("--server value conflicts with {0}".format( + " and ".join(conflicts))) + + parsed_args.server = constants.STAGING_URI + + if parsed_args.dry_run: + if self.verb not in ["certonly", "renew"]: + raise errors.Error("--dry-run currently only works with the " + "'certonly' or 'renew' subcommands (%r)" % self.verb) + parsed_args.break_my_certs = parsed_args.staging = True + if glob.glob(os.path.join(parsed_args.config_dir, constants.ACCOUNTS_DIR, "*")): + # The user has a prod account, but might not have a staging + # one; we don't want to start trying to perform interactive registration + parsed_args.tos = True + parsed_args.register_unsafely_without_email = True + + def handle_csr(self, parsed_args): """Process a --csr flag.""" if parsed_args.verb != "certonly": From 5e3fc3a957eaaff225e21916b1241cd5a37ec522 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 6 Apr 2016 17:14:29 -0700 Subject: [PATCH 008/186] Keep all --csr checks in HelpfulArgumentParser.handle_csr --- letsencrypt/cli.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 75c7e116f..74c51f5e3 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -321,9 +321,6 @@ class HelpfulArgumentParser(object): self.set_test_server(parsed_args) if parsed_args.csr: - if parsed_args.allow_subset_of_names: - raise errors.Error("--allow-subset-of-names " - "cannot be used with --csr") self.handle_csr(parsed_args) hooks.validate_hooks(parsed_args) @@ -361,6 +358,8 @@ class HelpfulArgumentParser(object): "when obtaining a new or replacement " "via the certonly command. Please try the " "certonly command instead.") + if parsed_args.allow_subset_of_names: + raise errors.Error("--allow-subset-of-names cannot be used with --csr") try: csr = le_util.CSR(file=parsed_args.csr[0], data=parsed_args.csr[1], form="der") From 526bc5cf84aeaca0669d87ada3ced32615efe8e9 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 6 Apr 2016 17:35:29 -0700 Subject: [PATCH 009/186] Refactor CSR importing from cli -> crypto_util More specifically: HelpfulArgumentParser.handle_csr -> crypto_util.import_csr_file --- letsencrypt/cli.py | 18 ++---------------- letsencrypt/crypto_util.py | 30 ++++++++++++++++++++++++++++++ letsencrypt/tests/client_test.py | 6 ++++-- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 74c51f5e3..61fc57777 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -6,10 +6,8 @@ import logging import logging.handlers import os import sys -import traceback import configargparse -import OpenSSL import six import letsencrypt @@ -361,20 +359,8 @@ class HelpfulArgumentParser(object): if parsed_args.allow_subset_of_names: raise errors.Error("--allow-subset-of-names cannot be used with --csr") - try: - csr = le_util.CSR(file=parsed_args.csr[0], data=parsed_args.csr[1], form="der") - typ = OpenSSL.crypto.FILETYPE_ASN1 - domains = crypto_util.get_sans_from_csr(csr.data, OpenSSL.crypto.FILETYPE_ASN1) - except OpenSSL.crypto.Error: - try: - e1 = traceback.format_exc() - typ = OpenSSL.crypto.FILETYPE_PEM - csr = le_util.CSR(file=parsed_args.csr[0], data=parsed_args.csr[1], form="pem") - domains = crypto_util.get_sans_from_csr(csr.data, typ) - except OpenSSL.crypto.Error: - logger.debug("DER CSR parse error %s", e1) - logger.debug("PEM CSR parse error %s", traceback.format_exc()) - raise errors.Error("Failed to parse CSR file: {0}".format(parsed_args.csr[0])) + csrfile, contents = parsed_args.csr[0:2] + typ, csr, domains = crypto_util.import_csr_file(csrfile, contents) # This is not necessary for webroot to work, however, # obtain_certificate_from_csr requires parsed_args.domains to be set diff --git a/letsencrypt/crypto_util.py b/letsencrypt/crypto_util.py index 5fdcba843..2ca43f76f 100644 --- a/letsencrypt/crypto_util.py +++ b/letsencrypt/crypto_util.py @@ -6,6 +6,7 @@ """ import logging import os +import traceback import OpenSSL import pyrfc3339 @@ -171,6 +172,35 @@ def csr_matches_pubkey(csr, privkey): return False +def import_csr_file(csrfile, contents): + """Import a CSR file, which can be either PEM or DER. + + :param str csrfile: CSR filename + :param str contents: contens of the CSR file + + :rtype: tuple + + :returns: (le_util.CSR object representing the CSR, + OpenSSL FILETYPE_ representing DER or PEM, + list of domains requested in the CSR) + """ + try: + csr = le_util.CSR(file=csrfile, data=contents, form="der") + typ = OpenSSL.crypto.FILETYPE_ASN1 + domains = get_sans_from_csr(csr.data, OpenSSL.crypto.FILETYPE_ASN1) + except OpenSSL.crypto.Error: + try: + e1 = traceback.format_exc() + typ = OpenSSL.crypto.FILETYPE_PEM + csr = le_util.CSR(file=csrfile, data=contents, form="pem") + domains = get_sans_from_csr(csr.data, typ) + except OpenSSL.crypto.Error: + logger.debug("DER CSR parse error %s", e1) + logger.debug("PEM CSR parse error %s", traceback.format_exc()) + raise errors.Error("Failed to parse CSR file: {0}".format(csrfile)) + return typ, csr, domains + + def make_key(bits): """Generate PEM encoded RSA key. diff --git a/letsencrypt/tests/client_test.py b/letsencrypt/tests/client_test.py index cd6b11158..c3d5b322f 100644 --- a/letsencrypt/tests/client_test.py +++ b/letsencrypt/tests/client_test.py @@ -134,7 +134,7 @@ class ClientTest(unittest.TestCase): self.acme.fetch_chain.assert_called_once_with(mock.sentinel.certr) - # FIXME move parts of this to test_cli.py... + # FIXME move parts of this to crypto_util tests... @mock.patch("letsencrypt.client.logger") def test_obtain_certificate_from_csr(self, mock_logger): self._mock_obtain_certificate() @@ -144,9 +144,11 @@ class ClientTest(unittest.TestCase): # The CLI should believe that this is a certonly request, because # a CSR would not be allowed with other kinds of requests! mock_parsed_args.verb = "certonly" - with mock.patch("letsencrypt.client.le_util.CSR") as mock_CSR: + with mock.patch("letsencrypt.cli.crypto_util.le_util.CSR") as mock_CSR: mock_CSR.return_value = test_csr mock_parsed_args.domains = self.eg_domains[:] + mock_parsed_args.allow_subset_of_names = False + mock_parsed_args.csr = (mock.MagicMock(), mock.MagicMock()) mock_parser = mock.MagicMock(cli.HelpfulArgumentParser) cli.HelpfulArgumentParser.handle_csr(mock_parser, mock_parsed_args) From c4974e6d937eec5dd85b8fd99c6f477594cc6379 Mon Sep 17 00:00:00 2001 From: Pavel Pavlov Date: Thu, 7 Apr 2016 18:11:55 +0300 Subject: [PATCH 010/186] Nginx map statement hotfix --- letsencrypt-nginx/letsencrypt_nginx/nginxparser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py index cef0756d7..69594efc3 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py +++ b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py @@ -30,10 +30,11 @@ class RawNginxParser(object): assignment = (key + Optional(space + value, default=None) + semicolon) location_statement = Optional(space + modifier) + Optional(space + location) if_statement = Literal("if") + space + Regex(r"\(.+\)") + space + map_statement = Literal("map") + space + Regex(r"\S+") + space + Regex(r"\$\S+") + space block = Forward() block << Group( - (Group(key + location_statement) ^ Group(if_statement)) + + (Group(key + location_statement) ^ Group(if_statement) ^ Group(map_statement)) + left_bracket + Group(ZeroOrMore(Group(comment | assignment) | block)) + right_bracket) From 8145b7c11b9f824831ef2f059eaafdb664307d90 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sat, 9 Apr 2016 08:15:24 +0000 Subject: [PATCH 011/186] ACME: omitempty Error.detail, Error.type (fixes #2289) --- acme/acme/messages.py | 4 ++-- acme/acme/messages_test.py | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/acme/acme/messages.py b/acme/acme/messages.py index 24a3b580c..40ddbdb2f 100644 --- a/acme/acme/messages.py +++ b/acme/acme/messages.py @@ -37,9 +37,9 @@ class Error(jose.JSONObjectWithFields, errors.Error): ) ) - typ = jose.Field('type') + typ = jose.Field('type', omitempty=True, default='about:blank') title = jose.Field('title', omitempty=True) - detail = jose.Field('detail') + detail = jose.Field('detail', omitempty=True) @property def description(self): diff --git a/acme/acme/messages_test.py b/acme/acme/messages_test.py index b2b7febdc..c1f027302 100644 --- a/acme/acme/messages_test.py +++ b/acme/acme/messages_test.py @@ -28,6 +28,14 @@ class ErrorTest(unittest.TestCase): self.error_custom = Error(typ='custom', detail='bar') self.jobj_cusom = {'type': 'custom', 'detail': 'bar'} + def test_default_typ(self): + from acme.messages import Error + self.assertEqual(Error().typ, 'about:blank') + + def test_from_json_empty(self): + from acme.messages import Error + self.assertEqual(Error(), Error.from_json('{}')) + def test_from_json_hashable(self): from acme.messages import Error hash(Error.from_json(self.error.to_json())) From 0839168de7da3950e93056c2f80d029e7225e43f Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 10 Apr 2016 07:50:39 +0000 Subject: [PATCH 012/186] Fake deserialization error in test_check_response_not_ok_jobj_no_error --- acme/acme/client_test.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/acme/acme/client_test.py b/acme/acme/client_test.py index c8e95a423..7403cde81 100644 --- a/acme/acme/client_test.py +++ b/acme/acme/client_test.py @@ -484,9 +484,11 @@ class ClientNetworkTest(unittest.TestCase): def test_check_response_not_ok_jobj_no_error(self): self.response.ok = False self.response.json.return_value = {} - # pylint: disable=protected-access - self.assertRaises( - errors.ClientError, self.net._check_response, self.response) + with mock.patch('acme.client.messages.Error.from_json') as from_json: + from_json.side_effect = jose.DeserializationError + # pylint: disable=protected-access + self.assertRaises( + errors.ClientError, self.net._check_response, self.response) def test_check_response_not_ok_jobj_error(self): self.response.ok = False From 9111faeb942129cf2831be3ae695b5e7b5bc5b06 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 11 Apr 2016 09:44:29 -0700 Subject: [PATCH 013/186] don't lose domain ordering --- letsencrypt/client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/letsencrypt/client.py b/letsencrypt/client.py index 221879080..508117489 100644 --- a/letsencrypt/client.py +++ b/letsencrypt/client.py @@ -245,8 +245,9 @@ class Client(object): domains, self.config.allow_subset_of_names) - domains = [a.body.identifier.value.encode('ascii') - for a in authzr] + auth_domains = set(a.body.identifier.value.encode('ascii') + for a in authzr) + domains = [d for d in domains if d in auth_domains] # Create CSR from names key = crypto_util.init_save_key( From 9008adc1760e889093b618e133caaba0279a18d5 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 12 Apr 2016 12:23:24 -0700 Subject: [PATCH 014/186] add test to prevent regressions --- letsencrypt/tests/client_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/letsencrypt/tests/client_test.py b/letsencrypt/tests/client_test.py index cd6b11158..49fa5b17e 100644 --- a/letsencrypt/tests/client_test.py +++ b/letsencrypt/tests/client_test.py @@ -201,7 +201,8 @@ class ClientTest(unittest.TestCase): authzr = [] - for domain in domains: + # domain ordering should not be affected by authorization order + for domain in reversed(domains): authzr.append( mock.MagicMock( body=mock.MagicMock( From 82ee461e348051872c753416ab65f36f766af17d Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 8 Apr 2016 02:48:45 +0200 Subject: [PATCH 015/186] Adding renewal interval along with comment to the renewal configuration file --- certbot/storage.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/certbot/storage.py b/certbot/storage.py index 4ef614a8e..9462ad545 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -78,6 +78,9 @@ def write_renewal_config(o_filename, n_filename, target, relevant_data): if k not in relevant_data: del config["renewalparams"][k] + config["renew_before_expiry"] = constants.RENEWER_DEFAULTS["renew_before_expiry"] + config.comments["renew_before_expiry"] = "Renewal interval" + # TODO: add human-readable comments explaining other available # parameters logger.debug("Writing new config %s.", n_filename) From cafcffb86e259eaac29bb0dc88197b1b2e9df294 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Sat, 9 Apr 2016 02:20:31 +0200 Subject: [PATCH 016/186] Fixing errors --- certbot/storage.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/certbot/storage.py b/certbot/storage.py index 9462ad545..fdbdf7a0e 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -78,8 +78,10 @@ def write_renewal_config(o_filename, n_filename, target, relevant_data): if k not in relevant_data: del config["renewalparams"][k] - config["renew_before_expiry"] = constants.RENEWER_DEFAULTS["renew_before_expiry"] - config.comments["renew_before_expiry"] = "Renewal interval" + if "renew_before_expiry" not in config["renewalparams"]: + config["renewalparams"]["renew_before_expiry"] = ( + constants.RENEWER_DEFAULTS["renew_before_expiry"]) + config["renewalparams"].comments["renew_before_expiry"] = ["Renewal interval"] # TODO: add human-readable comments explaining other available # parameters From 2646ad4262630d7e05c2ee09b3c91c77d7c48870 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 18 Apr 2016 15:08:16 -0700 Subject: [PATCH 017/186] edit contributing.rst --- docs/contributing.rst | 432 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 docs/contributing.rst diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 000000000..3225de694 --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1,432 @@ +=============== +Developer Guide +=============== + +.. contents:: Table of Contents + :local: + + +.. _hacking: + +Hacking +======= + +Running a local copy of the client +---------------------------------- + +Running the client in developer mode from your local tree is a little +different than running ``letsencrypt-auto``. To get set up, do these things +once: + +.. code-block:: shell + + git clone https://github.com/letsencrypt/letsencrypt + cd letsencrypt + ./letsencrypt-auto-source/letsencrypt-auto --os-packages-only + ./tools/venv.sh + +Then in each shell where you're working on the client, do: + +.. code-block:: shell + + source ./venv/bin/activate + +After that, your shell will be using the virtual environment, and you run the +client by typing: + +.. code-block:: shell + + certbot + +Activating a shell in this way makes it easier to run unit tests +with ``tox`` and integration tests, as described below. To reverse this, you +can type ``deactivate``. More information can be found in the `virtualenv docs`_. + +.. _`virtualenv docs`: https://virtualenv.pypa.io + +Find issues to work on +---------------------- + +You can find the open issues in the `github issue tracker`_. Comparatively +easy ones are marked `Good Volunteer Task`_. If you're starting work on +something, post a comment to let others know and seek feedback on your plan +where appropriate. + +Once you've got a working branch, you can open a pull request. All changes in +your pull request must have thorough unit test coverage, pass our +`integration`_ tests, and be compliant with the :ref:`coding style +`. + +.. _github issue tracker: https://github.com/certbot/certbot/issues +.. _Good Volunteer Task: https://github.com/certbot/certbot/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+Volunteer+Task%22 + +Testing +------- + +The following tools are there to help you: + +- ``tox`` starts a full set of tests. Please note that it includes + apacheconftest, which uses the system's Apache install to test config file + parsing, so it should only be run on systems that have an + experimental, non-production Apache2 install on them. ``tox -e + apacheconftest`` can be used to run those specific Apache conf tests. + +- ``tox -e py27``, ``tox -e py26`` etc, run unit tests for specific Python + versions. + +- ``tox -e cover`` checks the test coverage only. Calling the + ``./tox.cover.sh`` script directly (or even ``./tox.cover.sh $pkg1 + $pkg2 ...`` for any subpackages) might be a bit quicker, though. + +- ``tox -e lint`` checks the style of the whole project, while + ``pylint --rcfile=.pylintrc path`` will check a single file or + specific directory only. + +- For debugging, we recommend ``pip install ipdb`` and putting + ``import ipdb; ipdb.set_trace()`` statement inside the source + code. Alternatively, you can use Python's standard library `pdb`, + but you won't get TAB completion... + + +.. _integration: + +Integration testing with the boulder CA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generally it is sufficient to open a pull request and let Github and Travis run +integration tests for you. + +However, if you prefer to run tests, you can use Vagrant, using the Vagrantfile +in Certbot's repository. To execute the tests on a Vagrant box, the only +command you are required to run is:: + + ./tests/boulder-integration.sh + +Otherwise, please follow the following instructions. + +Mac OS X users: Run ``./tests/mac-bootstrap.sh`` instead of +``boulder-start.sh`` to install dependencies, configure the +environment, and start boulder. + +Otherwise, install `Go`_ 1.5, ``libtool-ltdl``, ``mariadb-server`` and +``rabbitmq-server`` and then start Boulder_, an ACME CA server. + +If you can't get packages of Go 1.5 for your Linux system, +you can execute the following commands to install it: + +.. code-block:: shell + + wget https://storage.googleapis.com/golang/go1.5.3.linux-amd64.tar.gz -P /tmp/ + sudo tar -C /usr/local -xzf /tmp/go1.5.3.linux-amd64.tar.gz + if ! grep -Fxq "export GOROOT=/usr/local/go" ~/.profile ; then echo "export GOROOT=/usr/local/go" >> ~/.profile; fi + if ! grep -Fxq "export PATH=\\$GOROOT/bin:\\$PATH" ~/.profile ; then echo "export PATH=\\$GOROOT/bin:\\$PATH" >> ~/.profile; fi + +These commands download `Go`_ 1.5.3 to ``/tmp/``, extracts to ``/usr/local``, +and then adds the export lines required to execute ``boulder-start.sh`` to +``~/.profile`` if they were not previously added + +Make sure you execute the following command after `Go`_ finishes installing:: + + if ! grep -Fxq "export GOPATH=\\$HOME/go" ~/.profile ; then echo "export GOPATH=\\$HOME/go" >> ~/.profile; fi + +Afterwards, you'd be able to start Boulder_ using the following command:: + + ./tests/boulder-start.sh + +The script will download, compile and run the executable; please be +patient - it will take some time... Once its ready, you will see +``Server running, listening on 127.0.0.1:4000...``. Add ``/etc/hosts`` +entries pointing ``le.wtf``, ``le1.wtf``, ``le2.wtf``, ``le3.wtf`` +and ``nginx.wtf`` to 127.0.0.1. You may now run (in a separate terminal):: + + ./tests/boulder-integration.sh && echo OK || echo FAIL + +If you would like to test `certbot_nginx` plugin (highly +encouraged) make sure to install prerequisites as listed in +``certbot-nginx/tests/boulder-integration.sh`` and rerun +the integration tests suite. + +.. _Boulder: https://github.com/certbot/boulder +.. _Go: https://golang.org + + +Code components and layout +========================== + +acme + contains all protocol specific code +certbot + all client code + + +Plugin-architecture +------------------- + +Certbot has a plugin architecture to facilitate support for +different webservers, other TLS servers, and operating systems. +The interfaces available for plugins to implement are defined in +`interfaces.py`_ and `plugins/common.py`_. + +The most common kind of plugin is a "Configurator", which is likely to +implement the `~certbot.interfaces.IAuthenticator` and +`~certbot.interfaces.IInstaller` interfaces (though some +Configurators may implement just one of those). + +There are also `~certbot.interfaces.IDisplay` plugins, +which implement bindings to alternative UI libraries. + +.. _interfaces.py: https://github.com/certbot/certbot/blob/master/certbot/interfaces.py +.. _plugins/common.py: https://github.com/certbot/certbot/blob/master/certbot/plugins/common.py#L34 + + +Authenticators +-------------- + +Authenticators are plugins designed to prove that this client deserves a +certificate for some domain name by solving challenges received from +the ACME server. From the protocol, there are essentially two +different types of challenges. Challenges that must be solved by +individual plugins in order to satisfy domain validation (subclasses +of `~.DVChallenge`, i.e. `~.challenges.TLSSNI01`, +`~.challenges.HTTP01`, `~.challenges.DNS`) and continuity specific +challenges (subclasses of `~.ContinuityChallenge`, +i.e. `~.challenges.RecoveryToken`, `~.challenges.RecoveryContact`, +`~.challenges.ProofOfPossession`). Continuity challenges are +always handled by the `~.ContinuityAuthenticator`, while plugins are +expected to handle `~.DVChallenge` types. +Right now, we have two authenticator plugins, the `~.ApacheConfigurator` +and the `~.StandaloneAuthenticator`. The Standalone and Apache +authenticators only solve the `~.challenges.TLSSNI01` challenge currently. +(You can set which challenges your authenticator can handle through the +:meth:`~.IAuthenticator.get_chall_pref`. + +(FYI: We also have a partial implementation for a `~.DNSAuthenticator` +in a separate branch). + + +Installer +--------- + +Installers plugins exist to actually setup the certificate in a server, +possibly tweak the security configuration to make it more correct and secure +(Fix some mixed content problems, turn on HSTS, redirect to HTTPS, etc). +Installer plugins tell the main client about their abilities to do the latter +via the :meth:`~.IInstaller.supported_enhancements` call. We currently +have two Installers in the tree, the `~.ApacheConfigurator`. and the +`~.NginxConfigurator`. External projects have made some progress toward +support for IIS, Icecast and Plesk. + +Installers and Authenticators will oftentimes be the same class/object +(because for instance both tasks can be performed by a webserver like nginx) +though this is not always the case (the standalone plugin is an authenticator +that listens on port 443, but it cannot install certs; a postfix plugin would +be an installer but not an authenticator). + +Installers and Authenticators are kept separate because +it should be possible to use the `~.StandaloneAuthenticator` (it sets +up its own Python server to perform challenges) with a program that +cannot solve challenges itself (Such as MTA installers). + + +Installer Development +--------------------- + +There are a few existing classes that may be beneficial while +developing a new `~certbot.interfaces.IInstaller`. +Installers aimed to reconfigure UNIX servers may use Augeas for +configuration parsing and can inherit from `~.AugeasConfigurator` class +to handle much of the interface. Installers that are unable to use +Augeas may still find the `~.Reverter` class helpful in handling +configuration checkpoints and rollback. + + +Display +~~~~~~~ + +We currently offer a pythondialog and "text" mode for displays. Display +plugins implement the `~certbot.interfaces.IDisplay` +interface. + +.. _dev-plugin: + +Writing your own plugin +======================= + +Certbot client supports dynamic discovery of plugins through the +`setuptools entry points`_. This way you can, for example, create a +custom implementation of `~certbot.interfaces.IAuthenticator` or +the `~certbot.interfaces.IInstaller` without having to merge it +with the core upstream source code. An example is provided in +``examples/plugins/`` directory. + +.. warning:: Please be aware though that as this client is still in a + developer-preview stage, the API may undergo a few changes. If you + believe the plugin will be beneficial to the community, please + consider submitting a pull request to the repo and we will update + it with any necessary API changes. + +.. _`setuptools entry points`: + https://pythonhosted.org/setuptools/setuptools.html#dynamic-discovery-of-services-and-plugins + + +.. _coding-style: + +Coding style +============ + +Please: + +1. **Be consistent with the rest of the code**. + +2. Read `PEP 8 - Style Guide for Python Code`_. + +3. Follow the `Google Python Style Guide`_, with the exception that we + use `Sphinx-style`_ documentation:: + + def foo(arg): + """Short description. + + :param int arg: Some number. + + :returns: Argument + :rtype: int + + """ + return arg + +4. Remember to use ``pylint``. + +.. _Google Python Style Guide: + https://google-styleguide.googlecode.com/svn/trunk/pyguide.html +.. _Sphinx-style: http://sphinx-doc.org/ +.. _PEP 8 - Style Guide for Python Code: + https://www.python.org/dev/peps/pep-0008 + +Submitting a pull request +========================= + +Steps: + +1. Write your code! +2. Make sure your environment is set up properly and that you're in your + virtualenv. You can do this by running ``./tools/venv.sh``. + (this is a **very important** step) +3. Run ``./pep8.travis.sh`` to do a cursory check of your code style. + Fix any errors. +4. Run ``tox -e lint`` to check for pylint errors. Fix any errors. +5. Run ``tox`` to run the entire test suite including coverage. Fix any errors. +6. If your code touches communication with an ACME server/Boulder, you + should run the integration tests, see `integration`_. See `Known Issues`_ + for some common failures that have nothing to do with your code. +7. Submit the PR. +8. Did your tests pass on Travis? If they didn't, it might not be your fault! + See `Known Issues`_. If it's not a known issue, fix any errors. + +.. _Known Issues: + https://github.com/certbot/certbot/wiki/Known-issues + +Updating the documentation +========================== + +In order to generate the Sphinx documentation, run the following +commands: + +.. code-block:: shell + + make -C docs clean html + +This should generate documentation in the ``docs/_build/html`` +directory. + + +Other methods for running the client +==================================== + +Vagrant +------- + +If you are a Vagrant user, Certbot comes with a Vagrantfile that +automates setting up a development environment in an Ubuntu 14.04 +LTS VM. To set it up, simply run ``vagrant up``. The repository is +synced to ``/vagrant``, so you can get started with: + +.. code-block:: shell + + vagrant ssh + cd /vagrant + sudo ./venv/bin/certbot + +Support for other Linux distributions coming soon. + +.. note:: + Unfortunately, Python distutils and, by extension, setup.py and + tox, use hard linking quite extensively. Hard linking is not + supported by the default sync filesystem in Vagrant. As a result, + all actions with these commands are *significantly slower* in + Vagrant. One potential fix is to `use NFS`_ (`related issue`_). + +.. _use NFS: http://docs.vagrantup.com/v2/synced-folders/nfs.html +.. _related issue: https://github.com/ClusterHQ/flocker/issues/516 + + +Docker +------ + +OSX users will probably find it easiest to set up a Docker container for +development. Certbot comes with a Dockerfile (``Dockerfile-dev``) +for doing so. To use Docker on OSX, install and setup docker-machine using the +instructions at https://docs.docker.com/installation/mac/. + +To build the development Docker image:: + + docker build -t certbot -f Dockerfile-dev . + +Now run tests inside the Docker image: + +.. code-block:: shell + + docker run -it certbot bash + cd src + tox -e py27 + + +.. _prerequisites: + +Notes on OS dependencies +======================== + +OS-level dependencies can be installed like so: + +.. code-block:: shell + + letsencrypt-auto-source/letsencrypt-auto --os-packages-only + +In general... + +* ``sudo`` is required as a suggested way of running privileged process +* `Python`_ 2.6/2.7 is required +* `Augeas`_ is required for the Python bindings +* ``virtualenv`` and ``pip`` are used for managing other python library + dependencies + +.. _Python: https://wiki.python.org/moin/BeginnersGuide/Download +.. _Augeas: http://augeas.net/ +.. _Virtualenv: https://virtualenv.pypa.io + + +Debian +------ + +For squeeze you will need to: + +- Use ``virtualenv --no-site-packages -p python`` instead of ``-p python2``. + + +FreeBSD +------- + +Package installation for FreeBSD uses ``pkg``, not ports. + +FreeBSD by default uses ``tcsh``. In order to activate virtualenv (see +below), you will need a compatible shell, e.g. ``pkg install bash && +bash``. From 5b597e0e8b28b52774bd94fc55b9ff09a1994d55 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 20 Apr 2016 09:28:11 +1000 Subject: [PATCH 018/186] Rebuild letsencrypt-auto from current source --- letsencrypt-auto-source/letsencrypt-auto | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 111f2b272..1cd04e506 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -1,6 +1,6 @@ #!/bin/sh # -# Download and run the latest release version of the Let's Encrypt client. +# Download and run the latest release version of the Certbot client. # # NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING # @@ -46,7 +46,7 @@ for arg in "$@" ; do done # letsencrypt-auto needs root access to bootstrap OS dependencies, and -# letsencrypt itself needs root access for almost all modes of operation +# 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 # this script *can* be run as root (not recommended), or fall back to using # `su` @@ -186,7 +186,7 @@ BootstrapDebCommon() { AddBackportRepo precise-backports "deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse" else echo "No libaugeas0 version is available that's new enough to run the" - echo "Let's Encrypt apache plugin..." + echo "Certbot apache plugin..." fi # XXX add a case for ubuntu PPAs fi @@ -426,7 +426,7 @@ Bootstrap() { elif grep -iq "Amazon Linux" /etc/issue ; then ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon else - echo "Sorry, I don't know how to bootstrap Let's Encrypt on your operating system!" + echo "Sorry, I don't know how to bootstrap Certbot on your operating system!" echo echo "You will need to bootstrap, configure virtualenv, and run pip install manually." echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" @@ -466,7 +466,7 @@ if [ "$1" = "--le-auto-phase2" ]; then # ------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt" # This is the flattened list of packages letsencrypt-auto installs. To generate -# this, do `pip install --no-cache-dir -e acme -e . -e letsencrypt-apache`, and +# this, do `pip install --no-cache-dir -e acme -e . -e certbot-apache`, and # then use `hashin` or a more secure method to gather the hashes. argparse==1.4.0 \ @@ -823,7 +823,7 @@ UNLIKELY_EOF fi echo "Installation succeeded." fi - echo "Requesting root privileges to run letsencrypt..." + echo "Requesting root privileges to run certbot..." echo " " $SUDO "$VENV_BIN/letsencrypt" "$@" $SUDO "$VENV_BIN/letsencrypt" "$@" else @@ -831,8 +831,8 @@ else # # Each phase checks the version of only the thing it is responsible for # upgrading. Phase 1 checks the version of the latest release of - # letsencrypt-auto (which is always the same as that of the letsencrypt - # package). Phase 2 checks the version of the locally installed letsencrypt. + # letsencrypt-auto (which is always the same as that of the certbot + # package). Phase 2 checks the version of the locally installed certbot. if [ ! -f "$VENV_BIN/letsencrypt" ]; then # If it looks like we've never bootstrapped before, bootstrap: From b597f4a284ac17a20482808b266ece29b6fecb99 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 20 Apr 2016 09:28:41 +1000 Subject: [PATCH 019/186] [letsencrypt-auto] handle network/pypi failures more gracefully --- letsencrypt-auto-source/letsencrypt-auto | 5 +++-- letsencrypt-auto-source/letsencrypt-auto.template | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1cd04e506..81b1801cf 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -978,8 +978,9 @@ if __name__ == '__main__': UNLIKELY_EOF # --------------------------------------------------------------------------- DeterminePythonVersion - REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` - if [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then + if ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then + echo "WARNING: unable to check for updates." + elif [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then echo "Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." # Now we drop into Python so we don't have to install even more diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 2c8e1ec4c..168dea2af 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -248,8 +248,9 @@ else UNLIKELY_EOF # --------------------------------------------------------------------------- DeterminePythonVersion - REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` - if [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then + if ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then + echo "WARNING: unable to check for updates." + elif [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then echo "Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." # Now we drop into Python so we don't have to install even more From 3c455b7e64f44deb8a47f77f8c7e70b67db3aab9 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 20 Apr 2016 10:45:30 +1000 Subject: [PATCH 020/186] letsencrypt-auto: set CERTBOT_AUTO :) --- letsencrypt-auto-source/letsencrypt-auto | 7 +++++-- letsencrypt-auto-source/letsencrypt-auto.template | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 81b1801cf..1f2dfcf85 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -50,9 +50,12 @@ done # The "normal" case is that sudo is used for the steps that need root, but # this script *can* be run as root (not recommended), or fall back to using # `su` +SUDO_ENV="" +export CERTBOT_AUTO="$0" if test "`id -u`" -ne "0" ; then if command -v sudo 1>/dev/null 2>&1; then SUDO=sudo + SUDO_ENV="CERTBOT_AUTO=\"$0\"" else echo \"sudo\" is not available, will use \"su\" for installation steps... # Because the parameters in `su -c` has to be a string, @@ -824,8 +827,8 @@ UNLIKELY_EOF echo "Installation succeeded." fi echo "Requesting root privileges to run certbot..." - echo " " $SUDO "$VENV_BIN/letsencrypt" "$@" - $SUDO "$VENV_BIN/letsencrypt" "$@" + echo " " $SUDO $SUDO_ENV "$VENV_BIN/letsencrypt" "$@" + $SUDO $SUDO_ENV "$VENV_BIN/letsencrypt" "$@" else # Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke. # diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 168dea2af..580ee7c07 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -50,9 +50,12 @@ done # The "normal" case is that sudo is used for the steps that need root, but # this script *can* be run as root (not recommended), or fall back to using # `su` +SUDO_ENV="" +export CERTBOT_AUTO="$0" if test "`id -u`" -ne "0" ; then if command -v sudo 1>/dev/null 2>&1; then SUDO=sudo + SUDO_ENV="CERTBOT_AUTO=\"$0\"" else echo \"sudo\" is not available, will use \"su\" for installation steps... # Because the parameters in `su -c` has to be a string, @@ -220,8 +223,8 @@ UNLIKELY_EOF echo "Installation succeeded." fi echo "Requesting root privileges to run certbot..." - echo " " $SUDO "$VENV_BIN/letsencrypt" "$@" - $SUDO "$VENV_BIN/letsencrypt" "$@" + echo " " $SUDO $SUDO_ENV "$VENV_BIN/letsencrypt" "$@" + $SUDO $SUDO_ENV "$VENV_BIN/letsencrypt" "$@" else # Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke. # From a73986576318d9fdbe95621b37caa72bbb470797 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 20 Apr 2016 10:49:02 +1000 Subject: [PATCH 021/186] Print a deprecation warning with the ancient letsencrypt-auto --- certbot/cli.py | 19 ++++++++++++++++++- certbot/main.py | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/certbot/cli.py b/certbot/cli.py index e2c57595b..3e6f78bc1 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -37,8 +37,9 @@ helpful_parser = None # should only be used for purposes where inability to detect letsencrypt-auto # fails safely +LEAUTO = "letsencrypt-auto" fragment = os.path.join(".local", "share", "certbot") -cli_command = "letsencrypt-auto" if fragment in sys.argv[0] else "certbot" +cli_command = LEAUTO if fragment in sys.argv[0] else "certbot" # Argparse's help formatting has a lot of unhelpful peculiarities, so we want # to replace as much of it as we can... @@ -141,6 +142,22 @@ def usage_strings(plugins): return USAGE % (apache_doc, nginx_doc), SHORT_USAGE +def possible_deprecation_warning(config): + "A deprecation warning for users with the old, not-self-upgrading letsencrypt-auto." + if cli_command != LEAUTO: + return + if config.no_self_upgrade: + # users setting --no-self-upgrade might be hanging on a clent version like 0.3.0 + # or 0.5.0 which is the new script, but doesn't set CERTBOT_AUTO; they don't + # need warnings + return + if "CERTBOT_AUTO" not in os.environ: + logger.warn("You are running with an old copy of letsencrypt-auto that does " + "not receive updates, and is less reliable than more recent versions. " + "We recommend upgrading to the latest certbot-auto script, or using native " + "OS packages.") + + class _Default(object): """A class to use as a default to detect if a value is set by a user""" diff --git a/certbot/main.py b/certbot/main.py index 72f4fe66e..05347734e 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -649,6 +649,7 @@ def main(cli_args=sys.argv[1:]): args = cli.prepare_and_parse_args(plugins, cli_args) config = configuration.NamespaceConfig(args) zope.component.provideUtility(config) + cli.possible_deprecation_warning(config) # Setup logging ASAP, otherwise "No handlers could be found for # logger ..." TODO: this should be done before plugins discovery From 45681909c7fba2e0b061f6e5abe471d252c45a08 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 20 Apr 2016 14:39:26 -0400 Subject: [PATCH 022/186] Selectively rename le-auto strings --- letsencrypt-auto-source/letsencrypt-auto | 38 +++++++++---------- .../letsencrypt-auto.template | 20 +++++----- letsencrypt-auto-source/pieces/fetch.py | 2 +- .../pieces/letsencrypt-auto-requirements.txt | 2 +- letsencrypt-auto-source/tests/auto_test.py | 12 +++--- 5 files changed, 35 insertions(+), 39 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 111f2b272..c137c4978 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -1,6 +1,6 @@ #!/bin/sh # -# Download and run the latest release version of the Let's Encrypt client. +# Download and run the latest release version of the Certbot client. # # NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING # @@ -21,7 +21,7 @@ VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" LE_AUTO_VERSION="0.6.0.dev0" -# This script takes the same arguments as the main letsencrypt program, but it +# This script takes the same arguments as the main certbot program, but it # additionally responds to --verbose (more output) and --debug (allow support # for experimental platforms) for arg in "$@" ; do @@ -45,8 +45,8 @@ for arg in "$@" ; do esac done -# letsencrypt-auto needs root access to bootstrap OS dependencies, and -# letsencrypt itself needs root access for almost all modes of operation +# 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 # this script *can* be run as root (not recommended), or fall back to using # `su` @@ -186,7 +186,7 @@ BootstrapDebCommon() { AddBackportRepo precise-backports "deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse" else echo "No libaugeas0 version is available that's new enough to run the" - echo "Let's Encrypt apache plugin..." + echo "Certbot apache plugin..." fi # XXX add a case for ubuntu PPAs fi @@ -426,7 +426,7 @@ Bootstrap() { elif grep -iq "Amazon Linux" /etc/issue ; then ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon else - echo "Sorry, I don't know how to bootstrap Let's Encrypt on your operating system!" + echo "Sorry, I don't know how to bootstrap Certbot on your operating system!" echo echo "You will need to bootstrap, configure virtualenv, and run pip install manually." echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" @@ -446,7 +446,8 @@ if [ "$1" = "--le-auto-phase2" ]; then shift 1 # the --le-auto-phase2 arg if [ -f "$VENV_BIN/letsencrypt" ]; then # --version output ran through grep due to python-cryptography DeprecationWarnings - INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep ^letsencrypt | cut -d " " -f 2) + # grep for both certbot and letsencrypt until certbot and shim packages have been released + INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2) else INSTALLED_VERSION="none" fi @@ -465,8 +466,8 @@ if [ "$1" = "--le-auto-phase2" ]; then # There is no $ interpolation due to quotes on starting heredoc delimiter. # ------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt" -# This is the flattened list of packages letsencrypt-auto installs. To generate -# this, do `pip install --no-cache-dir -e acme -e . -e letsencrypt-apache`, and +# This is the flattened list of packages certbot-auto installs. To generate +# this, do `pip install --no-cache-dir -e acme -e . -e certbot-apache`, and # then use `hashin` or a more secure method to gather the hashes. argparse==1.4.0 \ @@ -823,16 +824,16 @@ UNLIKELY_EOF fi echo "Installation succeeded." fi - echo "Requesting root privileges to run letsencrypt..." + echo "Requesting root privileges to run certbot..." echo " " $SUDO "$VENV_BIN/letsencrypt" "$@" $SUDO "$VENV_BIN/letsencrypt" "$@" else - # Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke. + # Phase 1: Upgrade certbot-auto if neceesary, then self-invoke. # # Each phase checks the version of only the thing it is responsible for # upgrading. Phase 1 checks the version of the latest release of - # letsencrypt-auto (which is always the same as that of the letsencrypt - # package). Phase 2 checks the version of the locally installed letsencrypt. + # certbot-auto (which is always the same as that of the certbot + # package). Phase 2 checks the version of the locally installed certbot. if [ ! -f "$VENV_BIN/letsencrypt" ]; then # If it looks like we've never bootstrapped before, bootstrap: @@ -953,7 +954,7 @@ def verified_new_le_auto(get, tag, temp_dir): stderr=dev_null) except CalledProcessError as exc: raise ExpectedError("Couldn't verify signature of downloaded " - "letsencrypt-auto.", exc) + "certbot-auto.", exc) def main(): @@ -980,27 +981,24 @@ UNLIKELY_EOF DeterminePythonVersion REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` if [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then - echo "Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." + echo "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." # Now we drop into Python so we don't have to install even more # dependencies (curl, etc.), for better flow control, and for the option of # future Windows compatibility. "$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION" - # Install new copy of letsencrypt-auto. + # Install new copy of certbot-auto. # TODO: Deal with quotes in pathnames. - echo "Replacing letsencrypt-auto..." + echo "Replacing certbot-auto..." # Clone permissions with cp. chmod and chown don't have a --reference # option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD: - echo " " $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone" $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone" - echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone" $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone" # Using mv rather than cp leaves the old file descriptor pointing to the # original copy so the shell can continue to read it unmolested. mv across # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the # cp is unlikely to fail (esp. under sudo) if the rm doesn't. - echo " " $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" # TODO: Clean up temp dir safely, even if it has quotes in its path. rm -rf "$TEMP_DIR" diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 2c8e1ec4c..67f82febf 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -21,7 +21,7 @@ VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" LE_AUTO_VERSION="{{ LE_AUTO_VERSION }}" -# This script takes the same arguments as the main letsencrypt program, but it +# This script takes the same arguments as the main certbot program, but it # additionally responds to --verbose (more output) and --debug (allow support # for experimental platforms) for arg in "$@" ; do @@ -45,7 +45,7 @@ for arg in "$@" ; do esac done -# letsencrypt-auto needs root access to bootstrap OS dependencies, and +# 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 # this script *can* be run as root (not recommended), or fall back to using @@ -177,7 +177,8 @@ if [ "$1" = "--le-auto-phase2" ]; then shift 1 # the --le-auto-phase2 arg if [ -f "$VENV_BIN/letsencrypt" ]; then # --version output ran through grep due to python-cryptography DeprecationWarnings - INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep ^letsencrypt | cut -d " " -f 2) + # grep for both certbot and letsencrypt until certbot and shim packages have been released + INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2) else INSTALLED_VERSION="none" fi @@ -223,11 +224,11 @@ UNLIKELY_EOF echo " " $SUDO "$VENV_BIN/letsencrypt" "$@" $SUDO "$VENV_BIN/letsencrypt" "$@" else - # Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke. + # Phase 1: Upgrade certbot-auto if neceesary, then self-invoke. # # Each phase checks the version of only the thing it is responsible for # upgrading. Phase 1 checks the version of the latest release of - # letsencrypt-auto (which is always the same as that of the certbot + # certbot-auto (which is always the same as that of the certbot # package). Phase 2 checks the version of the locally installed certbot. if [ ! -f "$VENV_BIN/letsencrypt" ]; then @@ -250,27 +251,24 @@ UNLIKELY_EOF DeterminePythonVersion REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` if [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then - echo "Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." + echo "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." # Now we drop into Python so we don't have to install even more # dependencies (curl, etc.), for better flow control, and for the option of # future Windows compatibility. "$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION" - # Install new copy of letsencrypt-auto. + # Install new copy of certbot-auto. # TODO: Deal with quotes in pathnames. - echo "Replacing letsencrypt-auto..." + echo "Replacing certbot-auto..." # Clone permissions with cp. chmod and chown don't have a --reference # option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD: - echo " " $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone" $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone" - echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone" $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone" # Using mv rather than cp leaves the old file descriptor pointing to the # original copy so the shell can continue to read it unmolested. mv across # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the # cp is unlikely to fail (esp. under sudo) if the rm doesn't. - echo " " $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" # TODO: Clean up temp dir safely, even if it has quotes in its path. rm -rf "$TEMP_DIR" diff --git a/letsencrypt-auto-source/pieces/fetch.py b/letsencrypt-auto-source/pieces/fetch.py index 39ff7777c..38f4aa255 100644 --- a/letsencrypt-auto-source/pieces/fetch.py +++ b/letsencrypt-auto-source/pieces/fetch.py @@ -103,7 +103,7 @@ def verified_new_le_auto(get, tag, temp_dir): stderr=dev_null) except CalledProcessError as exc: raise ExpectedError("Couldn't verify signature of downloaded " - "letsencrypt-auto.", exc) + "certbot-auto.", exc) def main(): diff --git a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt index 27cfb3d43..3a1ce34f1 100644 --- a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt +++ b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt @@ -1,4 +1,4 @@ -# This is the flattened list of packages letsencrypt-auto installs. To generate +# This is the flattened list of packages certbot-auto installs. To generate # this, do `pip install --no-cache-dir -e acme -e . -e certbot-apache`, and # then use `hashin` or a more secure method to gather the hashes. diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index edb5f0c04..3b7e8731b 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -231,7 +231,7 @@ class AutoTests(TestCase): * The OpenSSL sig mismatches. For tests which get to the end, we run merely ``letsencrypt --version``. - The functioning of the rest of the letsencrypt script is covered by other + The functioning of the rest of the certbot script is covered by other test suites. """ @@ -277,7 +277,7 @@ class AutoTests(TestCase): ok_(re.match(r'letsencrypt \d+\.\d+\.\d+', err.strip().splitlines()[-1])) # Make a few assertions to test the validity of the next tests: - self.assertIn('Upgrading letsencrypt-auto ', out) + self.assertIn('Upgrading certbot-auto ', out) self.assertIn('Creating virtual environment...', out) # Now we have le-auto 99.9.9 and LE 99.9.9 installed. This @@ -286,14 +286,14 @@ class AutoTests(TestCase): # Test when neither phase-1 upgrade nor phase-2 upgrade is # needed (probably a common case): out, err = run_letsencrypt_auto() - self.assertNotIn('Upgrading letsencrypt-auto ', out) + self.assertNotIn('Upgrading certbot-auto ', out) self.assertNotIn('Creating virtual environment...', out) # Test when a phase-1 upgrade is not needed but a phase-2 # upgrade is: set_le_script_version(venv_dir, '0.0.1') out, err = run_letsencrypt_auto() - self.assertNotIn('Upgrading letsencrypt-auto ', out) + self.assertNotIn('Upgrading certbot-auto ', out) self.assertIn('Creating virtual environment...', out) def test_openssl_failure(self): @@ -312,10 +312,10 @@ class AutoTests(TestCase): except CalledProcessError as exc: eq_(exc.returncode, 1) self.assertIn("Couldn't verify signature of downloaded " - "letsencrypt-auto.", + "certbot-auto.", exc.output) else: - self.fail('Signature check on letsencrypt-auto erroneously passed.') + self.fail('Signature check on certbot-auto erroneously passed.') def test_pip_failure(self): """Make sure pip stops us if there is a hash mismatch.""" From 530033a37dec26e40ba526d58694f61fd52c6066 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 21 Apr 2016 15:16:39 -0400 Subject: [PATCH 023/186] Add CLI parsing --- letsencrypt-auto-source/letsencrypt-auto | 10 ++++++++++ letsencrypt-auto-source/letsencrypt-auto.template | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index c137c4978..1b88f1cc1 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -34,6 +34,10 @@ for arg in "$@" ; do # Do not upgrade this script (also prevents client upgrades, because each # copy of the script pins a hash of the python client) NO_SELF_UPGRADE=1;; + --help) + HELP=1;; + --yes) + ASSUME_YES=1;; --verbose) VERBOSE=1;; [!-]*|-*[!v]*|-) @@ -81,6 +85,12 @@ else SUDO= fi +if [ $(basename $0) = "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 diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 67f82febf..f274418f3 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -34,6 +34,10 @@ for arg in "$@" ; do # Do not upgrade this script (also prevents client upgrades, because each # copy of the script pins a hash of the python client) NO_SELF_UPGRADE=1;; + --help) + HELP=1;; + --yes) + ASSUME_YES=1;; --verbose) VERBOSE=1;; [!-]*|-*[!v]*|-) @@ -81,6 +85,12 @@ else SUDO= fi +if [ $(basename $0) = "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 From 0fa18b608150472801ccddaead63f5b3e6a96f12 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 21 Apr 2016 15:55:28 -0400 Subject: [PATCH 024/186] Add help text --- letsencrypt-auto-source/letsencrypt-auto | 22 +++++++++++++++---- .../letsencrypt-auto.template | 22 +++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1b88f1cc1..df4783a72 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -20,10 +20,24 @@ VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" LE_AUTO_VERSION="0.6.0.dev0" +BASENAME=$(basename $0) +USAGE="Usage: $BASENAME [OPTION] +A self-updating wrapper script for the Certbot ACME client. When run, updates +to both this script and certbot will be downloaded and installed. After +ensuring you have the latest versions installed, certbot will be invoked with +all arguments you provided. + +Help for certbot itself cannot be provided until it is installed. + + --debug attempt installation on experimental platforms + --help print this help + --no-self-upgrade do not download updates for certbot or certbot-auto + --os-packages-only install OS dependencies and exit + -v, --verbose provide more output + --yes assume yes is the answer to all prompts + +All arguments are accepted and forwarded to the Certbot client when run." -# This script takes the same arguments as the main certbot program, but it -# additionally responds to --verbose (more output) and --debug (allow support -# for experimental platforms) for arg in "$@" ; do case "$arg" in --debug) @@ -85,7 +99,7 @@ else SUDO= fi -if [ $(basename $0) = "letsencrypt-auto" ]; then +if [ $BASENAME = "letsencrypt-auto" ]; then # letsencrypt-auto does not respect --help or --yes for backwards compatibility ASSUME_YES=1 HELP=0 diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index f274418f3..a17d11fa4 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -20,10 +20,24 @@ VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" LE_AUTO_VERSION="{{ LE_AUTO_VERSION }}" +BASENAME=$(basename $0) +USAGE="Usage: $BASENAME [OPTION] +A self-updating wrapper script for the Certbot ACME client. When run, updates +to both this script and certbot will be downloaded and installed. After +ensuring you have the latest versions installed, certbot will be invoked with +all arguments you provided. + +Help for certbot itself cannot be provided until it is installed. + + --debug attempt installation on experimental platforms + --help print this help + --no-self-upgrade do not download updates for certbot or certbot-auto + --os-packages-only install OS dependencies and exit + -v, --verbose provide more output + --yes assume yes is the answer to all prompts + +All arguments are accepted and forwarded to the Certbot client when run." -# This script takes the same arguments as the main certbot program, but it -# additionally responds to --verbose (more output) and --debug (allow support -# for experimental platforms) for arg in "$@" ; do case "$arg" in --debug) @@ -85,7 +99,7 @@ else SUDO= fi -if [ $(basename $0) = "letsencrypt-auto" ]; then +if [ $BASENAME = "letsencrypt-auto" ]; then # letsencrypt-auto does not respect --help or --yes for backwards compatibility ASSUME_YES=1 HELP=0 From c66f0bd18e9d65a48935eaf9d0c9ef630aa0f218 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 21 Apr 2016 16:13:17 -0400 Subject: [PATCH 025/186] Make le-auto helpful --- letsencrypt-auto-source/letsencrypt-auto | 8 ++++++-- letsencrypt-auto-source/letsencrypt-auto.template | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index df4783a72..9be546584 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -21,11 +21,11 @@ VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" LE_AUTO_VERSION="0.6.0.dev0" BASENAME=$(basename $0) -USAGE="Usage: $BASENAME [OPTION] +USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates to both this script and certbot will be downloaded and installed. After ensuring you have the latest versions installed, certbot will be invoked with -all arguments you provided. +all arguments you have provided. Help for certbot itself cannot be provided until it is installed. @@ -860,6 +860,10 @@ else # package). Phase 2 checks the version of the locally installed certbot. if [ ! -f "$VENV_BIN/letsencrypt" ]; then + if [ "$HELP" = 1 ]; then + echo "$USAGE" + exit 0 + fi # If it looks like we've never bootstrapped before, bootstrap: Bootstrap fi diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index a17d11fa4..fe4baeafd 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -21,11 +21,11 @@ VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" LE_AUTO_VERSION="{{ LE_AUTO_VERSION }}" BASENAME=$(basename $0) -USAGE="Usage: $BASENAME [OPTION] +USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates to both this script and certbot will be downloaded and installed. After ensuring you have the latest versions installed, certbot will be invoked with -all arguments you provided. +all arguments you have provided. Help for certbot itself cannot be provided until it is installed. @@ -256,6 +256,10 @@ else # package). Phase 2 checks the version of the locally installed certbot. if [ ! -f "$VENV_BIN/letsencrypt" ]; then + if [ "$HELP" = 1 ]; then + echo "$USAGE" + exit 0 + fi # If it looks like we've never bootstrapped before, bootstrap: Bootstrap fi From 2f81a8963e3038a5156ff660f663d55c1e3295ab Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 21 Apr 2016 15:18:27 -0700 Subject: [PATCH 026/186] move github refs back to LE --- docs/api/cb_util.rst | 5 ----- docs/api/le_util.rst | 5 +++++ docs/ciphers.rst | 4 ++-- docs/contributing.rst | 12 ++++++------ docs/using.rst | 14 +++++++------- 5 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 docs/api/cb_util.rst create mode 100644 docs/api/le_util.rst diff --git a/docs/api/cb_util.rst b/docs/api/cb_util.rst deleted file mode 100644 index 066fa906c..000000000 --- a/docs/api/cb_util.rst +++ /dev/null @@ -1,5 +0,0 @@ -:mod:`certbot.cb_util` --------------------------- - -.. automodule:: certbot.cb_util - :members: diff --git a/docs/api/le_util.rst b/docs/api/le_util.rst new file mode 100644 index 000000000..c9e332745 --- /dev/null +++ b/docs/api/le_util.rst @@ -0,0 +1,5 @@ +:mod:`certbot.le_util` +-------------------------- + +.. automodule:: certbot.le_util + :members: diff --git a/docs/ciphers.rst b/docs/ciphers.rst index be6784276..a37caa0d2 100644 --- a/docs/ciphers.rst +++ b/docs/ciphers.rst @@ -153,7 +153,7 @@ recommendations with sources of expert guidance on ciphersuites and other cryptographic parameters. We're grateful to everyone who contributed suggestions. The recommendations we received are available at -https://github.com/certbot/certbot/wiki/Ciphersuite-guidance +https://github.com/letsencrypt/letsencrypt/wiki/Ciphersuite-guidance Certbot users are welcome to review these authorities to better inform their own cryptographic parameter choices. We also @@ -196,7 +196,7 @@ TODO The status of this feature is tracked as part of issue #1123 in our bug tracker. -https://github.com/certbot/certbot/issues/1123 +https://github.com/letsencrypt/letsencrypt/issues/1123 Prior to implementation of #1123, the client does not actually modify ciphersuites (this is intended to be implemented as a "configuration diff --git a/docs/contributing.rst b/docs/contributing.rst index 3225de694..9f7a7b3c3 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -57,8 +57,8 @@ your pull request must have thorough unit test coverage, pass our `integration`_ tests, and be compliant with the :ref:`coding style `. -.. _github issue tracker: https://github.com/certbot/certbot/issues -.. _Good Volunteer Task: https://github.com/certbot/certbot/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+Volunteer+Task%22 +.. _github issue tracker: https://github.com/letsencrypt/letsencrypt/issues +.. _Good Volunteer Task: https://github.com/letsencrypt/letsencrypt/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+Volunteer+Task%22 Testing ------- @@ -146,7 +146,7 @@ encouraged) make sure to install prerequisites as listed in ``certbot-nginx/tests/boulder-integration.sh`` and rerun the integration tests suite. -.. _Boulder: https://github.com/certbot/boulder +.. _Boulder: https://github.com/letsencrypt/boulder .. _Go: https://golang.org @@ -175,8 +175,8 @@ Configurators may implement just one of those). There are also `~certbot.interfaces.IDisplay` plugins, which implement bindings to alternative UI libraries. -.. _interfaces.py: https://github.com/certbot/certbot/blob/master/certbot/interfaces.py -.. _plugins/common.py: https://github.com/certbot/certbot/blob/master/certbot/plugins/common.py#L34 +.. _interfaces.py: https://github.com/letsencrypt/letsencrypt/blob/master/letsencrypt/interfaces.py +.. _plugins/common.py: https://github.com/letsencrypt/letsencrypt/blob/master/letsencrypt/plugins/common.py#L34 Authenticators @@ -323,7 +323,7 @@ Steps: See `Known Issues`_. If it's not a known issue, fix any errors. .. _Known Issues: - https://github.com/certbot/certbot/wiki/Known-issues + https://github.com/letsencrypt/letsencrypt/wiki/Known-issues Updating the documentation ========================== diff --git a/docs/using.rst b/docs/using.rst index 2b16e9a27..94a4af72d 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -93,10 +93,10 @@ s3front_ Y Y Integration with Amazon CloudFront distribution of S3 buck gandi_ Y Y Integration with Gandi's hosting products and API =========== ==== ==== =============================================================== -.. _plesk: https://github.com/plesk/certbot-plesk -.. _haproxy: https://code.greenhost.net/open/certbot-haproxy -.. _s3front: https://github.com/dlapiduz/certbot-s3front -.. _gandi: https://github.com/Gandi/certbot-gandi +.. _plesk: https://github.com/plesk/letsencrypt-plesk +.. _haproxy: https://code.greenhost.net/open/letsencrypt-haproxy +.. _s3front: https://github.com/dlapiduz/letsencrypt-s3front +.. _gandi: https://github.com/Gandi/letsencrypt-gandi Future plugins for IMAP servers, SMTP servers, IRC servers, etc, are likely to be installers but not authenticators. @@ -194,7 +194,7 @@ Third-party plugins ------------------- These plugins are listed at -https://github.com/certbot/certbot/wiki/Plugins. If you're +https://github.com/letsencrypt/letsencrypt/wiki/Plugins. If you're interested, you can also :ref:`write your own plugin `. Renewal @@ -365,7 +365,7 @@ get support on our `forums `_. If you find a bug in the software, please do report it in our `issue tracker -`_. Remember to +`_. Remember to give us as much information as possible: - copy and paste exact command line used and the output (though mind @@ -390,7 +390,7 @@ plugins cannot reach it from inside the Docker container. You should definitely read the :ref:`where-certs` section, in order to know how to manage the certs -manually. https://github.com/certbot/certbot/wiki/Ciphersuite-guidance +manually. https://github.com/letsencrypt/letsencrypt/wiki/Ciphersuite-guidance provides some information about recommended ciphersuites. If none of these make much sense to you, you should definitely use the certbot-auto_ method, which enables you to use installer plugins From d803fb9d2a8d30e2485bf9742e57e2d800501945 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 21 Apr 2016 15:42:02 -0700 Subject: [PATCH 027/186] fix /etc/ and 3p --- docs/using.rst | 60 +++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 94a4af72d..07a3b6b6c 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -27,9 +27,9 @@ To install and run the client, just type... ./certbot-auto -.. hint:: During the beta phase, Certbot 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 +.. hint:: During the beta phase, the Let's Encrypt servers enforce 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 @@ -137,14 +137,14 @@ would obtain a single certificate for all of those names, using the ``/var/www/other`` for the second two. The webroot plugin works by creating a temporary file for each of your requested -domains in ``${webroot-path}/.well-known/acme-challenge``. Then the Certbot +domains in ``${webroot-path}/.well-known/acme-challenge``. Then the Let's Encrypt validation server makes HTTP requests to validate that the DNS for each requested domain resolves to the server running certbot. An example request made to your web server would look like: :: - 66.133.109.36 - - [05/Jan/2016:20:11:24 -0500] "GET /.well-known/acme-challenge/HGr8U1IeTW4kY_Z6UIyaakzOkyQgPr_7ArlLgtZE8SX HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Certbot validation server; +https://www.certbot.com)" + 66.133.109.36 - - [05/Jan/2016:20:11:24 -0500] "GET /.well-known/acme-challenge/HGr8U1IeTW4kY_Z6UIyaakzOkyQgPr_7ArlLgtZE8SX HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encryptvalidation server; +https://www.letsencrypt.org)" Note that to use the webroot plugin, your server must be configured to serve files from hidden directories. If ``/.well-known`` is treated specially by @@ -272,14 +272,14 @@ 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/certbot/live/$domain``. Rather than copying, please point +``/etc/letsencrypt/live/$domain``. Rather than copying, please point your (web) server configuration directly to those files (or create -symlinks). During the renewal_, ``/etc/certbot/live`` is updated +symlinks). During the renewal_, ``/etc/letsencrypt/live`` is updated with the latest necessary files. -.. note:: ``/etc/certbot/archive`` and ``/etc/certbot/keys`` +.. note:: ``/etc/letsencrypt/archive`` and ``/etc/letsencrypt/keys`` contain all previous keys and certificates, while - ``/etc/certbot/live`` symlinks to the latest versions. + ``/etc/letsencrypt/live`` symlinks to the latest versions. The following files are available: @@ -348,9 +348,9 @@ example configuration file is shown below: By default, the following locations are searched: -- ``/etc/certbot/cli.ini`` -- ``$XDG_CONFIG_HOME/certbot/cli.ini`` (or - ``~/.config/certbot/cli.ini`` if ``$XDG_CONFIG_HOME`` is not +- ``/etc/letsencrypt/cli.ini`` +- ``$XDG_CONFIG_HOME/letsencrypt/cli.ini`` (or + ``~/.config/letsencrypt/cli.ini`` if ``$XDG_CONFIG_HOME`` is not set). .. keep it up to date with constants.py @@ -361,7 +361,7 @@ Getting help If you're having problems you can chat with us on `IRC (#certbot @ OFTC) `_ or -get support on our `forums `_. +get support on our `forums `_. If you find a bug in the software, please do report it in our `issue tracker @@ -371,7 +371,7 @@ give us as much information as possible: - copy and paste exact command line used and the output (though mind that the latter might include some personally identifiable information, including your email and domains) -- copy and paste logs from ``/var/log/certbot`` (though mind they +- copy and paste logs from ``/var/log/letsencrypt`` (though mind they also might contain personally identifiable information) - copy and paste ``certbot --version`` output - your operating system, including specific version @@ -403,13 +403,13 @@ to, `install Docker`_, then issue the following command: .. code-block:: shell sudo docker run -it --rm -p 443:443 -p 80:80 --name certbot \ - -v "/etc/certbot:/etc/certbot" \ - -v "/var/lib/certbot:/var/lib/certbot" \ - quay.io/certbot/certbot:latest auth + -v "/etc/letsencrypt:/etc/letsencrypt" \ + -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ + quay.io/letsencrypt/letsencrypt:latest auth and follow the instructions (note that ``auth`` command is explicitly used - no installer plugins involved). Your new cert will be available -in ``/etc/certbot/live`` on the host. +in ``/etc/letsencrypt/live`` on the host. .. _Docker: https://docker.com .. _`install Docker`: https://docs.docker.com/userguide/ @@ -420,31 +420,31 @@ Operating System Packages **FreeBSD** - * Port: ``cd /usr/ports/security/py-certbot make install clean`` - * Package: ``pkg install py27-certbot`` + * Port: ``cd /usr/ports/security/py-letsencrypt make install clean`` + * Package: ``pkg install py27-letsencrypt`` **OpenBSD** - * Port: ``cd /usr/ports/security/certbot/client && make install clean`` - * Package: ``pkg_add certbot`` + * Port: ``cd /usr/ports/security/letsencrypt/client && make install clean`` + * Package: ``pkg_add letsencrypt`` **Arch Linux** .. code-block:: shell - sudo pacman -S certbot certbot-apache + sudo pacman -S letsencrypt letsencrypt-apache **Debian** -If you run Debian Stretch or Debian Sid, you can install certbot packages. +If you run Debian Stretch or Debian Sid, you can install letsencrypt packages. .. code-block:: shell sudo apt-get update - sudo apt-get install certbot python-certbot-apache + sudo apt-get install letsencrypt python-letsencrypt-apache If you don't want to use the Apache plugin, you can omit the -``python-certbot-apache`` package. +``python-letsencrypt-apache`` package. Packages for Debian Jessie are coming in the next few weeks. @@ -452,7 +452,7 @@ Packages for Debian Jessie are coming in the next few weeks. .. code-block:: shell - sudo dnf install certbot + sudo dnf install letsencrypt **Gentoo** @@ -461,8 +461,8 @@ want to use the Apache plugin, it has to be installed separately: .. code-block:: shell - emerge -av app-crypt/certbot - emerge -av app-crypt/certbot-apache + emerge -av app-crypt/letsencrypt + emerge -av app-crypt/letsencrypt-apache Currently, only the Apache plugin is included in Portage. However, if you want the nginx plugin, you can use Layman to add the mrueg overlay which @@ -473,7 +473,7 @@ does include the nginx plugin package: emerge -av app-portage/layman layman -S layman -a mrueg - emerge -av app-crypt/certbot-nginx + emerge -av app-crypt/letsencrypt-nginx When using the Apache plugin, you will run into a "cannot find a cert or key directive" error if you're sporting the default Gentoo ``httpd.conf``. From 2869f06109951a393134a868a02226d9f0569a1e Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 21 Apr 2016 15:56:23 -0700 Subject: [PATCH 028/186] add README.rst --- README.rst | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.rst b/README.rst index 050cde82b..7c7269dba 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ Disclaimer ========== -The Let's Encrypt Client is **BETA SOFTWARE**. It contains plenty of bugs and +The Certbot is **BETA SOFTWARE**. It contains plenty of bugs and rough edges, and should be tested thoroughly in staging environments before use on production systems. @@ -11,10 +11,10 @@ For more information regarding the status of the project, please see https://letsencrypt.org. Be sure to checkout the `Frequently Asked Questions (FAQ) `_. -About the Let's Encrypt Client +About Certbot ============================== -The Let's Encrypt Client is a fully-featured, extensible client for the Let's +Certbot is a fully-featured, extensible client for the Let's Encrypt CA (or any other CA that speaks the `ACME `_ protocol) that can automate the tasks of obtaining certificates and @@ -24,22 +24,22 @@ systems. Installation ------------ -If ``letsencrypt`` is packaged for your Unix OS, you can install it from -there, and run it by typing ``letsencrypt``. Because not all operating -systems have packages yet, we provide a temporary solution via the -``letsencrypt-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, 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:~$ git clone https://github.com/letsencrypt/letsencrypt user@webserver:~$ cd letsencrypt - user@webserver:~/letsencrypt$ ./letsencrypt-auto --help + user@webserver:~/letsencrypt$ ./certbot-auto --help Or for full command line help, type:: - ./letsencrypt-auto --help all + ./certbot-auto --help all -``letsencrypt-auto`` updates to the latest client release automatically. And -since ``letsencrypt-auto`` is a wrapper to ``letsencrypt``, it accepts exactly +``certbot-auto`` updates to the latest client release automatically. And +since ``certbot-auto`` is a wrapper to ``certbot``, it accepts exactly the same command line flags and arguments. More details about this script and other installation methods can be found `in the User Guide `_. @@ -47,7 +47,7 @@ other installation methods can be found `in the User Guide How to run the client --------------------- -In many cases, you can just run ``letsencrypt-auto`` or ``letsencrypt``, and the +In many cases, you can just run ``certbot-auto`` or ``certbot``, and the client will guide you through the process of obtaining and installing certs interactively. @@ -56,7 +56,7 @@ For instance, if you want to obtain a cert for ``example.com``, ``www.example.com``, and ``other.example.net``, using the Apache plugin to both obtain and install the certs, you could do this:: - ./letsencrypt-auto --apache -d example.com -d www.example.com -d other.example.net + ./certbot-auto --apache -d example.com -d www.example.com -d other.example.net (The first time you run the command, it will make an account, and ask for an email and agreement to the Let's Encrypt Subscriber Agreement; you can @@ -65,7 +65,7 @@ automate those with ``--email`` and ``--agree-tos``) If you want to use a webserver that doesn't have full plugin support yet, you can still use "standalone" or "webroot" plugins to obtain a certificate:: - ./letsencrypt-auto certonly --standalone --email admin@example.com -d example.com -d www.example.com -d other.example.net + ./certbot-auto certonly --standalone --email admin@example.com -d example.com -d www.example.com -d other.example.net Understanding the client in more depth @@ -87,7 +87,7 @@ Notes for developers: https://letsencrypt.readthedocs.org/en/latest/contributing Main Website: https://letsencrypt.org/ -IRC Channel: #letsencrypt on `Freenode`_ +IRC Channel: #letsencrypt on `Freenode`_ or #certbot on `OFTC`_ Community: https://community.letsencrypt.org @@ -152,7 +152,7 @@ Current Features - standalone (runs its own simple webserver to prove you control a domain) - webroot (adds files to webroot directories in order to prove control of domains and obtain certs) - - nginx/0.8.48+ (highly experimental, not included in letsencrypt-auto) + - nginx/0.8.48+ (highly experimental, not included in certbot-auto) * The private key is generated locally on your system. * Can talk to the Let's Encrypt CA or optionally to other ACME From 61203db2ebd17a27cb0f3316812bb5d72683c546 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 22 Apr 2016 13:01:32 -0400 Subject: [PATCH 029/186] Add --yes support to arch and debian bootstrappers --- letsencrypt-auto-source/letsencrypt-auto | 14 +++++++++++--- .../pieces/bootstrappers/arch_common.sh | 6 +++++- .../pieces/bootstrappers/deb_common.sh | 8 ++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 9be546584..d96836e64 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -175,6 +175,10 @@ BootstrapDebCommon() { augeas_pkg="libaugeas0 augeas-lenses" AUGVERSION=`apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2` + if [ "$ASSUME_YES" = 1 ]; then + YES_FLAG="-y" + fi + AddBackportRepo() { # ARGS: BACKPORT_NAME="$1" @@ -196,7 +200,7 @@ BootstrapDebCommon() { $SUDO apt-get update fi fi - $SUDO apt-get install -y --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg + $SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg augeas_pkg= } @@ -215,7 +219,7 @@ BootstrapDebCommon() { # XXX add a case for ubuntu PPAs fi - $SUDO apt-get install -y --no-install-recommends \ + $SUDO apt-get install $YES_FLAG --no-install-recommends \ python \ python-dev \ $virtualenv \ @@ -334,8 +338,12 @@ BootstrapArchCommon() { # pacman -T exits with 127 if there are missing dependencies missing=$($SUDO pacman -T $deps) || true + if [ "$ASSUME_YES" = 1 ]; then + noconfirm="--noconfirm" + fi + if [ "$missing" ]; then - $SUDO pacman -S --needed $missing + $SUDO pacman -S --needed $missing $noconfirm fi } diff --git a/letsencrypt-auto-source/pieces/bootstrappers/arch_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/arch_common.sh index b2fc01a14..39e2da5fe 100755 --- a/letsencrypt-auto-source/pieces/bootstrappers/arch_common.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/arch_common.sh @@ -21,7 +21,11 @@ BootstrapArchCommon() { # pacman -T exits with 127 if there are missing dependencies missing=$($SUDO pacman -T $deps) || true + if [ "$ASSUME_YES" = 1 ]; then + noconfirm="--noconfirm" + fi + if [ "$missing" ]; then - $SUDO pacman -S --needed $missing + $SUDO pacman -S --needed $missing $noconfirm fi } diff --git a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh index 57ed11399..b2b76fd55 100644 --- a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh @@ -34,6 +34,10 @@ BootstrapDebCommon() { augeas_pkg="libaugeas0 augeas-lenses" AUGVERSION=`apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2` + if [ "$ASSUME_YES" = 1 ]; then + YES_FLAG="-y" + fi + AddBackportRepo() { # ARGS: BACKPORT_NAME="$1" @@ -55,7 +59,7 @@ BootstrapDebCommon() { $SUDO apt-get update fi fi - $SUDO apt-get install -y --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg + $SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg augeas_pkg= } @@ -74,7 +78,7 @@ BootstrapDebCommon() { # XXX add a case for ubuntu PPAs fi - $SUDO apt-get install -y --no-install-recommends \ + $SUDO apt-get install $YES_FLAG --no-install-recommends \ python \ python-dev \ $virtualenv \ From 40aa4dbf91349f5ca7a191d5f00f55b49f6e92af Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 22 Apr 2016 14:51:40 -0400 Subject: [PATCH 030/186] add --yes support to red hat bootstrap script --- letsencrypt-auto-source/letsencrypt-auto | 78 ++++++++++--------- .../pieces/bootstrappers/rpm_common.sh | 78 ++++++++++--------- 2 files changed, 82 insertions(+), 74 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index d96836e64..9e1dfef42 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -240,9 +240,10 @@ BootstrapDebCommon() { BootstrapRpmCommon() { # Tested with: - # - Fedora 22, 23 (x64) + # - Fedora 20, 21, 22, 23 (x64) # - Centos 7 (x64: on DigitalOcean droplet) # - CentOS 7 Minimal install in a Hyper-V VM + # - CentOS 6 (EPEL must be installed manually) if type dnf 2>/dev/null then @@ -256,47 +257,50 @@ BootstrapRpmCommon() { exit 1 fi + pkgs=" + gcc + dialog + augeas-libs + openssl + openssl-devel + libffi-devel + redhat-rpm-config + ca-certificates + " + # Some distros and older versions of current distros use a "python27" # instead of "python" naming convention. Try both conventions. - if ! $SUDO $tool install -y \ - python \ - python-devel \ - python-virtualenv \ - python-tools \ - python-pip - then - if ! $SUDO $tool install -y \ - python27 \ - python27-devel \ - python27-virtualenv \ - python27-tools \ - python27-pip - then - echo "Could not install Python dependencies. Aborting bootstrap!" - exit 1 - fi + if $SUDO $tool list python >/dev/null 2>&1; then + pkgs="$pkgs + python + python-devel + python-virtualenv + python-tools + python-pip + " + else + pkgs="$pkgs + python27 + python27-devel + python27-virtualenv + python27-tools + python27-pip + " fi - if ! $SUDO $tool install -y \ - gcc \ - dialog \ - augeas-libs \ - openssl \ - openssl-devel \ - libffi-devel \ - redhat-rpm-config \ - ca-certificates - then - echo "Could not install additional dependencies. Aborting bootstrap!" - exit 1 - fi - - if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then - if ! $SUDO $tool install -y mod_ssl - then - echo "Apache found, but mod_ssl could not be installed." - fi + pkgs="$pkgs + mod_ssl + " + fi + + if [ "$ASSUME_YES" = 1 ]; then + yes_flag="-y" + fi + + if ! $SUDO $tool install $yes_flag $pkgs; then + echo "Could not install OS dependencies. Aborting bootstrap!" + exit 1 fi } diff --git a/letsencrypt-auto-source/pieces/bootstrappers/rpm_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/rpm_common.sh index 68a11a531..0f98b4bbc 100755 --- a/letsencrypt-auto-source/pieces/bootstrappers/rpm_common.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/rpm_common.sh @@ -1,8 +1,9 @@ BootstrapRpmCommon() { # Tested with: - # - Fedora 22, 23 (x64) + # - Fedora 20, 21, 22, 23 (x64) # - Centos 7 (x64: on DigitalOcean droplet) # - CentOS 7 Minimal install in a Hyper-V VM + # - CentOS 6 (EPEL must be installed manually) if type dnf 2>/dev/null then @@ -16,46 +17,49 @@ BootstrapRpmCommon() { exit 1 fi + pkgs=" + gcc + dialog + augeas-libs + openssl + openssl-devel + libffi-devel + redhat-rpm-config + ca-certificates + " + # Some distros and older versions of current distros use a "python27" # instead of "python" naming convention. Try both conventions. - if ! $SUDO $tool install -y \ - python \ - python-devel \ - python-virtualenv \ - python-tools \ - python-pip - then - if ! $SUDO $tool install -y \ - python27 \ - python27-devel \ - python27-virtualenv \ - python27-tools \ - python27-pip - then - echo "Could not install Python dependencies. Aborting bootstrap!" - exit 1 - fi + if $SUDO $tool list python >/dev/null 2>&1; then + pkgs="$pkgs + python + python-devel + python-virtualenv + python-tools + python-pip + " + else + pkgs="$pkgs + python27 + python27-devel + python27-virtualenv + python27-tools + python27-pip + " fi - if ! $SUDO $tool install -y \ - gcc \ - dialog \ - augeas-libs \ - openssl \ - openssl-devel \ - libffi-devel \ - redhat-rpm-config \ - ca-certificates - then - echo "Could not install additional dependencies. Aborting bootstrap!" - exit 1 - fi - - if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then - if ! $SUDO $tool install -y mod_ssl - then - echo "Apache found, but mod_ssl could not be installed." - fi + pkgs="$pkgs + mod_ssl + " + fi + + if [ "$ASSUME_YES" = 1 ]; then + yes_flag="-y" + fi + + if ! $SUDO $tool install $yes_flag $pkgs; then + echo "Could not install OS dependencies. Aborting bootstrap!" + exit 1 fi } From ab2319e6097beab3b05e5428b8185a6e1b330e5e Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 22 Apr 2016 15:00:24 -0400 Subject: [PATCH 031/186] Respect yes with opensuse bootstrap --- letsencrypt-auto-source/letsencrypt-auto | 7 ++++++- .../pieces/bootstrappers/suse_common.sh | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 9e1dfef42..dfa39b6d1 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -307,7 +307,12 @@ BootstrapRpmCommon() { BootstrapSuseCommon() { # SLE12 don't have python-virtualenv - $SUDO zypper -nq in -l \ + if [ "$ASSUME_YES" = 1 ]; then + zypper_flags="-nq" + install_flags="-l" + fi + + $SUDO zypper $zypper_flags in $install_flags \ python \ python-devel \ python-virtualenv \ diff --git a/letsencrypt-auto-source/pieces/bootstrappers/suse_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/suse_common.sh index 46c60f992..9ac295922 100755 --- a/letsencrypt-auto-source/pieces/bootstrappers/suse_common.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/suse_common.sh @@ -1,7 +1,12 @@ BootstrapSuseCommon() { # SLE12 don't have python-virtualenv - $SUDO zypper -nq in -l \ + if [ "$ASSUME_YES" = 1 ]; then + zypper_flags="-nq" + install_flags="-l" + fi + + $SUDO zypper $zypper_flags in $install_flags \ python \ python-devel \ python-virtualenv \ From 23baf225a4ee9fb9382381290781f9d9c124ac20 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 22 Apr 2016 16:44:06 -0400 Subject: [PATCH 032/186] Ask before enabling backports --- letsencrypt-auto-source/letsencrypt-auto | 34 ++++++++++++------- .../pieces/bootstrappers/deb_common.sh | 34 ++++++++++++------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index dfa39b6d1..3ca88c279 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -183,26 +183,34 @@ BootstrapDebCommon() { # ARGS: BACKPORT_NAME="$1" BACKPORT_SOURCELINE="$2" + echo "To use the Apache Certbot plugin, augeas needs to be installed from $BACKPORT_NAME." if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then # This can theoretically error if sources.list.d is empty, but in that case we don't care. if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then - /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." - sleep 1s - /bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..." - sleep 1s - /bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..." - sleep 1s if echo $BACKPORT_NAME | grep -q wheezy ; then - /bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")' + echo 'Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports"' + fi + if [ "$ASSUME_YES" = 1 ]; then + add_backports=1 + else + read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response + case $response in + [yY][eE][sS]|[yY]|"") + add_backports=1;; + *) + add_backports=0;; + esac + fi + if [ "$add_backports" = 1 ]; then + $SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list" + $SUDO apt-get update fi - - $SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list" - $SUDO apt-get update fi fi - $SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg - augeas_pkg= - + if [ "$add_backports" != 0 ]; then + $SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg + augeas_pkg= + fi } diff --git a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh index b2b76fd55..5370aa2f2 100644 --- a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh @@ -42,26 +42,34 @@ BootstrapDebCommon() { # ARGS: BACKPORT_NAME="$1" BACKPORT_SOURCELINE="$2" + echo "To use the Apache Certbot plugin, augeas needs to be installed from $BACKPORT_NAME." if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then # This can theoretically error if sources.list.d is empty, but in that case we don't care. if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then - /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." - sleep 1s - /bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..." - sleep 1s - /bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..." - sleep 1s if echo $BACKPORT_NAME | grep -q wheezy ; then - /bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")' + echo 'Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports"' + fi + if [ "$ASSUME_YES" = 1 ]; then + add_backports=1 + else + read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response + case $response in + [yY][eE][sS]|[yY]|"") + add_backports=1;; + *) + add_backports=0;; + esac + fi + if [ "$add_backports" = 1 ]; then + $SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list" + $SUDO apt-get update fi - - $SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list" - $SUDO apt-get update fi fi - $SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg - augeas_pkg= - + if [ "$add_backports" != 0 ]; then + $SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg + augeas_pkg= + fi } From 771f5cfe49bc43e43870cc11a390c0c646353290 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Tue, 26 Apr 2016 04:20:50 +0200 Subject: [PATCH 033/186] Implementing schoen's correction --- certbot/storage.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/certbot/storage.py b/certbot/storage.py index fdbdf7a0e..42cbfc2c9 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -79,9 +79,8 @@ def write_renewal_config(o_filename, n_filename, target, relevant_data): del config["renewalparams"][k] if "renew_before_expiry" not in config["renewalparams"]: - config["renewalparams"]["renew_before_expiry"] = ( + config["renewalparams"].comments["renew_before_expiry"] = ( constants.RENEWER_DEFAULTS["renew_before_expiry"]) - config["renewalparams"].comments["renew_before_expiry"] = ["Renewal interval"] # TODO: add human-readable comments explaining other available # parameters From 070642faafd2eb5fccac04dd8f14c6b7c1d0528d Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Tue, 26 Apr 2016 05:26:07 +0200 Subject: [PATCH 034/186] Fixing renew_before_expiry comment --- certbot/storage.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/certbot/storage.py b/certbot/storage.py index 42cbfc2c9..82f07e3c5 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -79,8 +79,7 @@ def write_renewal_config(o_filename, n_filename, target, relevant_data): del config["renewalparams"][k] if "renew_before_expiry" not in config["renewalparams"]: - config["renewalparams"].comments["renew_before_expiry"] = ( - constants.RENEWER_DEFAULTS["renew_before_expiry"]) + config.final_comment = ["renew_before_expiry = 30 days"] # TODO: add human-readable comments explaining other available # parameters From e3ad290dff710152f95b1418245dcb2247c72f38 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Wed, 27 Apr 2016 02:50:36 +0200 Subject: [PATCH 035/186] Moving renew_before_expiry comment to initial_comment --- certbot/storage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot/storage.py b/certbot/storage.py index 82f07e3c5..caf268933 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -78,8 +78,8 @@ def write_renewal_config(o_filename, n_filename, target, relevant_data): if k not in relevant_data: del config["renewalparams"][k] - if "renew_before_expiry" not in config["renewalparams"]: - config.final_comment = ["renew_before_expiry = 30 days"] + if "renew_before_expiry" not in config: + config.initial_comment = ["renew_before_expiry = 30 days"] # TODO: add human-readable comments explaining other available # parameters From bf6f6b636cf70f964dcd7d3fed5e31d88eabce8d Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Thu, 28 Apr 2016 02:32:53 +0200 Subject: [PATCH 036/186] Setting value of commented renew_before_expiry to default value --- certbot/storage.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/certbot/storage.py b/certbot/storage.py index caf268933..c4bfb3e28 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -79,7 +79,8 @@ def write_renewal_config(o_filename, n_filename, target, relevant_data): del config["renewalparams"][k] if "renew_before_expiry" not in config: - config.initial_comment = ["renew_before_expiry = 30 days"] + default_interval = constants.RENEWER_DEFAULTS["renew_before_expiry"] + config.initial_comment = ["renew_before_expiry = " + default_interval] # TODO: add human-readable comments explaining other available # parameters From 528a816f704b3d359c423425eadc1c66c4d9f181 Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Mon, 2 May 2016 09:30:32 +0300 Subject: [PATCH 037/186] Don't fail authentication when vhost cannot be found Should fix #677 and #2600. --- certbot-apache/certbot_apache/tls_sni_01.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/tls_sni_01.py b/certbot-apache/certbot_apache/tls_sni_01.py index 1236c2eb9..a8a931fd6 100644 --- a/certbot-apache/certbot_apache/tls_sni_01.py +++ b/certbot-apache/certbot_apache/tls_sni_01.py @@ -4,6 +4,7 @@ import os import logging from certbot.plugins import common +from certbot.errors import PluginError from certbot_apache import obj from certbot_apache import parser @@ -116,12 +117,21 @@ class ApacheTlsSni01(common.TLSSNI01): def _get_addrs(self, achall): """Return the Apache addresses needed for TLS-SNI-01.""" - vhost = self.configurator.choose_vhost(achall.domain, temp=True) # TODO: Checkout _default_ rules. addrs = set() default_addr = obj.Addr(("*", str( self.configurator.config.tls_sni_01_port))) + try: + vhost = self.configurator.choose_vhost(achall.domain, temp=True) + except PluginError: + # We couldn't find the virtualhost for this domain, possibly + # because it's a new vhost that's not configured yet (GH #677), + # or perhaps because there were multiple sections + # in the config file (GH #1042). See also GH #2600. + addrs.add(default_addr) + return addrs + for addr in vhost.addrs: if "_default_" == addr.get_addr(): addrs.add(default_addr) From 8b4f48556d2f3b1614641ddd87ada36586f99e4a Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Mon, 2 May 2016 09:45:27 +0300 Subject: [PATCH 038/186] Catch the right exception Conrary to the docstring of choose_vhost(), when you run non-interactive certificate renewals and the Apache plugin fails to discover the correct vhost, it raises MissingCommandlineFlag and not PluginError. --- certbot-apache/certbot_apache/tls_sni_01.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot-apache/certbot_apache/tls_sni_01.py b/certbot-apache/certbot_apache/tls_sni_01.py index a8a931fd6..f14f7be0f 100644 --- a/certbot-apache/certbot_apache/tls_sni_01.py +++ b/certbot-apache/certbot_apache/tls_sni_01.py @@ -4,7 +4,7 @@ import os import logging from certbot.plugins import common -from certbot.errors import PluginError +from certbot.errors import PluginError, MissingCommandlineFlag from certbot_apache import obj from certbot_apache import parser @@ -124,7 +124,7 @@ class ApacheTlsSni01(common.TLSSNI01): try: vhost = self.configurator.choose_vhost(achall.domain, temp=True) - except PluginError: + except (PluginError, MissingCommandlineFlag): # We couldn't find the virtualhost for this domain, possibly # because it's a new vhost that's not configured yet (GH #677), # or perhaps because there were multiple sections From d73e2e68ac65a80a4407f83ebd1b2ea1fa25681e Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Mon, 2 May 2016 11:45:07 +0300 Subject: [PATCH 039/186] Add a test for #2906 --- .../certbot_apache/tests/tls_sni_01_test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/certbot-apache/certbot_apache/tests/tls_sni_01_test.py b/certbot-apache/certbot_apache/tests/tls_sni_01_test.py index 17ef92004..aa6a2a09c 100644 --- a/certbot-apache/certbot_apache/tests/tls_sni_01_test.py +++ b/certbot-apache/certbot_apache/tests/tls_sni_01_test.py @@ -4,6 +4,7 @@ import shutil import mock +from certbot import errors from certbot.plugins import common_test from certbot_apache import obj @@ -137,6 +138,16 @@ class TlsSniPerformTest(util.ApacheTest): set([obj.Addr.fromstring("*:443")]), self.sni._get_addrs(self.achalls[0])) + def test_get_addrs_no_vhost_found(self): + self.sni.configurator.choose_vhost = mock.Mock( + side_effect=errors.MissingCommandlineFlag( + "Failed to run Apache plugin non-interactively")) + + # pylint: disable=protected-access + self.assertEqual( + set([obj.Addr.fromstring("*:443")]), + self.sni._get_addrs(self.achalls[0])) + if __name__ == "__main__": unittest.main() # pragma: no cover From 0f228e935dd39ef72792aa39b70a2163b665594d Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 2 May 2016 11:52:57 -0700 Subject: [PATCH 040/186] Add backports countdown when using --yes/letsencrypt-auto --- letsencrypt-auto-source/letsencrypt-auto | 6 ++++++ letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 3ca88c279..adeb94e3e 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -191,6 +191,12 @@ BootstrapDebCommon() { echo 'Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports"' fi if [ "$ASSUME_YES" = 1 ]; then + /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." + sleep 1s + /bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..." + sleep 1s + /bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..." + sleep 1s add_backports=1 else read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response diff --git a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh index 5370aa2f2..e91f52261 100644 --- a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh @@ -50,6 +50,12 @@ BootstrapDebCommon() { echo 'Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports"' fi if [ "$ASSUME_YES" = 1 ]; then + /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." + sleep 1s + /bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..." + sleep 1s + /bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..." + sleep 1s add_backports=1 else read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response From 8f6c289e780903ce68b3b66d71a672b866b2e47e Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 2 May 2016 13:59:42 -0700 Subject: [PATCH 041/186] incorperate jsha's comments --- README.rst | 4 ++++ docs/contributing.rst | 2 +- docs/packaging.rst | 2 +- docs/using.rst | 11 ++++++----- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 7c7269dba..a2af9ec59 100644 --- a/README.rst +++ b/README.rst @@ -21,6 +21,10 @@ protocol) that can automate the tasks of obtaining certificates and configuring webservers to use them. This client runs on Unix-based operating systems. +Until May 2016, Certbot was named simply ``letsencrypt`` or ``letsencrypt-auto``, +depending on install method. Instructions on the Internet, and some pieces of the +software, may still refer to this older name. + Installation ------------ diff --git a/docs/contributing.rst b/docs/contributing.rst index 9f7a7b3c3..60cc63e66 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -175,7 +175,7 @@ Configurators may implement just one of those). There are also `~certbot.interfaces.IDisplay` plugins, which implement bindings to alternative UI libraries. -.. _interfaces.py: https://github.com/letsencrypt/letsencrypt/blob/master/letsencrypt/interfaces.py +.. _interfaces.py: https://github.com/letsencrypt/letsencrypt/blob/master/certbot/interfaces.py .. _plugins/common.py: https://github.com/letsencrypt/letsencrypt/blob/master/letsencrypt/plugins/common.py#L34 diff --git a/docs/packaging.rst b/docs/packaging.rst index bd366dbaa..5f09b65fa 100644 --- a/docs/packaging.rst +++ b/docs/packaging.rst @@ -3,4 +3,4 @@ Packaging Guide =============== Documentation can be found at -https://github.com/certbot/certbot/wiki/Packaging. +https://github.com/letsencrypt/letsencrypt/wiki/Packaging. diff --git a/docs/using.rst b/docs/using.rst index 07a3b6b6c..56ce78e80 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -27,7 +27,7 @@ To install and run the client, just type... ./certbot-auto -.. hint:: During the beta phase, the Let's Encrypt servers enforce strict rate +.. 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. @@ -144,7 +144,7 @@ made to your web server would look like: :: - 66.133.109.36 - - [05/Jan/2016:20:11:24 -0500] "GET /.well-known/acme-challenge/HGr8U1IeTW4kY_Z6UIyaakzOkyQgPr_7ArlLgtZE8SX HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encryptvalidation server; +https://www.letsencrypt.org)" + 66.133.109.36 - - [05/Jan/2016:20:11:24 -0500] "GET /.well-known/acme-challenge/HGr8U1IeTW4kY_Z6UIyaakzOkyQgPr_7ArlLgtZE8SX HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)" Note that to use the webroot plugin, your server must be configured to serve files from hidden directories. If ``/.well-known`` is treated specially by @@ -360,8 +360,9 @@ Getting help ============ If you're having problems you can chat with us on `IRC (#certbot @ -OFTC) `_ or -get support on our `forums `_. +OFTC) `_ or at +`IRC (#letsencrypt @ freenode) `_ +or get support on our `forums `_. If you find a bug in the software, please do report it in our `issue tracker @@ -420,7 +421,7 @@ Operating System Packages **FreeBSD** - * Port: ``cd /usr/ports/security/py-letsencrypt make install clean`` + * Port: ``cd /usr/ports/security/py-letsencrypt && make install clean`` * Package: ``pkg install py27-letsencrypt`` **OpenBSD** From a9ecd146a9797eb068827bf6c357fde15f3a9a03 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 2 May 2016 14:16:41 -0700 Subject: [PATCH 042/186] Make certbot accept --yes flag --- certbot/cli.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/certbot/cli.py b/certbot/cli.py index e2c57595b..40af5dccb 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -649,6 +649,9 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): "automation", "--no-self-upgrade", action="store_true", help="(letsencrypt-auto only) prevent the letsencrypt-auto script from" " upgrading itself to newer released versions") + helpful.add( + "automation", "--yes", action="store_true", + help="(letsencrypt-auto only) assume yes is the answer to all prompts") helpful.add( "automation", "-q", "--quiet", dest="quiet", action="store_true", help="Silence all output except errors. Useful for automation via cron." From b844b7d605b2bcaa174cf4b025af926bffd1bc81 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 3 May 2016 15:44:36 -0700 Subject: [PATCH 043/186] Create certbot-auto during release process --- tools/release.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/release.sh b/tools/release.sh index d41192af9..06aefea44 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -188,9 +188,10 @@ while ! openssl dgst -sha256 -verify $RELEASE_OPENSSL_PUBKEY -signature \ done # copy leauto to the root, overwriting the previous release version +cp -p letsencrypt-auto-source/letsencrypt-auto certbot-auto cp -p letsencrypt-auto-source/letsencrypt-auto letsencrypt-auto -git add letsencrypt-auto letsencrypt-auto-source +git add certbot-auto letsencrypt-auto letsencrypt-auto-source 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" From 891b186856026da0d11e5916bfe78280ca7faa0d Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Tue, 3 May 2016 17:04:30 -0700 Subject: [PATCH 044/186] changed wiki refs, added some words --- docs/ciphers.rst | 6 +++--- docs/contributing.rst | 14 +++++++------- docs/packaging.rst | 2 +- docs/using.rst | 10 +++++----- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/ciphers.rst b/docs/ciphers.rst index a37caa0d2..5a046e757 100644 --- a/docs/ciphers.rst +++ b/docs/ciphers.rst @@ -131,7 +131,7 @@ The Let's Encrypt project may deviate from the Mozilla recommendations in the future if good cause is shown and we believe our users' priorities would be well-served by doing so. In general, please address relevant proposals for changing priorities to the Mozilla security -team first, before asking the Let's Encrypt project to change +team first, before asking the Let's Encrypt project or EFF to change Certbot's priorities. The Mozilla security team is likely to have more resources and expertise to bring to bear on evaluating reasons why its recommendations should be updated. @@ -153,7 +153,7 @@ recommendations with sources of expert guidance on ciphersuites and other cryptographic parameters. We're grateful to everyone who contributed suggestions. The recommendations we received are available at -https://github.com/letsencrypt/letsencrypt/wiki/Ciphersuite-guidance +https://github.com/certbot/certbot/wiki/Ciphersuite-guidance Certbot users are welcome to review these authorities to better inform their own cryptographic parameter choices. We also @@ -196,7 +196,7 @@ TODO The status of this feature is tracked as part of issue #1123 in our bug tracker. -https://github.com/letsencrypt/letsencrypt/issues/1123 +https://github.com/certbot/certbot/issues/1123 Prior to implementation of #1123, the client does not actually modify ciphersuites (this is intended to be implemented as a "configuration diff --git a/docs/contributing.rst b/docs/contributing.rst index 60cc63e66..49e9e146d 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -20,8 +20,8 @@ once: .. code-block:: shell - git clone https://github.com/letsencrypt/letsencrypt - cd letsencrypt + git clone https://github.com/certbot/certbot + cd certbot ./letsencrypt-auto-source/letsencrypt-auto --os-packages-only ./tools/venv.sh @@ -57,8 +57,8 @@ your pull request must have thorough unit test coverage, pass our `integration`_ tests, and be compliant with the :ref:`coding style `. -.. _github issue tracker: https://github.com/letsencrypt/letsencrypt/issues -.. _Good Volunteer Task: https://github.com/letsencrypt/letsencrypt/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+Volunteer+Task%22 +.. _github issue tracker: https://github.com/certbot/certbot/issues +.. _Good Volunteer Task: https://github.com/certbot/certbot/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+Volunteer+Task%22 Testing ------- @@ -175,8 +175,8 @@ Configurators may implement just one of those). There are also `~certbot.interfaces.IDisplay` plugins, which implement bindings to alternative UI libraries. -.. _interfaces.py: https://github.com/letsencrypt/letsencrypt/blob/master/certbot/interfaces.py -.. _plugins/common.py: https://github.com/letsencrypt/letsencrypt/blob/master/letsencrypt/plugins/common.py#L34 +.. _interfaces.py: https://github.com/certbot/certbot/blob/master/certbot/interfaces.py +.. _plugins/common.py: https://github.com/certbot/certbot/blob/master/certbot/plugins/common.py#L34 Authenticators @@ -323,7 +323,7 @@ Steps: See `Known Issues`_. If it's not a known issue, fix any errors. .. _Known Issues: - https://github.com/letsencrypt/letsencrypt/wiki/Known-issues + https://github.com/certbot/certbot/wiki/Known-issues Updating the documentation ========================== diff --git a/docs/packaging.rst b/docs/packaging.rst index 5f09b65fa..bd366dbaa 100644 --- a/docs/packaging.rst +++ b/docs/packaging.rst @@ -3,4 +3,4 @@ Packaging Guide =============== Documentation can be found at -https://github.com/letsencrypt/letsencrypt/wiki/Packaging. +https://github.com/certbot/certbot/wiki/Packaging. diff --git a/docs/using.rst b/docs/using.rst index 56ce78e80..0dcab4971 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -194,7 +194,7 @@ Third-party plugins ------------------- These plugins are listed at -https://github.com/letsencrypt/letsencrypt/wiki/Plugins. If you're +https://github.com/certbot/certbot/wiki/Plugins. If you're interested, you can also :ref:`write your own plugin `. Renewal @@ -362,11 +362,11 @@ Getting help If you're having problems you can chat with us on `IRC (#certbot @ OFTC) `_ or at `IRC (#letsencrypt @ freenode) `_ -or get support on our `forums `_. +or get support on the Let's Encrypt `forums `_. If you find a bug in the software, please do report it in our `issue tracker -`_. Remember to +`_. Remember to give us as much information as possible: - copy and paste exact command line used and the output (though mind @@ -391,7 +391,7 @@ plugins cannot reach it from inside the Docker container. You should definitely read the :ref:`where-certs` section, in order to know how to manage the certs -manually. https://github.com/letsencrypt/letsencrypt/wiki/Ciphersuite-guidance +manually. https://github.com/certbot/certbot/wiki/Ciphersuite-guidance provides some information about recommended ciphersuites. If none of these make much sense to you, you should definitely use the certbot-auto_ method, which enables you to use installer plugins @@ -526,7 +526,7 @@ whole process is described in the :doc:`contributing`. Comparison of different methods ------------------------------- -Unless you have a very specific requirements, we kindly ask you to use +Unless you have a very specific requirements, we kindly suggest that you use the certbot-auto_ method. It's the fastest, the most thoroughly tested and the most reliable way of getting our software and the free SSL certificates! From e1d93663997bca079d7a415733a6fc9b11bbc803 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Wed, 4 May 2016 10:52:58 -0700 Subject: [PATCH 045/186] updated README --- CHANGES.rst | 4 ++-- README.rst | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 55e4bd796..4ce41a8bc 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,9 +3,9 @@ ChangeLog Please note: the change log will only get updated after first release - for now please use the -`commit log `_. +`commit log `_. To see the changes in a given release, inspect the github milestone for the release. For instance: -https://github.com/letsencrypt/letsencrypt/issues?utf8=%E2%9C%93&q=milestone%3A0.3.0 +https://github.com/certbot/certbot/issues?utf8=%E2%9C%93&q=milestone%3A0.3.0 diff --git a/README.rst b/README.rst index a2af9ec59..60e11901c 100644 --- a/README.rst +++ b/README.rst @@ -34,9 +34,9 @@ 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:~$ git clone https://github.com/letsencrypt/letsencrypt - user@webserver:~$ cd letsencrypt - user@webserver:~/letsencrypt$ ./certbot-auto --help + user@webserver:~$ git clone https://github.com/certbot/certbot + user@webserver:~$ cd certbot + user@webserver:~/certbot$ ./certbot-auto --help Or for full command line help, type:: @@ -85,7 +85,7 @@ Links Documentation: https://letsencrypt.readthedocs.org -Software project: https://github.com/letsencrypt/letsencrypt +Software project: https://github.com/certbot/certbot Notes for developers: https://letsencrypt.readthedocs.org/en/latest/contributing.html @@ -107,12 +107,12 @@ email to client-dev+subscribe@letsencrypt.org) -.. |build-status| image:: https://travis-ci.org/letsencrypt/letsencrypt.svg?branch=master - :target: https://travis-ci.org/letsencrypt/letsencrypt +.. |build-status| image:: https://travis-ci.org/certbot/certbot.svg?branch=master + :target: https://travis-ci.org/certbot/certbot :alt: Travis CI status -.. |coverage| image:: https://coveralls.io/repos/letsencrypt/letsencrypt/badge.svg?branch=master - :target: https://coveralls.io/r/letsencrypt/letsencrypt +.. |coverage| image:: https://coveralls.io/repos/certbot/certbot/badge.svg?branch=master + :target: https://coveralls.io/r/certbot/certbot :alt: Coverage status .. |docs| image:: https://readthedocs.org/projects/letsencrypt/badge/ @@ -159,7 +159,7 @@ Current Features - nginx/0.8.48+ (highly experimental, not included in certbot-auto) * The private key is generated locally on your system. -* Can talk to the Let's Encrypt CA or optionally to other ACME +* Can talk to the Let's Encrypt CA or optionally to other ACME compliant services. * Can get domain-validated (DV) certificates. * Can revoke certificates. @@ -174,4 +174,5 @@ 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 From d9f36df96f458c98a81967074378118c2b7c970b Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Wed, 4 May 2016 16:02:48 -0700 Subject: [PATCH 046/186] contribute back changes from website --- docs/using.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 0dcab4971..83377ecee 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -433,7 +433,7 @@ Operating System Packages .. code-block:: shell - sudo pacman -S letsencrypt letsencrypt-apache + sudo pacman -S letsencrypt **Debian** @@ -442,10 +442,10 @@ If you run Debian Stretch or Debian Sid, you can install letsencrypt packages. .. code-block:: shell sudo apt-get update - sudo apt-get install letsencrypt python-letsencrypt-apache + sudo apt-get install certbot python-certbot-apache If you don't want to use the Apache plugin, you can omit the -``python-letsencrypt-apache`` package. +``python-certbot-apache`` package. Packages for Debian Jessie are coming in the next few weeks. @@ -466,8 +466,12 @@ want to use the Apache plugin, it has to be installed separately: emerge -av app-crypt/letsencrypt-apache Currently, only the Apache plugin is included in Portage. However, if you -want the nginx plugin, you can use Layman to add the mrueg overlay which -does include the nginx plugin package: +Warning! +You can use Layman to add the mrueg overlay which does include a package for the +Certbot Nginx plugin, however, this plugin is known to be buggy and should only +be used with caution after creating a backup up your Nginx configuration. +We strongly recommend you use the app-crypt/letsencrypt package instead until +the Nginx plugin is ready. .. code-block:: shell From 144f28690b75e0c4deef9395d774f8b0e774c28a Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Wed, 4 May 2016 17:03:52 -0700 Subject: [PATCH 047/186] added new docs links --- CONTRIBUTING.md | 2 +- README.rst | 14 ++++++++++---- certbot-apache/docs/conf.py | 2 +- certbot-compatibility-test/docs/conf.py | 2 +- certbot-nginx/docs/conf.py | 2 +- letshelp-certbot/docs/conf.py | 2 +- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bf19b18e1..5f1625658 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,4 +15,4 @@ to the Sphinx generated docs is provided below. --> -https://letsencrypt.readthedocs.org/en/latest/contributing.html +https://certbot.eff.org/docs/contributing.html diff --git a/README.rst b/README.rst index 60e11901c..1bfb8fdab 100644 --- a/README.rst +++ b/README.rst @@ -25,6 +25,12 @@ Until May 2016, Certbot was named simply ``letsencrypt`` or ``letsencrypt-auto`` depending on install method. Instructions on the Internet, and some pieces of the software, may still refer to this older name. +Contributing +------------ + +If you'd like to contribute to this project please read `Developer Guide +`_. + Installation ------------ @@ -46,7 +52,7 @@ Or for full command line help, type:: since ``certbot-auto`` is a wrapper to ``certbot``, it accepts exactly the same command line flags and arguments. More details about this script and other installation methods can be found `in the User Guide -`_. +`_. How to run the client --------------------- @@ -77,17 +83,17 @@ Understanding the client in more depth To understand what the client is doing in detail, it's important to understand the way it uses plugins. Please see the `explanation of -plugins `_ in +plugins `_ in the User Guide. Links ===== -Documentation: https://letsencrypt.readthedocs.org +Documentation: https://certbot.eff.org/docs Software project: https://github.com/certbot/certbot -Notes for developers: https://letsencrypt.readthedocs.org/en/latest/contributing.html +Notes for developers: https://certbot.eff.org/docs/contributing.html Main Website: https://letsencrypt.org/ diff --git a/certbot-apache/docs/conf.py b/certbot-apache/docs/conf.py index 2f996c7f4..d2fe15581 100644 --- a/certbot-apache/docs/conf.py +++ b/certbot-apache/docs/conf.py @@ -314,5 +314,5 @@ texinfo_documents = [ intersphinx_mapping = { 'python': ('https://docs.python.org/', None), 'acme': ('https://acme-python.readthedocs.org/en/latest/', None), - 'certbot': ('https://letsencrypt.readthedocs.org/en/latest/', None), + 'certbot': ('https://certbot.eff.org/docs/', None), } diff --git a/certbot-compatibility-test/docs/conf.py b/certbot-compatibility-test/docs/conf.py index 1ef69ab2d..f89f4b368 100644 --- a/certbot-compatibility-test/docs/conf.py +++ b/certbot-compatibility-test/docs/conf.py @@ -311,7 +311,7 @@ texinfo_documents = [ intersphinx_mapping = { 'python': ('https://docs.python.org/', None), 'acme': ('https://acme-python.readthedocs.org/en/latest/', None), - 'certbot': ('https://letsencrypt.readthedocs.org/en/latest/', None), + 'certbot': ('https://certbot.eff.org/docs/', None), 'certbot-apache': ( 'https://letsencrypt-apache.readthedocs.org/en/latest/', None), 'certbot-nginx': ( diff --git a/certbot-nginx/docs/conf.py b/certbot-nginx/docs/conf.py index fa00e6503..167abb4fb 100644 --- a/certbot-nginx/docs/conf.py +++ b/certbot-nginx/docs/conf.py @@ -307,5 +307,5 @@ texinfo_documents = [ intersphinx_mapping = { 'python': ('https://docs.python.org/', None), 'acme': ('https://acme-python.readthedocs.org/en/latest/', None), - 'certbot': ('https://letsencrypt.readthedocs.org/en/latest/', None), + 'certbot': ('https://certbot.eff.org/docs/', None), } diff --git a/letshelp-certbot/docs/conf.py b/letshelp-certbot/docs/conf.py index 905d70662..17d8b3ea9 100644 --- a/letshelp-certbot/docs/conf.py +++ b/letshelp-certbot/docs/conf.py @@ -307,5 +307,5 @@ texinfo_documents = [ intersphinx_mapping = { 'python': ('https://docs.python.org/', None), 'acme': ('https://acme-python.readthedocs.org/en/latest/', None), - 'certbot': ('https://letsencrypt.readthedocs.org/en/latest/', None), + 'certbot': ('https://certbot.eff.org/docs/', None), } From 4e19f9eae0c0cdf6def576bd98949fee12e23b7c Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 4 May 2016 17:28:16 -0700 Subject: [PATCH 048/186] venv is still named letsencrypt --- certbot/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/cli.py b/certbot/cli.py index e2c57595b..97b1a5399 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -37,7 +37,7 @@ helpful_parser = None # should only be used for purposes where inability to detect letsencrypt-auto # fails safely -fragment = os.path.join(".local", "share", "certbot") +fragment = os.path.join(".local", "share", "letsencrypt") cli_command = "letsencrypt-auto" if fragment in sys.argv[0] else "certbot" # Argparse's help formatting has a lot of unhelpful peculiarities, so we want From d38cf4a74ed565679c1cd9998c23b8af55be9bfe Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 4 May 2016 17:55:12 -0700 Subject: [PATCH 049/186] Build shim packages in next release --- tools/release.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/release.sh b/tools/release.sh index 06aefea44..e6169c5c8 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -45,7 +45,7 @@ export GPG_TTY=$(tty) PORT=${PORT:-1234} # subpackages to be released -SUBPKGS=${SUBPKGS:-"acme certbot-apache certbot-nginx letshelp-certbot"} +SUBPKGS=${SUBPKGS:-"acme certbot-apache certbot-nginx letshelp-certbot letsencrypt letsencrypt-apache letsencrypt-nginx letshelp-letsencrypt"} subpkgs_modules="$(echo $SUBPKGS | sed s/-/_/g)" # certbot_compatibility_test is not packaged because: # - it is not meant to be used by anyone else than Certbot devs @@ -162,12 +162,12 @@ done deactivate # pin pip hashes of the things we just built -for pkg in acme certbot certbot-apache ; do +for pkg in acme certbot certbot-apache letsencrypt letsencrypt-apache ; do echo $pkg==$version \\ pip hash dist."$version/$pkg"/*.{whl,gz} | grep "^--hash" | python2 -c 'from sys import stdin; input = stdin.read(); print " ", input.replace("\n--hash", " \\\n --hash"),' done > /tmp/hashes.$$ -if ! wc -l /tmp/hashes.$$ | grep -qE "^\s*9 " ; then +if ! wc -l /tmp/hashes.$$ | grep -qE "^\s*15 " ; then echo Unexpected pip hash output exit 1 fi From f3172bcfeed8666c9904bdabfcfbb28fd17c947a Mon Sep 17 00:00:00 2001 From: Jeremy Gillula Date: Thu, 5 May 2016 08:55:49 -0700 Subject: [PATCH 050/186] Changing some "will happen"s to "hopefully will happen"s --- README.rst | 4 ++-- docs/using.rst | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 050cde82b..cc4e53bda 100644 --- a/README.rst +++ b/README.rst @@ -128,8 +128,8 @@ System Requirements =================== The Let's Encrypt Client presently only runs on Unix-ish OSes that include -Python 2.6 or 2.7; Python 3.x support will be added after the Public Beta -launch. The client requires root access in order to write to +Python 2.6 or 2.7; Python 3.x support will hopefully be added after the Public +Beta launch. The client requires root access in order to write to ``/etc/letsencrypt``, ``/var/log/letsencrypt``, ``/var/lib/letsencrypt``; to bind to ports 80 and 443 (if you use the ``standalone`` plugin) and to read and modify webserver configurations (if you use the ``apache`` or ``nginx`` diff --git a/docs/using.rst b/docs/using.rst index 66c5907ae..8f56554ce 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -124,7 +124,7 @@ or ``--webroot-path /usr/share/nginx/html`` are two common webroot paths. If you're getting a certificate for many domains at once, the plugin needs to know where each domain's files are served from, which could -potentially be a separate directory for each domain. When requested a +potentially be a separate directory for each domain. When requesting a certificate for multiple domains, each domain will use the most recently specified ``--webroot-path``. So, for instance, @@ -184,11 +184,11 @@ be on a different computer. Nginx ----- -In the future, if you're running Nginx you can use this plugin to -automatically obtain and install your certificate. The Nginx plugin -is still experimental, however, and is not installed with -letsencrypt-auto_. If installed, you can select this plugin on the -command line by including ``--nginx``. +In the future, if you're running Nginx you will hopefully be able to use this +plugin to automatically obtain and install your certificate. The Nginx plugin is +still experimental, however, and is not installed with letsencrypt-auto_. If +installed, you can select this plugin on the command line by including +``--nginx``. Third-party plugins ------------------- @@ -446,7 +446,7 @@ If you run Debian Stretch or Debian Sid, you can install letsencrypt packages. If you don't want to use the Apache plugin, you can omit the ``python-letsencrypt-apache`` package. -Packages for Debian Jessie are coming in the next few weeks. +Packages for Debian Jessie will hopefully be coming in the next few weeks. **Fedora** From 127ba71c43770d233d1604ab8a2b32e574c12e8b Mon Sep 17 00:00:00 2001 From: Jeremy Gillula Date: Thu, 5 May 2016 11:17:47 -0700 Subject: [PATCH 051/186] Adding the fact that we actually have backports for Debian Jessie to the docs --- docs/using.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index 8f56554ce..60c074d75 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -446,7 +446,13 @@ If you run Debian Stretch or Debian Sid, you can install letsencrypt packages. If you don't want to use the Apache plugin, you can omit the ``python-letsencrypt-apache`` package. -Packages for Debian Jessie will hopefully be coming in the next few weeks. +Packages exist for Debian Jessie via backports. First you'll have to follow the +instructions at http://backports.debian.org/Instructions/ to enable the Jessie backports +repo, if you have not already done so. Then run: + +.. code-block:: shell + + sudo apt-get install certbot python-certbot-apache -t jessie-backports **Fedora** From fbbbb5b51634d348f82f893e1a02e98c0fcf3606 Mon Sep 17 00:00:00 2001 From: Jeremy Gillula Date: Thu, 5 May 2016 11:31:28 -0700 Subject: [PATCH 052/186] Turns out the public beta is over, but still no Python 3.0 support. We over-promised! --- README.rst | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index cc4e53bda..236bdf8f4 100644 --- a/README.rst +++ b/README.rst @@ -128,16 +128,15 @@ System Requirements =================== The Let's Encrypt Client presently only runs on Unix-ish OSes that include -Python 2.6 or 2.7; Python 3.x support will hopefully be added after the Public -Beta launch. The client requires root access in order to write to -``/etc/letsencrypt``, ``/var/log/letsencrypt``, ``/var/lib/letsencrypt``; to -bind to ports 80 and 443 (if you use the ``standalone`` plugin) and to read and -modify webserver configurations (if you use the ``apache`` or ``nginx`` -plugins). If none of these apply to you, it is theoretically possible to run -without root privileges, but for most users who want to avoid running an ACME -client as root, either `letsencrypt-nosudo -`_ or `simp_le -`_ are more appropriate choices. +Python 2.6 or 2.7; Python 3.x support will hopefully be added in the future. The +client requires root access in order to write to ``/etc/letsencrypt``, +``/var/log/letsencrypt``, ``/var/lib/letsencrypt``; to bind to ports 80 and 443 +(if you use the ``standalone`` plugin) and to read and modify webserver +configurations (if you use the ``apache`` or ``nginx`` plugins). If none of +these apply to you, it is theoretically possible to run without root privileges, +but for most users who want to avoid running an ACME client as root, either +`letsencrypt-nosudo `_ or +`simp_le `_ are more appropriate choices. The Apache plugin currently requires a Debian-based OS with augeas version 1.0; this includes Ubuntu 12.04+ and Debian 7+. From a65fca486cf65e88cdc8c8881c3e9f0c20db76ed Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 6 May 2016 11:57:12 -0700 Subject: [PATCH 053/186] Specify minimum parsedatetime version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 67cefdc48..4ee56576b 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ install_requires = [ 'ConfigArgParse>=0.9.3', 'configobj', 'cryptography>=0.7', # load_pem_x509_certificate - 'parsedatetime', + 'parsedatetime>=1.3', # Calendar.parseDT 'psutil>=2.1.0', # net_connections introduced in 2.1.0 'PyOpenSSL', 'pyrfc3339', From 495371a3b8d150f989d92820e3d30abbe26ac96a Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 6 May 2016 12:33:52 -0700 Subject: [PATCH 054/186] Use --force-reinstall to fix bad virtualenv package --- tools/_venv_common.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/_venv_common.sh b/tools/_venv_common.sh index a121af82d..dc6ca3dd2 100755 --- a/tools/_venv_common.sh +++ b/tools/_venv_common.sh @@ -18,7 +18,8 @@ virtualenv --no-site-packages $VENV_NAME $VENV_ARGS # Separately install setuptools and pip to make sure following # invocations use latest pip install -U setuptools -pip install -U pip +# --force-reinstall used to fix broken pip installation on some systems +pip install --force-reinstall -U pip pip install "$@" set +x From 785010fe5001a3c1472bf3ef47e99fb1da32f802 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 6 May 2016 12:45:51 -0700 Subject: [PATCH 055/186] Welcome to Certbot! --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 236bdf8f4..91a3cfcb5 100644 --- a/README.rst +++ b/README.rst @@ -3,9 +3,9 @@ Disclaimer ========== -The Let's Encrypt Client is **BETA SOFTWARE**. It contains plenty of bugs and -rough edges, and should be tested thoroughly in staging environments before use -on production systems. +Certbot (previously, the Let's Encrypt client) is **BETA SOFTWARE**. It +contains plenty of bugs and rough edges, and should be tested thoroughly in +staging environments before use on production systems. For more information regarding the status of the project, please see https://letsencrypt.org. Be sure to checkout the From 7167a9e108c62a865a0a6d1df2084e404d3cd2ef Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 6 May 2016 16:41:23 -0700 Subject: [PATCH 056/186] fixes #2927 --- certbot/plugins/standalone.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/certbot/plugins/standalone.py b/certbot/plugins/standalone.py index a3bb1d8f0..16e9dc11b 100644 --- a/certbot/plugins/standalone.py +++ b/certbot/plugins/standalone.py @@ -120,6 +120,13 @@ def supported_challenges_validator(data): """ challs = data.split(",") + + # tls-sni-01 was dvsni during private beta + if "dvsni" in challs: + challs = [challenges.TLSSNI01.typ if chall == "dvsni" else chall + for chall in challs] + data = ",".join(challs) + unrecognized = [name for name in challs if name not in challenges.Challenge.TYPES] if unrecognized: From 56d7a97e6aeec9b91d3517f0afa4f0da815983c9 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 6 May 2016 16:44:31 -0700 Subject: [PATCH 057/186] Test dvsni with standalone-supported-challenges --- certbot/plugins/standalone_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certbot/plugins/standalone_test.py b/certbot/plugins/standalone_test.py index 9f5b14591..eb6631732 100644 --- a/certbot/plugins/standalone_test.py +++ b/certbot/plugins/standalone_test.py @@ -85,6 +85,11 @@ class SupportedChallengesValidatorTest(unittest.TestCase): def test_not_subset(self): self.assertRaises(argparse.ArgumentTypeError, self._call, "dns") + def test_dvsni(self): + self.assertEqual("tls-sni-01", self._call("dvsni")) + self.assertEqual("http-01,tls-sni-01", self._call("http-01,dvsni")) + self.assertEqual("tls-sni-01,http-01", self._call("dvsni,http-01")) + class AuthenticatorTest(unittest.TestCase): """Tests for certbot.plugins.standalone.Authenticator.""" From 30ae348a8c462a770332046f31c13a8f2cb4b183 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 6 May 2016 16:53:33 -0700 Subject: [PATCH 058/186] Add logger message --- certbot/plugins/standalone.py | 1 + 1 file changed, 1 insertion(+) diff --git a/certbot/plugins/standalone.py b/certbot/plugins/standalone.py index 16e9dc11b..8e1cb72a4 100644 --- a/certbot/plugins/standalone.py +++ b/certbot/plugins/standalone.py @@ -123,6 +123,7 @@ def supported_challenges_validator(data): # tls-sni-01 was dvsni during private beta if "dvsni" in challs: + logger.info("Updating legacy standalone_supported_challenges value") challs = [challenges.TLSSNI01.typ if chall == "dvsni" else chall for chall in challs] data = ",".join(challs) From 4627971dc68f1cf834eb1e836b8b4ad40e39fb0f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 6 May 2016 17:30:18 -0700 Subject: [PATCH 059/186] s/--letsencrypt/--certbot --- tests/travis-integration.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/travis-integration.sh b/tests/travis-integration.sh index 1b51f0980..c22c346b1 100755 --- a/tests/travis-integration.sh +++ b/tests/travis-integration.sh @@ -12,8 +12,8 @@ cd $GOPATH/src/github.com/letsencrypt/boulder/ # boulder's integration-test.py has code that knows to start and wait for the # boulder processes to start reliably and then will run the certbot -# boulder-interation.sh on its own. The --letsencrypt flag says to run only the +# boulder-interation.sh on its own. The --certbot flag says to run only the # certbot tests (instead of any other client tests it might run). We're # going to want to define a more robust interaction point between the boulder # and certbot tests, but that will be better built off of this. -python test/integration-test.py --letsencrypt +python test/integration-test.py --certbot From 5c0eabcd76fc73e0fd6240cb62466336ad555593 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 6 May 2016 17:42:25 -0700 Subject: [PATCH 060/186] Rename LETSENCRYPT_PATH to CERTBOT_PATH --- tests/travis-integration.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/travis-integration.sh b/tests/travis-integration.sh index c22c346b1..159a2ef80 100755 --- a/tests/travis-integration.sh +++ b/tests/travis-integration.sh @@ -6,7 +6,7 @@ set -o errexit source .tox/$TOXENV/bin/activate -export LETSENCRYPT_PATH=`pwd` +export CERTBOT_PATH=`pwd` cd $GOPATH/src/github.com/letsencrypt/boulder/ From 9059a4966408fe8a495ea79539a8619728597ddc Mon Sep 17 00:00:00 2001 From: Dominic Cleal Date: Sat, 7 May 2016 18:49:18 +0100 Subject: [PATCH 061/186] Merge Augeas fix for empty section continuations From https://github.com/hercules-team/augeas/commit/568be1bc392bab6089c027de990b857ce962cc26 Fixes #2731 --- .../certbot_apache/augeas_lens/httpd.aug | 4 +- .../section-empty-continuations-2731.conf | 247 ++++++++++++++++++ 2 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 certbot-apache/certbot_apache/tests/apache-conf-files/passing/section-empty-continuations-2731.conf diff --git a/certbot-apache/certbot_apache/augeas_lens/httpd.aug b/certbot-apache/certbot_apache/augeas_lens/httpd.aug index 697d5de89..07974b364 100644 --- a/certbot-apache/certbot_apache/augeas_lens/httpd.aug +++ b/certbot-apache/certbot_apache/augeas_lens/httpd.aug @@ -45,8 +45,8 @@ autoload xfm let dels (s:string) = del s s (* deal with continuation lines *) -let sep_spc = del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)/ " " -let sep_osp = del /([ \t]*|[ \t]*\\\\\r?\n[ \t]*)/ "" +let sep_spc = del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)+/ " " +let sep_osp = del /([ \t]*|[ \t]*\\\\\r?\n[ \t]*)*/ "" let sep_eq = del /[ \t]*=[ \t]*/ "=" let nmtoken = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/ diff --git a/certbot-apache/certbot_apache/tests/apache-conf-files/passing/section-empty-continuations-2731.conf b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/section-empty-continuations-2731.conf new file mode 100644 index 000000000..3f2f96965 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/section-empty-continuations-2731.conf @@ -0,0 +1,247 @@ +#ATTENTION! +# +#DO NOT MODIFY THIS FILE BECAUSE IT WAS GENERATED AUTOMATICALLY, +#SO ALL YOUR CHANGES WILL BE LOST THE NEXT TIME THE FILE IS GENERATED. + +NameVirtualHost 192.168.100.218:80 +NameVirtualHost 10.128.178.192:80 + +NameVirtualHost 192.168.100.218:443 +NameVirtualHost 10.128.178.192:443 + + +ServerName "254020-web1.example.com" +ServerAdmin "name@example.com" + +DocumentRoot "/tmp" + + + LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" plesklog + + + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" plesklog + + + TraceEnable off + +ServerTokens ProductOnly + + + AllowOverride "All" + Options SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + +php_admin_flag engine off + + + +php_admin_flag engine off + + + + + + AllowOverride All + Options SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + php_admin_flag engine off + + + php_admin_flag engine off + + + + + Header add X-Powered-By PleskLin + + + + JkWorkersFile "/etc/httpd/conf/workers.properties" + JkLogFile /var/log/httpd/mod_jk.log + JkLogLevel info + + +#Include "/etc/httpd/conf/plesk.conf.d/ip_default/*.conf" + + + + ServerName "default" + UseCanonicalName Off + DocumentRoot "/tmp" + ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin" + + + + SSLEngine off + + + + AllowOverride None + Options None + Order allow,deny + Allow from all + + + + + +php_admin_flag engine on + + + +php_admin_flag engine on + + + + + + + + + + ServerName "default-192_168_100_218" + UseCanonicalName Off + DocumentRoot "/tmp" + ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin" + + + SSLEngine on + SSLVerifyClient none + #SSLCertificateFile "/usr/local/psa/var/certificates/cert-9MgutN" + + #SSLCACertificateFile "/usr/local/psa/var/certificates/cert-s6Wx3P" + + + AllowOverride None + Options None + Order allow,deny + Allow from all + + + + + +php_admin_flag engine on + + + +php_admin_flag engine on + + + + + + + ServerName "default-10_128_178_192" + UseCanonicalName Off + DocumentRoot "/tmp" + ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin" + + + SSLEngine on + SSLVerifyClient none + #SSLCertificateFile "/usr/local/psa/var/certificates/certxfb6025" + + + + AllowOverride None + Options None + Order allow,deny + Allow from all + + + + + +php_admin_flag engine on + + + +php_admin_flag engine on + + + + + + + + + + + DocumentRoot "/tmp" + ServerName lists + ServerAlias lists.* + UseCanonicalName Off + + ScriptAlias "/mailman/" "/usr/lib/mailman/cgi-bin/" + + Alias "/icons/" "/var/www/icons/" + Alias "/pipermail/" "/var/lib/mailman/archives/public/" + + + SSLEngine off + + + + + Options FollowSymLinks + Order allow,deny + Allow from all + + + + + + + DocumentRoot "/tmp" + ServerName lists + ServerAlias lists.* + UseCanonicalName Off + + ScriptAlias "/mailman/" "/usr/lib/mailman/cgi-bin/" + + Alias "/icons/" "/var/www/icons/" + Alias "/pipermail/" "/var/lib/mailman/archives/public/" + + SSLEngine on + SSLVerifyClient none + #SSLCertificateFile "/usr/local/psa/var/certificates/certxfb6025" + + + + Options FollowSymLinks + Order allow,deny + Allow from all + + + + + + + RPAFproxy_ips 192.168.100.218 10.128.178.192 + + + RPAFproxy_ips 192.168.100.218 10.128.178.192 + From 3d90fb809761deba0ffa18c615c0c5ac00887ba1 Mon Sep 17 00:00:00 2001 From: Dominic Cleal Date: Sat, 7 May 2016 21:55:31 +0100 Subject: [PATCH 062/186] Merge Augeas fix for escaped spaces in arguments From https://github.com/hercules-team/augeas/commit/f741b8b4f23dd9372dcdea18383ef9138f9c161e Fixes #2735 --- certbot-apache/certbot_apache/augeas_lens/httpd.aug | 4 ++-- .../passing/escaped-space-arguments-2735.conf | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 certbot-apache/certbot_apache/tests/apache-conf-files/passing/escaped-space-arguments-2735.conf diff --git a/certbot-apache/certbot_apache/augeas_lens/httpd.aug b/certbot-apache/certbot_apache/augeas_lens/httpd.aug index 697d5de89..f27798efe 100644 --- a/certbot-apache/certbot_apache/augeas_lens/httpd.aug +++ b/certbot-apache/certbot_apache/augeas_lens/httpd.aug @@ -58,8 +58,8 @@ let empty = Util.empty_dos let indent = Util.indent (* borrowed from shellvars.aug *) -let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'/ -let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'/ +let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'|\\\\ / +let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'|\\\\ / let char_arg_wl = /([^\\ '"},\t\r\n]|[^ '"},\t\r\n]+[^\\ '"},\t\r\n])/ let cdot = /\\\\./ diff --git a/certbot-apache/certbot_apache/tests/apache-conf-files/passing/escaped-space-arguments-2735.conf b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/escaped-space-arguments-2735.conf new file mode 100644 index 000000000..1ea53dfab --- /dev/null +++ b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/escaped-space-arguments-2735.conf @@ -0,0 +1,2 @@ +RewriteCond %{HTTP:Content-Disposition} \.php [NC] +RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/ [NC] From 653c7b6327508a3dba2d8a2ef7c5c4463647d7fe Mon Sep 17 00:00:00 2001 From: Michal Moravec Date: Sun, 8 May 2016 16:16:54 +0200 Subject: [PATCH 063/186] Ensure /usr/local/lib/ exists before creating libaugeas.dylib symlink in mac.sh bootstraper --- letsencrypt-auto-source/pieces/bootstrappers/mac.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/letsencrypt-auto-source/pieces/bootstrappers/mac.sh b/letsencrypt-auto-source/pieces/bootstrappers/mac.sh index 79e58eb3f..e41db04b1 100755 --- a/letsencrypt-auto-source/pieces/bootstrappers/mac.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/mac.sh @@ -26,7 +26,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 From 3c413c28b8e6ce0208289ccd12fdc8252c1ce805 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 9 May 2016 12:31:39 -0700 Subject: [PATCH 064/186] fix grammar --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 1bfb8fdab..a0bd4059b 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ Disclaimer ========== -The Certbot is **BETA SOFTWARE**. It contains plenty of bugs and +Certbot is **BETA SOFTWARE**. It contains plenty of bugs and rough edges, and should be tested thoroughly in staging environments before use on production systems. From 555513940c8e541923cb2e28a56d62b684559dd3 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 9 May 2016 14:57:01 -0700 Subject: [PATCH 065/186] Explain *-hook and -q in renewal documentation --- docs/using.rst | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 60c074d75..7d7b4fbfd 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -215,12 +215,25 @@ expire in less than 30 days. The same plugin and options that were used at the time the certificate was originally issued will be used for the renewal attempt, unless you specify other plugins or options. +You can also specify hooks to be run before or after a certificate is +renewed. For example, if you want to use the standalone_ plugin to renew +your certificates, you may want to use a command like + +``letsencrypt renew --standalone --pre-hook "service nginx stop" --post-hook "service nginx start"`` + +This will stop Nginx so standalone can bind to the necessary ports and +then restart Nginx after the plugin is finished. The hooks will only be +run if a certificate is due for renewal, so you can run this command +frequently without unnecessarily stopping your webserver. More +information about renewal hooks can be found by running +``letsencrypt --help renew``. + If you're sure that this command executes successfully without human intervention, you can add the command to ``crontab`` (since certificates are only renewed when they're determined to be near expiry, the command -can run on a regular basis, like every week or every day); note that -the current version provides detailed output describing either renewal -success or failure. +can run on a regular basis, like every week or every day). You may also +want to use the ``-q`` or ``--quiet`` quiet flag to silence all output +except errors. The ``--force-renew`` flag may be helpful for automating renewal; it causes the expiration time of the certificate(s) to be ignored when From 9ddabc3e9a2fcc89dd7d2f892e6a726cdb070325 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 9 May 2016 15:17:14 -0700 Subject: [PATCH 066/186] fix docs conf --- docs/conf.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index fb2bdea73..b2b31ac5d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -64,8 +64,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'Let\'s Encrypt' -copyright = u'2014-2015, Let\'s Encrypt Project' +project = u'Certbot' +copyright = u'2014-2016, Certbot Project' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -225,7 +225,7 @@ html_static_path = ['_static'] #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'LetsEncryptdoc' +htmlhelp_basename = 'Certbotdoc' # -- Options for LaTeX output --------------------------------------------- @@ -247,8 +247,8 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'LetsEncrypt.tex', u'Let\'s Encrypt Documentation', - u'Let\'s Encrypt Project', 'manual'), + ('index', 'Certbot.tex', u'Certbot Documentation', + u'Certbot Project', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -277,7 +277,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'certbot', u'Let\'s Encrypt Documentation', + ('index', 'certbot', u'Certbot Documentation', [project], 7), ('man/certbot', 'certbot', u'certbot script documentation', [project], 1), @@ -293,8 +293,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'LetsEncrypt', u'Let\'s Encrypt Documentation', - u'Let\'s Encrypt Project', 'LetsEncrypt', 'One line description of project.', + ('index', 'Certbot', u'Certbot Documentation', + u'Certbot Project', 'Certbot', 'One line description of project.', 'Miscellaneous'), ] From bbcde8cec1096ef44825862a66546d565d7419d6 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Mon, 9 May 2016 15:27:17 -0700 Subject: [PATCH 067/186] seth changes --- docs/ciphers.rst | 4 ++-- docs/using.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ciphers.rst b/docs/ciphers.rst index 5a046e757..8996dd9ef 100644 --- a/docs/ciphers.rst +++ b/docs/ciphers.rst @@ -131,7 +131,7 @@ The Let's Encrypt project may deviate from the Mozilla recommendations in the future if good cause is shown and we believe our users' priorities would be well-served by doing so. In general, please address relevant proposals for changing priorities to the Mozilla security -team first, before asking the Let's Encrypt project or EFF to change +team first, before asking the Certbot developers to change Certbot's priorities. The Mozilla security team is likely to have more resources and expertise to bring to bear on evaluating reasons why its recommendations should be updated. @@ -187,7 +187,7 @@ to enable updating ciphers with each new Certbot release, or certbot --update-ciphers off to disable automatic configuration updates. These features have not yet -been implemented and this syntax may change then they are implemented. +been implemented and this syntax may change when they are implemented. TODO diff --git a/docs/using.rst b/docs/using.rst index 10d4aa544..f215b335b 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -539,7 +539,7 @@ Comparison of different methods Unless you have a very specific requirements, we kindly suggest that you use the certbot-auto_ method. It's the fastest, the most thoroughly tested and the most reliable way of getting our software and the free -SSL certificates! +TLS/SSL certificates! Beyond the methods discussed here, other methods may be possible, such as installing Certbot directly with pip from PyPI or downloading a ZIP From 6fa7eb576bc5042b8455e1da85c60ee858253dac Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 9 May 2016 18:11:36 -0700 Subject: [PATCH 068/186] Use -n when using certonly --- docs/using.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 7d7b4fbfd..748fae370 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -254,9 +254,11 @@ renewals of that certificate. An alternative form that provides for more fine-grained control over the renewal process (while renewing specified certificates one at a time), is ``letsencrypt certonly`` with the complete set of subject domains of -a specific certificate specified via `-d` flags, like +a specific certificate specified via `-d` flags. You may also want to +include the ``-n`` or ``--noninteractive`` flag to prevent blocking on +user input (which is useful when running the command from cron). -``letsencrypt certonly -d example.com -d www.example.com`` +``letsencrypt certonly -n -d example.com -d www.example.com`` (All of the domains covered by the certificate must be specified in this case in order to renew and replace the old certificate rather From 3ce47282ea37f2c9b87868ae731c0dcacbef0e12 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 9 May 2016 18:14:02 -0700 Subject: [PATCH 069/186] Make --quiet suggestion stronger --- docs/using.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 748fae370..e7e0e9474 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -231,9 +231,9 @@ information about renewal hooks can be found by running If you're sure that this command executes successfully without human intervention, you can add the command to ``crontab`` (since certificates are only renewed when they're determined to be near expiry, the command -can run on a regular basis, like every week or every day). You may also -want to use the ``-q`` or ``--quiet`` quiet flag to silence all output -except errors. +can run on a regular basis, like every week or every day). In that case, +you are likely to want to use the ``-q`` or ``--quiet`` quiet flag to +silence all output except errors. The ``--force-renew`` flag may be helpful for automating renewal; it causes the expiration time of the certificate(s) to be ignored when From 7f8fadee37e6c2de78786338d9a30c8a21e9995f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 9 May 2016 18:33:47 -0700 Subject: [PATCH 070/186] Revert "Make certbot accept --yes flag" This reverts commit a9ecd146a9797eb068827bf6c357fde15f3a9a03. --- certbot/cli.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/certbot/cli.py b/certbot/cli.py index 40af5dccb..e2c57595b 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -649,9 +649,6 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): "automation", "--no-self-upgrade", action="store_true", help="(letsencrypt-auto only) prevent the letsencrypt-auto script from" " upgrading itself to newer released versions") - helpful.add( - "automation", "--yes", action="store_true", - help="(letsencrypt-auto only) assume yes is the answer to all prompts") helpful.add( "automation", "-q", "--quiet", dest="quiet", action="store_true", help="Silence all output except errors. Useful for automation via cron." From f38d59d6756f76be4f51b86e1365556da569216f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 9 May 2016 19:08:25 -0700 Subject: [PATCH 071/186] Use --non-interactive instead of --yes and use getopt for parsing short opts --- letsencrypt-auto-source/letsencrypt-auto | 31 +++++++++++-------- .../letsencrypt-auto.template | 31 +++++++++++-------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index adeb94e3e..538226d2f 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -29,15 +29,26 @@ all arguments you have provided. Help for certbot itself cannot be provided until it is installed. - --debug attempt installation on experimental platforms - --help print this help - --no-self-upgrade do not download updates for certbot or certbot-auto - --os-packages-only install OS dependencies and exit - -v, --verbose provide more output - --yes assume yes is the answer to all prompts + --debug attempt experimental installation + -h, --help print this help + -n, --non-interactive, --noninteractive run without asking for user input + --no-self-upgrade do not download updates + --os-packages-only install OS dependencies and exit + -v, --verbose provide more output 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) @@ -50,16 +61,10 @@ for arg in "$@" ; do NO_SELF_UPGRADE=1;; --help) HELP=1;; - --yes) + --noninteractive|--non-interactive) ASSUME_YES=1;; --verbose) VERBOSE=1;; - [!-]*|-*[!v]*|-) - # Anything that isn't -v, -vv, etc.: that is, anything that does not - # start with a -, contains anything that's not a v, or is just "-" - ;; - *) # -v+ remains. - VERBOSE=1;; esac done diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index fe4baeafd..af4ed62d3 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -29,15 +29,26 @@ all arguments you have provided. Help for certbot itself cannot be provided until it is installed. - --debug attempt installation on experimental platforms - --help print this help - --no-self-upgrade do not download updates for certbot or certbot-auto - --os-packages-only install OS dependencies and exit - -v, --verbose provide more output - --yes assume yes is the answer to all prompts + --debug attempt experimental installation + -h, --help print this help + -n, --non-interactive, --noninteractive run without asking for user input + --no-self-upgrade do not download updates + --os-packages-only install OS dependencies and exit + -v, --verbose provide more output 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) @@ -50,16 +61,10 @@ for arg in "$@" ; do NO_SELF_UPGRADE=1;; --help) HELP=1;; - --yes) + --noninteractive|--non-interactive) ASSUME_YES=1;; --verbose) VERBOSE=1;; - [!-]*|-*[!v]*|-) - # Anything that isn't -v, -vv, etc.: that is, anything that does not - # start with a -, contains anything that's not a v, or is just "-" - ;; - *) # -v+ remains. - VERBOSE=1;; esac done From 8394e5eb64e4cd4b18b6432340bc335349a8bec6 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 9 May 2016 19:07:11 -0700 Subject: [PATCH 072/186] Draft of new installation instructions --- README.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 91a3cfcb5..3ba541f77 100644 --- a/README.rst +++ b/README.rst @@ -30,9 +30,15 @@ systems have packages yet, we provide a temporary solution via the ``letsencrypt-auto`` wrapper script, which obtains some dependencies from your OS and puts others in a python virtual environment:: - user@webserver:~$ git clone https://github.com/letsencrypt/letsencrypt - user@webserver:~$ cd letsencrypt - user@webserver:~/letsencrypt$ ./letsencrypt-auto --help + user@webserver:~$ wget https://dl.eff.org/certbot-auto + user@webserver:~$ chmod a+x ./certbot-auto + user@webserver:~$ ./certbot-auto --help + +.. hint:: For stronger security, you can use these steps for extra verification before running the script: + + user@webserver:~$ wget https://dl.eff.org/certbot-auto.sig + user@webserver:~$ gpg2 --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2 + user@webserver:~$ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.sig certbot-auto Or for full command line help, type:: From 675f2e5413f5e13b8062351ca94f2bfd610498fe Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 9 May 2016 19:24:47 -0700 Subject: [PATCH 073/186] Put the signature instructions in a hint box --- README.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 3ba541f77..040aa6bdf 100644 --- a/README.rst +++ b/README.rst @@ -34,13 +34,14 @@ from your OS and puts others in a python virtual environment:: user@webserver:~$ chmod a+x ./certbot-auto user@webserver:~$ ./certbot-auto --help -.. hint:: For stronger security, you can use these steps for extra verification before running the script: +.. hint:: If you'd like stronger security when downloading the ``certbot-auto`` script, + you can use these steps for extra verification before running it:: - user@webserver:~$ wget https://dl.eff.org/certbot-auto.sig - user@webserver:~$ gpg2 --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2 - user@webserver:~$ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.sig certbot-auto + user@server:~$ wget https://dl.eff.org/certbot-auto.sig + user@server:~$ gpg2 --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2 + user@server:~$ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.sig certbot-auto -Or for full command line help, type:: +And for full command line help, you can type:: ./letsencrypt-auto --help all From 37efe306754bf8a1f111deb0933a2597ec0a4024 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 9 May 2016 19:31:29 -0700 Subject: [PATCH 074/186] Better explanation --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 040aa6bdf..840cfff0a 100644 --- a/README.rst +++ b/README.rst @@ -34,8 +34,8 @@ from your OS and puts others in a python virtual environment:: user@webserver:~$ chmod a+x ./certbot-auto user@webserver:~$ ./certbot-auto --help -.. hint:: If you'd like stronger security when downloading the ``certbot-auto`` script, - you can use these steps for extra verification before running it:: +.. hint:: The certbot-auto download is protected by HTTPS, which is pretty good, but if you'd like to + double check the integrity of the ``certbot-auto`` script, you can use these steps for verification before running it:: user@server:~$ wget https://dl.eff.org/certbot-auto.sig user@server:~$ gpg2 --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2 From 7a848d2b048b07c1b2fbd5f81b87c2a6cda46359 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 9 May 2016 19:51:08 -0700 Subject: [PATCH 075/186] Remove unneeded info about backports --- letsencrypt-auto-source/letsencrypt-auto | 3 --- letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh | 3 --- 2 files changed, 6 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 538226d2f..8dbdf5f9c 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -192,9 +192,6 @@ BootstrapDebCommon() { if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then # This can theoretically error if sources.list.d is empty, but in that case we don't care. if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then - if echo $BACKPORT_NAME | grep -q wheezy ; then - echo 'Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports"' - fi if [ "$ASSUME_YES" = 1 ]; then /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." sleep 1s diff --git a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh index e91f52261..bfbcfa31d 100644 --- a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh @@ -46,9 +46,6 @@ BootstrapDebCommon() { if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then # This can theoretically error if sources.list.d is empty, but in that case we don't care. if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then - if echo $BACKPORT_NAME | grep -q wheezy ; then - echo 'Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports"' - fi if [ "$ASSUME_YES" = 1 ]; then /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." sleep 1s From 86cb5b68e3b2f3148a7d4134ffd786a70c34ee58 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 10 May 2016 10:14:03 -0700 Subject: [PATCH 076/186] cli_command should sometimes be certbot-auto --- certbot/cli.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certbot/cli.py b/certbot/cli.py index 7ed8a0d3a..90e86a751 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -38,6 +38,11 @@ helpful_parser = None # fails safely LEAUTO = "letsencrypt-auto" +if "CERTBOT_AUTO" in os.environ: + # if we're here, this is probably going to be certbot-auto, unless the + # user saved the script under a different name + LEAUTO = os.path.basename(os.environ["CERTBOT_AUTO"]) + fragment = os.path.join(".local", "share", "letsencrypt") cli_command = LEAUTO if fragment in sys.argv[0] else "certbot" From ed23f2e27fb42aac0b37cc9df74e6853a912e75a Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 10 May 2016 10:21:15 -0700 Subject: [PATCH 077/186] CERTBOT_AUTO env was broken (especially if containing spaces) --- letsencrypt-auto-source/letsencrypt-auto | 14 +++++++++++--- letsencrypt-auto-source/letsencrypt-auto.template | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1f2dfcf85..72adfccb1 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -55,7 +55,7 @@ export CERTBOT_AUTO="$0" if test "`id -u`" -ne "0" ; then if command -v sudo 1>/dev/null 2>&1; then SUDO=sudo - SUDO_ENV="CERTBOT_AUTO=\"$0\"" + SUDO_ENV="CERTBOT_AUTO=$0" else echo \"sudo\" is not available, will use \"su\" for installation steps... # Because the parameters in `su -c` has to be a string, @@ -827,8 +827,16 @@ UNLIKELY_EOF echo "Installation succeeded." fi echo "Requesting root privileges to run certbot..." - echo " " $SUDO $SUDO_ENV "$VENV_BIN/letsencrypt" "$@" - $SUDO $SUDO_ENV "$VENV_BIN/letsencrypt" "$@" + 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 + else # Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke. # diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 580ee7c07..4e32d8b4f 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -55,7 +55,7 @@ export CERTBOT_AUTO="$0" if test "`id -u`" -ne "0" ; then if command -v sudo 1>/dev/null 2>&1; then SUDO=sudo - SUDO_ENV="CERTBOT_AUTO=\"$0\"" + SUDO_ENV="CERTBOT_AUTO=$0" else echo \"sudo\" is not available, will use \"su\" for installation steps... # Because the parameters in `su -c` has to be a string, @@ -223,8 +223,16 @@ UNLIKELY_EOF echo "Installation succeeded." fi echo "Requesting root privileges to run certbot..." - echo " " $SUDO $SUDO_ENV "$VENV_BIN/letsencrypt" "$@" - $SUDO $SUDO_ENV "$VENV_BIN/letsencrypt" "$@" + 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 + else # Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke. # From 62cf9c93a8dbaad2bb0523828c5072ed8288ca32 Mon Sep 17 00:00:00 2001 From: "Gregory L. Dietsche" Date: Tue, 10 May 2016 01:40:44 +0000 Subject: [PATCH 078/186] /etc/issue does not exist on all systems Signed-off-by: Gregory L. Dietsche --- letsencrypt-auto-source/letsencrypt-auto.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 2c8e1ec4c..c451340bc 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -154,7 +154,7 @@ 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 else echo "Sorry, I don't know how to bootstrap Certbot on your operating system!" From 029a818370a013a0b9ec623d5065f5eac86249e7 Mon Sep 17 00:00:00 2001 From: "Gregory L. Dietsche" Date: Tue, 10 May 2016 01:44:51 +0000 Subject: [PATCH 079/186] Experimental Joyent SmartOS Support Testing using image: 088b97b0-e1a1-11e5-b895-9baa2086eb33 base-64-lts 15.4.1 Signed-off-by: Gregory L. Dietsche --- letsencrypt-auto-source/letsencrypt-auto.template | 3 +++ letsencrypt-auto-source/pieces/bootstrappers/smartos.sh | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 letsencrypt-auto-source/pieces/bootstrappers/smartos.sh diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index c451340bc..1a66753f1 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -122,6 +122,7 @@ DeterminePythonVersion() { {{ bootstrappers/gentoo_common.sh }} {{ bootstrappers/free_bsd.sh }} {{ bootstrappers/mac.sh }} +{{ bootstrappers/smartos.sh }} # Install required OS packages: Bootstrap() { @@ -156,6 +157,8 @@ Bootstrap() { ExperimentalBootstrap "Mac OS X" BootstrapMac 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 diff --git a/letsencrypt-auto-source/pieces/bootstrappers/smartos.sh b/letsencrypt-auto-source/pieces/bootstrappers/smartos.sh new file mode 100644 index 000000000..e721c1c0b --- /dev/null +++ b/letsencrypt-auto-source/pieces/bootstrappers/smartos.sh @@ -0,0 +1,4 @@ +BootstrapSmartOS() { + pkgin update + pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv' +} From 762e9e9db0b2b2eb6711b19b016da740946a63a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Wed, 11 May 2016 06:16:13 +0200 Subject: [PATCH 080/186] Fix mime.types parsing for nginx Added characters to key parsing rule which appear in the mime type in mime.types. --- certbot-nginx/certbot_nginx/nginxparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-nginx/certbot_nginx/nginxparser.py b/certbot-nginx/certbot_nginx/nginxparser.py index cef0756d7..8ab7adb0a 100644 --- a/certbot-nginx/certbot_nginx/nginxparser.py +++ b/certbot-nginx/certbot_nginx/nginxparser.py @@ -17,7 +17,7 @@ class RawNginxParser(object): right_bracket = Literal("}").suppress() semicolon = Literal(";").suppress() space = White().suppress() - key = Word(alphanums + "_/") + key = Word(alphanums + "_/+-.") # Matches anything that is not a special character AND any chars in single # or double quotes value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+") From 639efaeb7ba590ba056c60fdcccb7c0a5b77e69a Mon Sep 17 00:00:00 2001 From: chrismarget Date: Wed, 11 May 2016 12:01:53 -0400 Subject: [PATCH 081/186] Randomize serial numbers of DVSNI challenge certificates. --- acme/acme/crypto_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme/crypto_util.py b/acme/acme/crypto_util.py index 73f7f8f62..e121b1ac3 100644 --- a/acme/acme/crypto_util.py +++ b/acme/acme/crypto_util.py @@ -203,7 +203,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(OpenSSL.rand.bytes(16).encode("hex"), 16)) cert.set_version(2) extensions = [ From 22f6b77e680af0144b260a85ff51c53a34689179 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 10 May 2016 18:51:16 -0700 Subject: [PATCH 082/186] Move deprecation warning after logging setup --- certbot/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/main.py b/certbot/main.py index 939a5e0e4..0405d6eb5 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -649,7 +649,6 @@ def main(cli_args=sys.argv[1:]): args = cli.prepare_and_parse_args(plugins, cli_args) config = configuration.NamespaceConfig(args) zope.component.provideUtility(config) - cli.possible_deprecation_warning(config) # Setup logging ASAP, otherwise "No handlers could be found for # logger ..." TODO: this should be done before plugins discovery @@ -662,6 +661,7 @@ def main(cli_args=sys.argv[1:]): le_util.make_or_verify_dir( config.logs_dir, 0o700, os.geteuid(), "--strict-permissions" in cli_args) setup_logging(config, _cli_log_handler, logfile='letsencrypt.log') + cli.possible_deprecation_warning(config) logger.debug("certbot version: %s", certbot.__version__) # do not log `config`, as it contains sensitive data (e.g. revoke --key)! From a7ef4940b6fabde1730c2a4cf7aef2d689895dff Mon Sep 17 00:00:00 2001 From: chrismarget Date: Wed, 11 May 2016 13:57:18 -0400 Subject: [PATCH 083/186] Randomize DVSNI challenge certificate serial number, now for python 3.3. --- acme/acme/crypto_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme/crypto_util.py b/acme/acme/crypto_util.py index e121b1ac3..6cb5ad6fc 100644 --- a/acme/acme/crypto_util.py +++ b/acme/acme/crypto_util.py @@ -203,7 +203,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(int(OpenSSL.rand.bytes(16).encode("hex"), 16)) + cert.set_serial_number(int.from_bytes(OpenSSL.rand.bytes(16),'big')) cert.set_version(2) extensions = [ From 6f9e28fccad96c19b3fd58560d5c6ddba8201d04 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Wed, 11 May 2016 09:49:23 -0700 Subject: [PATCH 084/186] Allow unrecognized fields in directory. --- acme/acme/messages.py | 11 +---------- acme/acme/messages_test.py | 9 ++++----- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/acme/acme/messages.py b/acme/acme/messages.py index 24a3b580c..4a9bd9f47 100644 --- a/acme/acme/messages.py +++ b/acme/acme/messages.py @@ -143,12 +143,6 @@ class Directory(jose.JSONDeSerializable): def __init__(self, jobj): canon_jobj = util.map_keys(jobj, self._canon_key) - if not set(canon_jobj).issubset( - set(self._REGISTERED_TYPES).union(['meta'])): - # TODO: acme-spec is not clear about this: 'It is a JSON - # dictionary, whose keys are the "resource" values listed - # in {{https-requests}}' - raise ValueError('Wrong directory fields') # TODO: check that everything is an absolute URL; acme-spec is # not clear on that self._jobj = canon_jobj @@ -171,10 +165,7 @@ class Directory(jose.JSONDeSerializable): @classmethod def from_json(cls, jobj): jobj['meta'] = cls.Meta.from_json(jobj.pop('meta', {})) - try: - return cls(jobj) - except ValueError as error: - raise jose.DeserializationError(str(error)) + return cls(jobj) class Resource(jose.JSONObjectWithFields): diff --git a/acme/acme/messages_test.py b/acme/acme/messages_test.py index b2b7febdc..b39b9ff55 100644 --- a/acme/acme/messages_test.py +++ b/acme/acme/messages_test.py @@ -97,9 +97,9 @@ class DirectoryTest(unittest.TestCase): ), }) - def test_init_wrong_key_value_error(self): + def test_init_wrong_key_value_success(self): # pylint: disable=no-self-use from acme.messages import Directory - self.assertRaises(ValueError, Directory, {'foo': 'bar'}) + Directory({'foo': 'bar'}) def test_getitem(self): self.assertEqual('reg', self.dir['new-reg']) @@ -127,10 +127,9 @@ class DirectoryTest(unittest.TestCase): }, }) - def test_from_json_deserialization_error_on_wrong_key(self): + def test_from_json_deserialization_unknown_key_success(self): # pylint: disable=no-self-use from acme.messages import Directory - self.assertRaises( - jose.DeserializationError, Directory.from_json, {'foo': 'bar'}) + Directory.from_json({'foo': 'bar'}) class RegistrationTest(unittest.TestCase): From 7f70c09c5374ab225a341c73984ed12b3351abd7 Mon Sep 17 00:00:00 2001 From: chrismarget Date: Wed, 11 May 2016 15:19:39 -0400 Subject: [PATCH 085/186] Randomize serial numbers of DVSNI challenge certs. Should now work on python 2.7 and 3.3+ --- acme/acme/crypto_util.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme/acme/crypto_util.py b/acme/acme/crypto_util.py index 6cb5ad6fc..6465533a1 100644 --- a/acme/acme/crypto_util.py +++ b/acme/acme/crypto_util.py @@ -203,7 +203,12 @@ 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(int.from_bytes(OpenSSL.rand.bytes(16),'big')) + + try: + cert.set_serial_number(int(OpenSSL.rand.bytes(16).encode("hex"), 16)) + except AttributeError: + cert.set_serial_number(int.from_bytes(OpenSSL.rand.bytes(16),'big')) + cert.set_version(2) extensions = [ From 6fbd5fa81110e5e0c6aca139e4f827d2bab1da4e Mon Sep 17 00:00:00 2001 From: chrismarget Date: Wed, 11 May 2016 16:04:08 -0400 Subject: [PATCH 086/186] Added missing whitespace. --- acme/acme/crypto_util.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/acme/acme/crypto_util.py b/acme/acme/crypto_util.py index 6465533a1..66590bb26 100644 --- a/acme/acme/crypto_util.py +++ b/acme/acme/crypto_util.py @@ -203,12 +203,10 @@ def gen_ss_cert(key, domains, not_before=None, """ assert domains, "Must provide one or more hostnames for the cert." cert = OpenSSL.crypto.X509() - try: cert.set_serial_number(int(OpenSSL.rand.bytes(16).encode("hex"), 16)) except AttributeError: - cert.set_serial_number(int.from_bytes(OpenSSL.rand.bytes(16),'big')) - + cert.set_serial_number(int.from_bytes(OpenSSL.rand.bytes(16), 'big')) cert.set_version(2) extensions = [ From 4759bc9034a3e2dffbab561345a1716354e89b55 Mon Sep 17 00:00:00 2001 From: chrismarget Date: Wed, 11 May 2016 16:41:19 -0400 Subject: [PATCH 087/186] Trying to make pylint happy. --- acme/acme/crypto_util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/acme/acme/crypto_util.py b/acme/acme/crypto_util.py index 66590bb26..40004c4d0 100644 --- a/acme/acme/crypto_util.py +++ b/acme/acme/crypto_util.py @@ -206,6 +206,7 @@ def gen_ss_cert(key, domains, not_before=None, try: cert.set_serial_number(int(OpenSSL.rand.bytes(16).encode("hex"), 16)) except AttributeError: + # pylint: disable=E1101 cert.set_serial_number(int.from_bytes(OpenSSL.rand.bytes(16), 'big')) cert.set_version(2) From f7b10bb83e01f21bf9aac06b6b7b78d65a1d279d Mon Sep 17 00:00:00 2001 From: chrismarget Date: Wed, 11 May 2016 17:06:29 -0400 Subject: [PATCH 088/186] Serial number randomization with improved portability. No exception handling required this time. --- acme/acme/crypto_util.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/acme/acme/crypto_util.py b/acme/acme/crypto_util.py index 40004c4d0..2b2133475 100644 --- a/acme/acme/crypto_util.py +++ b/acme/acme/crypto_util.py @@ -1,4 +1,5 @@ """Crypto utilities.""" +import binascii import contextlib import logging import re @@ -203,11 +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() - try: - cert.set_serial_number(int(OpenSSL.rand.bytes(16).encode("hex"), 16)) - except AttributeError: - # pylint: disable=E1101 - cert.set_serial_number(int.from_bytes(OpenSSL.rand.bytes(16), 'big')) + cert.set_serial_number(int(binascii.hexlify(OpenSSL.rand.bytes(16)), 16)) cert.set_version(2) extensions = [ From 407ebad36e78c5efa93c56373b2018f07ce31dc5 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 11 May 2016 15:56:10 -0700 Subject: [PATCH 089/186] Support openssl and gpg signatures in parallel --- README.rst | 4 ++-- tools/release.sh | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 840cfff0a..2cec4adad 100644 --- a/README.rst +++ b/README.rst @@ -37,9 +37,9 @@ from your OS and puts others in a python virtual environment:: .. hint:: The certbot-auto download is protected by HTTPS, which is pretty good, but if you'd like to double check the integrity of the ``certbot-auto`` script, you can use these steps for verification before running it:: - user@server:~$ wget https://dl.eff.org/certbot-auto.sig + user@server:~$ wget https://dl.eff.org/certbot-auto.asc user@server:~$ gpg2 --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2 - user@server:~$ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.sig certbot-auto + user@server:~$ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc certbot-auto And for full command line help, you can type:: diff --git a/tools/release.sh b/tools/release.sh index d41192af9..042aa5259 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -187,6 +187,9 @@ while ! openssl dgst -sha256 -verify $RELEASE_OPENSSL_PUBKEY -signature \ read -p "Please correctly sign letsencrypt-auto with offline-signrequest.sh" done +# This signature is not quite as strong, but easier for people to verify out of band +gpg -u "$RELEASE_GPG_KEY" --detach-sign --armor --sign letsencrypt-auto-source/letsencrypt-auto + # copy leauto to the root, overwriting the previous release version cp -p letsencrypt-auto-source/letsencrypt-auto letsencrypt-auto From ba7688ba99cf78f0ef1eff856965e06c4a3d43b3 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 11 May 2016 15:57:38 -0700 Subject: [PATCH 090/186] Avoid certbot-auto.asc.1 --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2cec4adad..74cd838b0 100644 --- a/README.rst +++ b/README.rst @@ -37,7 +37,7 @@ from your OS and puts others in a python virtual environment:: .. hint:: The certbot-auto download is protected by HTTPS, which is pretty good, but if you'd like to double check the integrity of the ``certbot-auto`` script, you can use these steps for verification before running it:: - user@server:~$ wget https://dl.eff.org/certbot-auto.asc + user@server:~$ wget -N https://dl.eff.org/certbot-auto.asc user@server:~$ gpg2 --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2 user@server:~$ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc certbot-auto From 5214c56f06c5202dfe2c77c15d2534daba17fd4c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 11 May 2016 16:09:30 -0700 Subject: [PATCH 091/186] Use certbot-auto.asc --- tools/release.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/release.sh b/tools/release.sh index 2e26e3dab..8c2d04cd4 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -189,6 +189,9 @@ done # This signature is not quite as strong, but easier for people to verify out of band gpg -u "$RELEASE_GPG_KEY" --detach-sign --armor --sign letsencrypt-auto-source/letsencrypt-auto +# We can't rename the openssl letsencrypt-auto.sig for compatibility reasons, +# but we can use the right name for cerbot-auto.asc from day one +mv letsencrypt-auto-source/letsencrypt-auto.asc letsencrypt-auto-source/certbot-auto.asc # copy leauto to the root, overwriting the previous release version cp -p letsencrypt-auto-source/letsencrypt-auto certbot-auto From 8e742fa3c67a5f50dadd674904ef733ca3044d61 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 11 May 2016 18:04:15 -0700 Subject: [PATCH 092/186] Release 0.6.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-auto | 1088 +++++++++++++++++ certbot-compatibility-test/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/__init__.py | 2 +- letsencrypt-apache/setup.py | 2 +- letsencrypt-auto | 269 ++-- letsencrypt-auto-source/certbot-auto.asc | 11 + letsencrypt-auto-source/letsencrypt-auto | 26 +- letsencrypt-auto-source/letsencrypt-auto.sig | Bin 256 -> 256 bytes .../pieces/letsencrypt-auto-requirements.txt | 24 +- letsencrypt-nginx/setup.py | 2 +- letsencrypt/setup.py | 2 +- letshelp-certbot/setup.py | 2 +- letshelp-letsencrypt/setup.py | 2 +- 16 files changed, 1313 insertions(+), 125 deletions(-) create mode 100755 certbot-auto create mode 100644 letsencrypt-auto-source/certbot-auto.asc diff --git a/acme/setup.py b/acme/setup.py index cbd3bfb87..20c7c7226 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0.dev0' +version = '0.6.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 7358c7041..538a68139 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0.dev0' +version = '0.6.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-auto b/certbot-auto new file mode 100755 index 000000000..8c6e6c486 --- /dev/null +++ b/certbot-auto @@ -0,0 +1,1088 @@ +#!/bin/sh +# +# Download and run the latest release version of the Certbot client. +# +# NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING +# +# IF YOU WANT TO EDIT IT LOCALLY, *ALWAYS* RUN YOUR COPY WITH THE +# "--no-self-upgrade" FLAG +# +# IF YOU WANT TO SEND PULL REQUESTS, THE REAL SOURCE FOR THIS FILE IS +# letsencrypt-auto-source/letsencrypt-auto.template AND +# letsencrypt-auto-source/pieces/bootstrappers/* + +set -e # Work even if somebody does "sh thisscript.sh". + +# Note: you can set XDG_DATA_HOME or VENV_PATH before running this script, +# if you want to change where the virtual environment will be installed +XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} +VENV_NAME="letsencrypt" +VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} +VENV_BIN="$VENV_PATH/bin" +LE_AUTO_VERSION="0.6.0" +BASENAME=$(basename $0) +USAGE="Usage: $BASENAME [OPTIONS] +A self-updating wrapper script for the Certbot ACME client. When run, updates +to both this script and certbot will be downloaded and installed. After +ensuring you have the latest versions installed, certbot will be invoked with +all arguments you have provided. + +Help for certbot itself cannot be provided until it is installed. + + --debug attempt experimental installation + -h, --help print this help + -n, --non-interactive, --noninteractive run without asking for user input + --no-self-upgrade do not download updates + --os-packages-only install OS dependencies and exit + -v, --verbose provide more output + +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) + DEBUG=1;; + --os-packages-only) + OS_PACKAGES_ONLY=1;; + --no-self-upgrade) + # Do not upgrade this script (also prevents client upgrades, because each + # copy of the script pins a hash of the python client) + NO_SELF_UPGRADE=1;; + --help) + HELP=1;; + --noninteractive|--non-interactive) + ASSUME_YES=1;; + --verbose) + VERBOSE=1;; + esac +done + +# 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 +# this script *can* be run as root (not recommended), or fall back to using +# `su` +SUDO_ENV="" +export CERTBOT_AUTO="$0" +if test "`id -u`" -ne "0" ; then + if command -v sudo 1>/dev/null 2>&1; then + SUDO=sudo + SUDO_ENV="CERTBOT_AUTO=$0" + else + echo \"sudo\" is not available, will use \"su\" for installation steps... + # Because the parameters in `su -c` has to be a string, + # we need properly escape it + su_sudo() { + args="" + # This `while` loop iterates over all parameters given to this function. + # For each parameter, all `'` will be replace by `'"'"'`, and the escaped string + # will be wrapped in a pair of `'`, then appended to `$args` string + # For example, `echo "It's only 1\$\!"` will be escaped to: + # 'echo' 'It'"'"'s only 1$!' + # │ │└┼┘│ + # │ │ │ └── `'s only 1$!'` the literal string + # │ │ └── `\"'\"` is a single quote (as a string) + # │ └── `'It'`, to be concatenated with the strings following it + # └── `echo` wrapped in a pair of `'`, it's totally fine for the shell command itself + while [ $# -ne 0 ]; do + args="$args'$(printf "%s" "$1" | sed -e "s/'/'\"'\"'/g")' " + shift + done + su root -c "$args" + } + SUDO=su_sudo + fi +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 + if [ "$2" != "" ]; then + echo "Bootstrapping dependencies via $1..." + $2 + fi + else + echo "WARNING: $1 support is very experimental at present..." + echo "if you would like to work on improving it, please ensure you have backups" + echo "and then run this script again with the --debug flag!" + exit 1 + fi +} + +DeterminePythonVersion() { + for LE_PYTHON in "$LE_PYTHON" python2.7 python27 python2 python; do + # Break (while keeping the LE_PYTHON value) if found. + command -v "$LE_PYTHON" > /dev/null && break + done + if [ "$?" != "0" ]; then + echo "Cannot find any Pythons; please install one!" + exit 1 + fi + export LE_PYTHON + + PYVER=`"$LE_PYTHON" -V 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | sed 's/\.//'` + if [ "$PYVER" -lt 26 ]; then + echo "You have an ancient version of Python entombed in your operating system..." + echo "This isn't going to work; you'll need at least version 2.6." + exit 1 + fi +} + +BootstrapDebCommon() { + # Current version tested with: + # + # - Ubuntu + # - 14.04 (x64) + # - 15.04 (x64) + # - Debian + # - 7.9 "wheezy" (x64) + # - sid (2015-10-21) (x64) + + # Past versions tested with: + # + # - Debian 8.0 "jessie" (x64) + # - Raspbian 7.8 (armhf) + + # Believed not to work: + # + # - Debian 6.0.10 "squeeze" (x64) + + $SUDO apt-get update || echo apt-get update hit problems but continuing anyway... + + # virtualenv binary can be found in different packages depending on + # distro version (#346) + + virtualenv= + if apt-cache show virtualenv > /dev/null 2>&1; then + virtualenv="virtualenv" + fi + + if apt-cache show python-virtualenv > /dev/null 2>&1; then + virtualenv="$virtualenv python-virtualenv" + fi + + augeas_pkg="libaugeas0 augeas-lenses" + AUGVERSION=`apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2` + + if [ "$ASSUME_YES" = 1 ]; then + YES_FLAG="-y" + fi + + AddBackportRepo() { + # ARGS: + BACKPORT_NAME="$1" + BACKPORT_SOURCELINE="$2" + echo "To use the Apache Certbot plugin, augeas needs to be installed from $BACKPORT_NAME." + if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then + # This can theoretically error if sources.list.d is empty, but in that case we don't care. + if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then + if [ "$ASSUME_YES" = 1 ]; then + /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." + sleep 1s + /bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..." + sleep 1s + /bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..." + sleep 1s + add_backports=1 + else + read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response + case $response in + [yY][eE][sS]|[yY]|"") + add_backports=1;; + *) + add_backports=0;; + esac + fi + if [ "$add_backports" = 1 ]; then + $SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list" + $SUDO apt-get update + fi + fi + fi + if [ "$add_backports" != 0 ]; then + $SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg + augeas_pkg= + fi + } + + + if dpkg --compare-versions 1.0 gt "$AUGVERSION" ; then + if lsb_release -a | grep -q wheezy ; then + AddBackportRepo wheezy-backports "deb http://http.debian.net/debian wheezy-backports main" + elif lsb_release -a | grep -q precise ; then + # XXX add ARM case + AddBackportRepo precise-backports "deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse" + else + echo "No libaugeas0 version is available that's new enough to run the" + echo "Certbot apache plugin..." + fi + # XXX add a case for ubuntu PPAs + fi + + $SUDO apt-get install $YES_FLAG --no-install-recommends \ + python \ + python-dev \ + $virtualenv \ + gcc \ + dialog \ + $augeas_pkg \ + libssl-dev \ + libffi-dev \ + ca-certificates \ + + + + if ! command -v virtualenv > /dev/null ; then + echo Failed to install a working \"virtualenv\" command, exiting + exit 1 + fi +} + +BootstrapRpmCommon() { + # Tested with: + # - Fedora 20, 21, 22, 23 (x64) + # - Centos 7 (x64: on DigitalOcean droplet) + # - CentOS 7 Minimal install in a Hyper-V VM + # - CentOS 6 (EPEL must be installed manually) + + if type dnf 2>/dev/null + then + tool=dnf + elif type yum 2>/dev/null + then + tool=yum + + else + echo "Neither yum nor dnf found. Aborting bootstrap!" + exit 1 + fi + + pkgs=" + gcc + dialog + augeas-libs + openssl + openssl-devel + libffi-devel + redhat-rpm-config + ca-certificates + " + + # Some distros and older versions of current distros use a "python27" + # instead of "python" naming convention. Try both conventions. + if $SUDO $tool list python >/dev/null 2>&1; then + pkgs="$pkgs + python + python-devel + python-virtualenv + python-tools + python-pip + " + else + pkgs="$pkgs + python27 + python27-devel + python27-virtualenv + python27-tools + python27-pip + " + fi + + if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then + pkgs="$pkgs + mod_ssl + " + fi + + if [ "$ASSUME_YES" = 1 ]; then + yes_flag="-y" + fi + + if ! $SUDO $tool install $yes_flag $pkgs; then + echo "Could not install OS dependencies. Aborting bootstrap!" + exit 1 + fi +} + +BootstrapSuseCommon() { + # SLE12 don't have python-virtualenv + + if [ "$ASSUME_YES" = 1 ]; then + zypper_flags="-nq" + install_flags="-l" + fi + + $SUDO zypper $zypper_flags in $install_flags \ + python \ + python-devel \ + python-virtualenv \ + gcc \ + dialog \ + augeas-lenses \ + libopenssl-devel \ + libffi-devel \ + ca-certificates +} + +BootstrapArchCommon() { + # Tested with: + # - ArchLinux (x86_64) + # + # "python-virtualenv" is Python3, but "python2-virtualenv" provides + # only "virtualenv2" binary, not "virtualenv" necessary in + # ./tools/_venv_common.sh + + deps=" + python2 + python-virtualenv + gcc + dialog + augeas + openssl + libffi + ca-certificates + pkg-config + " + + # pacman -T exits with 127 if there are missing dependencies + missing=$($SUDO pacman -T $deps) || true + + if [ "$ASSUME_YES" = 1 ]; then + noconfirm="--noconfirm" + fi + + if [ "$missing" ]; then + $SUDO pacman -S --needed $missing $noconfirm + fi +} + +BootstrapGentooCommon() { + PACKAGES=" + dev-lang/python:2.7 + dev-python/virtualenv + dev-util/dialog + app-admin/augeas + dev-libs/openssl + dev-libs/libffi + app-misc/ca-certificates + virtual/pkgconfig" + + case "$PACKAGE_MANAGER" in + (paludis) + $SUDO cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x + ;; + (pkgcore) + $SUDO pmerge --noreplace --oneshot $PACKAGES + ;; + (portage|*) + $SUDO emerge --noreplace --oneshot $PACKAGES + ;; + esac +} + +BootstrapFreeBsd() { + $SUDO pkg install -Ay \ + python \ + py27-virtualenv \ + augeas \ + libffi +} + +BootstrapMac() { + if hash brew 2>/dev/null; then + echo "Using Homebrew to install dependencies..." + pkgman=brew + pkgcmd="brew install" + elif hash port 2>/dev/null; then + echo "Using MacPorts to install dependencies..." + pkgman=port + pkgcmd="$SUDO port install" + else + echo "No Homebrew/MacPorts; installing Homebrew..." + ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + pkgman=brew + pkgcmd="brew install" + fi + + $pkgcmd augeas + $pkgcmd dialog + if [ "$(which python)" = "/System/Library/Frameworks/Python.framework/Versions/2.7/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..." + $pkgcmd python + fi + + # 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 + fi + + if ! hash pip 2>/dev/null; then + echo "pip not installed" + echo "Installing pip..." + curl --silent --show-error --retry 5 https://bootstrap.pypa.io/get-pip.py | python + fi + + if ! hash virtualenv 2>/dev/null; then + echo "virtualenv not installed." + echo "Installing with pip..." + pip install virtualenv + fi +} + + +# Install required OS packages: +Bootstrap() { + if [ -f /etc/debian_version ]; then + echo "Bootstrapping dependencies for Debian-based OSes..." + BootstrapDebCommon + elif [ -f /etc/redhat-release ]; then + echo "Bootstrapping dependencies for RedHat-based OSes..." + BootstrapRpmCommon + elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then + echo "Bootstrapping dependencies for openSUSE-based OSes..." + BootstrapSuseCommon + elif [ -f /etc/arch-release ]; then + if [ "$DEBUG" = 1 ]; then + echo "Bootstrapping dependencies for Archlinux..." + BootstrapArchCommon + else + echo "Please use pacman to install letsencrypt packages:" + echo "# pacman -S letsencrypt letsencrypt-apache" + echo + echo "If you would like to use the virtualenv way, please run the script again with the" + echo "--debug flag." + exit 1 + fi + elif [ -f /etc/manjaro-release ]; then + ExperimentalBootstrap "Manjaro Linux" BootstrapArchCommon + elif [ -f /etc/gentoo-release ]; then + ExperimentalBootstrap "Gentoo" BootstrapGentooCommon + elif uname | grep -iq FreeBSD ; then + ExperimentalBootstrap "FreeBSD" BootstrapFreeBsd + elif uname | grep -iq Darwin ; then + ExperimentalBootstrap "Mac OS X" BootstrapMac + elif grep -iq "Amazon Linux" /etc/issue ; then + ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon + else + echo "Sorry, I don't know how to bootstrap Certbot on your operating system!" + echo + echo "You will need to bootstrap, configure virtualenv, and run pip install manually." + echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" + echo "for more info." + fi +} + +TempDir() { + mktemp -d 2>/dev/null || mktemp -d -t 'le' # Linux || OS X +} + + + +if [ "$1" = "--le-auto-phase2" ]; then + # Phase 2: Create venv, install LE, and run. + + shift 1 # the --le-auto-phase2 arg + if [ -f "$VENV_BIN/letsencrypt" ]; then + # --version output ran through grep due to python-cryptography DeprecationWarnings + # grep for both certbot and letsencrypt until certbot and shim packages have been released + INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2) + else + INSTALLED_VERSION="none" + fi + if [ "$LE_AUTO_VERSION" != "$INSTALLED_VERSION" ]; then + echo "Creating virtual environment..." + DeterminePythonVersion + rm -rf "$VENV_PATH" + if [ "$VERBOSE" = 1 ]; then + virtualenv --no-site-packages --python "$LE_PYTHON" "$VENV_PATH" + else + virtualenv --no-site-packages --python "$LE_PYTHON" "$VENV_PATH" > /dev/null + fi + + echo "Installing Python packages..." + TEMP_DIR=$(TempDir) + # There is no $ interpolation due to quotes on starting heredoc delimiter. + # ------------------------------------------------------------------------- + cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt" +# This is the flattened list of packages certbot-auto installs. To generate +# this, do `pip install --no-cache-dir -e acme -e . -e certbot-apache`, and +# then use `hashin` or a more secure method to gather the hashes. + +argparse==1.4.0 \ + --hash=sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314 \ + --hash=sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4 + +# This comes before cffi because cffi will otherwise install an unchecked +# version via setup_requires. +pycparser==2.14 \ + --hash=sha256:7959b4a74abdc27b312fed1c21e6caf9309ce0b29ea86b591fd2e99ecdf27f73 + +cffi==1.4.2 \ + --hash=sha256:53c1c9ddb30431513eb7f3cdef0a3e06b0f1252188aaa7744af0f5a4cd45dbaf \ + --hash=sha256:a568f49dfca12a8d9f370187257efc58a38109e1eee714d928561d7a018a64f8 \ + --hash=sha256:809c6ca8cfbcaeebfbd432b4576001b40d38ff2463773cb57577d75e1a020bc3 \ + --hash=sha256:86cdca2cd9cba41422230390df17dfeaa9f344a911e3975c8be9da57b35548e9 \ + --hash=sha256:24b13db84aec385ca23c7b8ded83ef8bb4177bc181d14758f9f975be5d020d86 \ + --hash=sha256:969aeffd7c0e097f6be1efd682c156ae226591a0793a94b6c2d5e4293f4c8d4e \ + --hash=sha256:000f358d4b0fa249feaab9c1ce7d5b2fe7e02e7bdf6806c26418505fc685e268 \ + --hash=sha256:a9d86f460bbd8358a2d513ad779e3f3fc878e3b93a00b5002faebf616ffe6b9c \ + --hash=sha256:3127b3ab33eb23ccac071f9a0802748e5cf7c5cbcd02482bb063e35b41dbb0b0 \ + --hash=sha256:e2b2d42236469a40224d39e7b6c60575f388b2f423f354c7ee90a5b7f58c8065 \ + --hash=sha256:8c2dccafee89b1b424b0bec6ad2dd9622c949d2024e929f5da1ed801eac75f1d \ + --hash=sha256:a4de7a4d11aed488bab4fb14f4988587a829bece5a20433f780d6e33b08083cb \ + --hash=sha256:5ca8fe30425265a49274e4b0213a1bc98f4b13449ae5e96f984771e5d83e58c1 \ + --hash=sha256:a4fd38802f59e714eba81a024f62db710b27dbe27a7ea12e911537327aa84d30 \ + --hash=sha256:86cd6912bbc83e9405d4a73cd7f4b4ee8353652d2dbc7c820106ed5b4d1bab3a \ + --hash=sha256:8f1d177d364ea35900415ae24ca3e471be3d5334ed0419294068c49f45913998 +ConfigArgParse==0.10.0 \ + --hash=sha256:3b50a83dd58149dfcee98cb6565265d10b53e9c0a2bca7eeef7fb5f5524890a7 +configobj==5.0.6 \ + --hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902 +cryptography==1.2.3 \ + --hash=sha256:031938f73a5c5eb3e809e18ff7caeb6865351871417be6050cb8c86a9a202b9a \ + --hash=sha256:a179a38d50f8d68b491d7a313db78f8cabe290842cecddddc7b34d408e59db0a \ + --hash=sha256:906c88b2aadcf99cfabb24098263d1bf65ab0c8688acde10dae1f09d865920f1 \ + --hash=sha256:6e706c5c6088770b1d1b634e959e21963e315b0255f5f4777125ad3d54082977 \ + --hash=sha256:f5ebf8e31c48f8707921dca0e994de77813a9c9b9bf03c119c5ddf97bdcffe73 \ + --hash=sha256:c7b89e42288cc7fbee3812e99ef5c744f22452e11d6822f6807afc6d6b3be83e \ + --hash=sha256:8408d29865947109d8b68f1837a7cde1aa4dc86e0f79ca3ba58c0c44e443d6a5 \ + --hash=sha256:c7e76cf3c3d925dd31fa238cfb806cffba718c0f08707d77a538768477969956 \ + --hash=sha256:7d8de35380f31702758b7753bb5c40723832c73006dedb2f9099bf61a37f7287 \ + --hash=sha256:5edbee71fae5469ee83fe0a37866b9398c8ce3a46325c24fcedfbf097bb48a19 \ + --hash=sha256:594edafe4801c13bdc1cc305e7704a90c19617e95936f6ab457ee4ffe000ba50 \ + --hash=sha256:b7fdb16a0a7f481be42da744bfe1ea2163025de21f90f2c688a316f3c354da9c \ + --hash=sha256:207b8bf0fe0907336df38b733b487521cf9e138189aba9234ad54fe545dd0db8 \ + --hash=sha256:509a2f05386270cf783993c90d49ffefb3dd62aee45bf1ea8ce3d2cde7271c21 \ + --hash=sha256:ac69b65dd1af0179ede40c9f15788c88f73e628ea6c0519de3838e279bb388c6 \ + --hash=sha256:8df6fad6c6ae12fd7004ea29357f0a2b4d3774eaeca7656530d08d2d90cd41aa \ + --hash=sha256:0b8b96dd81cc1533a04f30382c0fe21c1972e189f794d0c4261a18cec08fd9b5 \ + --hash=sha256:cae8fca1883f23c50ea78d89de6fe4fefdb4cea83177760f47177559414ded93 \ + --hash=sha256:1a471ca576a9cdce1b1cd9f3a22b1d09ee44d46862037557de17919c0db44425 \ + --hash=sha256:8ec4e8e3d453b3a1b63b5f57737a434dcf1ee4a2f26f6ff7c5a37c3f679104d2 \ + --hash=sha256:8eb11c77dd8e73f48df6b2f7a7e16173fe0fe8fdfe266232832e88477e08454e +enum34==1.1.2 \ + --hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \ + --hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501 +funcsigs==0.4 \ + --hash=sha256:ff5ad9e2f8d9e5d1e8bbfbcf47722ab527cf0d51caeeed9da6d0f40799383fde \ + --hash=sha256:d83ce6df0b0ea6618700fe1db353526391a8a3ada1b7aba52fed7a61da772033 +idna==2.0 \ + --hash=sha256:9b2fc50bd3c4ba306b9651b69411ef22026d4d8335b93afc2214cef1246ce707 \ + --hash=sha256:16199aad938b290f5be1057c0e1efc6546229391c23cea61ca940c115f7d3d3b +ipaddress==1.0.16 \ + --hash=sha256:935712800ce4760701d89ad677666cd52691fd2f6f0b340c8b4239a3c17988a5 \ + --hash=sha256:5a3182b322a706525c46282ca6f064d27a02cffbd449f9f47416f1dc96aa71b0 +linecache2==1.0.0 \ + --hash=sha256:e78be9c0a0dfcbac712fe04fbf92b96cddae80b1b842f24248214c8496f006ef \ + --hash=sha256:4b26ff4e7110db76eeb6f5a7b64a82623839d595c2038eeda662f2a2db78e97c +ndg-httpsclient==0.4.0 \ + --hash=sha256:e8c155fdebd9c4bcb0810b4ed01ae1987554b1ee034dd7532d7b8fdae38a6274 +ordereddict==1.1 \ + --hash=sha256:1c35b4ac206cef2d24816c89f89cf289dd3d38cf7c449bb3fab7bf6d43f01b1f +parsedatetime==2.1 \ + --hash=sha256:ce9d422165cf6e963905cd5f74f274ebf7cc98c941916169178ef93f0e557838 \ + --hash=sha256:17c578775520c99131634e09cfca5a05ea9e1bd2a05cd06967ebece10df7af2d +pbr==1.8.1 \ + --hash=sha256:46c8db75ae75a056bd1cc07fa21734fe2e603d11a07833ecc1eeb74c35c72e0c \ + --hash=sha256:e2127626a91e6c885db89668976db31020f0af2da728924b56480fc7ccf09649 +psutil==3.3.0 \ + --hash=sha256:584f0b29fcc5d523b433cb8918b2fc74d67e30ee0b44a95baf031528f424619f \ + --hash=sha256:28ca0b6e9d99aa8dc286e8747a4471362b69812a25291de29b6a8d70a1545a0d \ + --hash=sha256:167ad5fff52a672c4ddc1c1a0b25146d6813ebb08a9aab0a3ac45f8a5b669c3b \ + --hash=sha256:e6dea6173a988727bb223d3497349ad5cdef5c0b282eff2d83e5f9065c53f85f \ + --hash=sha256:2af5e0a4aad66049955d0734aa4e3dc8caa17a9eaf8b4c1a27a5f1ee6e40f6fc \ + --hash=sha256:d9884dc0dc2e55e2448e495778dc9899c1c8bf37aeb2f434c1bea74af93c2683 \ + --hash=sha256:e27c2fe6dfcc8738be3d2c5a022f785eb72971057e1a9e1e34fba73bce8a71a6 \ + --hash=sha256:65afd6fecc8f3aed09ee4be63583bc8eb472f06ceaa4fe24c4d1d5a1a3c0e13f \ + --hash=sha256:ba1c558fbfcdf94515c2394b1155c1dc56e2bc2a9c17d30349827c9ed8a67e46 \ + --hash=sha256:ba95ea0022dcb64d36f0c1335c0605fae35bdf3e0fea8d92f5d0f6456a35e55b \ + --hash=sha256:421b6591d16b509aaa8d8c15821d66bb94cb4a8dc4385cad5c51b85d4a096d85 \ + --hash=sha256:326b305cbdb6f94dafbfe2c26b11da88b0ab07b8a07f8188ab9d75ff0c6e841a \ + --hash=sha256:9aede5b2b6fe46b3748ea8e5214443890d1634027bef3d33b7dad16556830278 \ + --hash=sha256:73bed1db894d1aa9c3c7e611d302cdeab7ae8a0dc0eeaf76727878db1ac5cd87 \ + --hash=sha256:935b5dd6d558af512f42501a7c08f41d7aff139af1bb3959daa3abb859234d6c \ + --hash=sha256:4ca0111cf157dcc0f2f69a323c5b5478718d68d45fc9435d84be0ec0f186215b \ + --hash=sha256:b6f13c95398a3fcf0226c4dcfa448560ba5865259cd96ec2810658651e932189 \ + --hash=sha256:ee6be30d1635bbdea4c4325d507dc8a0dbbde7e1c198bd62ddb9f43198b9e214 \ + --hash=sha256:dfa786858c268d7fbbe1b6175e001ec02738d7cfae0a7ce77bf9b651af676729 \ + --hash=sha256:aa77f9de72af9c16cc288cd4a24cf58824388f57d7a81e400c4616457629870e \ + --hash=sha256:f500093357d04da8140d87932cac2e54ef592a54ca8a743abb2850f60c2c22eb +pyasn1==0.1.9 \ + --hash=sha256:61f9d99e3cef65feb1bfe3a2eef7a93eb93819d345bf54bcd42f4e63d5204dae \ + --hash=sha256:1802a6dd32045e472a419db1441aecab469d33e0d2749e192abdec52101724af \ + --hash=sha256:35025cd9422c96504912f04e2f15fe79390a8597b430c2ca5d0534cf9309ffa0 \ + --hash=sha256:2f96ed5a0c329ca16230b326ca12b7461ec8f65e0be3e4f997516f36bf82a345 \ + --hash=sha256:28fee44217991cfad9e6a0b9f7e3f26041e21ebc96629e94e585ccd05d49fa65 \ + --hash=sha256:326e7a854a17fab07691204747695f8f692d674588a355c441fb14f660bf4e68 \ + --hash=sha256:cda5a90485709ca6795c86056c3e5fe7266028b05e53f1d527fdf93a6365a6b8 \ + --hash=sha256:0cb2a14742b543fdd68f931a14ce3829186ed2b1b2267a06787388c96b2dd9be \ + --hash=sha256:5191ff6b9126d2c039dd87f8ff025bed274baf07fa78afa46f556b1ad7265d6e \ + --hash=sha256:8323e03637b2d072cc7041300bac6ec448c3c28950ab40376036788e9a1af629 \ + --hash=sha256:853cacd96d1f701ddd67aa03ecc05f51890135b7262e922710112f12a2ed2a7f +pyOpenSSL==0.15.1 \ + --hash=sha256:88e45e6bb25dfed272a1ef2e728461d44b634c2cd689e989b6e56a349c5a3ae5 \ + --hash=sha256:f0a26070d6db0881de8bcc7846934b7c3c930d8f9c79d45883ee48984bc0d672 +pyRFC3339==1.0 \ + --hash=sha256:eea31835c56e2096af4363a5745a784878a61d043e247d3a6d6a0a32a9741f56 \ + --hash=sha256:8dfbc6c458b8daba1c0f3620a8c78008b323a268b27b7359e92a4ae41325f535 +python-augeas==0.5.0 \ + --hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2 +python2-pythondialog==3.3.0 \ + --hash=sha256:04e93f24995c43dd90f338d5d865ca72ce3fb5a5358d4daa4965571db35fc3ec \ + --hash=sha256:3e6f593fead98f8a526bc3e306933533236e33729f552f52896ea504f55313fa +pytz==2015.7 \ + --hash=sha256:3abe6a6d3fc2fbbe4c60144211f45da2edbe3182a6f6511af6bbba0598b1f992 \ + --hash=sha256:939ef9c1e1224d980405689a97ffcf7828c56d1517b31d73464356c1f2b7769e \ + --hash=sha256:ead4aefa7007249e05e51b01095719d5a8dd95760089f5730aac5698b1932918 \ + --hash=sha256:3cca0df08bd0ed98432390494ce3ded003f5e661aa460be7a734bffe35983605 \ + --hash=sha256:3ede470d3d17ba3c07638dfa0d10452bc1b6e5ad326127a65ba77e6aaeb11bec \ + --hash=sha256:68c47964f7186eec306b13629627722b9079cd4447ed9e5ecaecd4eac84ca734 \ + --hash=sha256:dd5d3991950aae40a6c81de1578942e73d629808cefc51d12cd157980e6cfc18 \ + --hash=sha256:a77c52062c07eb7c7b30545dbc73e32995b7e117eea750317b5cb5c7a4618f14 \ + --hash=sha256:81af9aec4bc960a9a0127c488f18772dae4634689233f06f65443e7b11ebeb51 \ + --hash=sha256:e079b1dadc5c06246cc1bb6fe1b23a50b1d1173f2edd5104efd40bb73a28f406 \ + --hash=sha256:fbd26746772c24cb93c8b97cbdad5cb9e46c86bbdb1b9d8a743ee00e2fb1fc5d \ + --hash=sha256:99266ef30a37e43932deec2b7ca73e83c8dbc3b9ff703ec73eca6b1dae6befea \ + --hash=sha256:8b6ce1c993909783bc96e0b4f34ea223bff7a4df2c90bdb9c4e0f1ac928689e3 +requests==2.9.1 \ + --hash=sha256:113fbba5531a9e34945b7d36b33a084e8ba5d0664b703c81a7c572d91919a5b8 \ + --hash=sha256:c577815dd00f1394203fc44eb979724b098f88264a9ef898ee45b8e5e9cf587f +six==1.10.0 \ + --hash=sha256:0ff78c403d9bccf5a425a6d31a12aa6b47f1c21ca4dc2573a7e2f32a97335eb1 \ + --hash=sha256:105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a +traceback2==1.4.0 \ + --hash=sha256:8253cebec4b19094d67cc5ed5af99bf1dba1285292226e98a31929f87a5d6b23 \ + --hash=sha256:05acc67a09980c2ecfedd3423f7ae0104839eccb55fc645773e1caa0951c3030 +unittest2==1.1.0 \ + --hash=sha256:13f77d0875db6d9b435e1d4f41e74ad4cc2eb6e1d5c824996092b3430f088bb8 \ + --hash=sha256:22882a0e418c284e1f718a822b3b022944d53d2d908e1690b319a9d3eb2c0579 +zope.component==4.2.2 \ + --hash=sha256:282c112b55dd8e3c869a3571f86767c150ab1284a9ace2bdec226c592acaf81a +zope.event==4.1.0 \ + --hash=sha256:dc7a59a2fd91730d3793131a5d261b29e93ec4e2a97f1bc487ce8defee2fe786 +zope.interface==4.1.3 \ + --hash=sha256:f07b631f7a601cd8cbd3332d54f43142c7088a83299f859356f08d1d4d4259b3 \ + --hash=sha256:de5cca083b9439d8002fb76bbe6b4998c5a5a721fab25b84298967f002df4c94 \ + --hash=sha256:6788416f7ea7f5b8a97be94825377aa25e8bdc73463e07baaf9858b29e737077 \ + --hash=sha256:6f3230f7254518201e5a3708cbb2de98c848304f06e3ded8bfb39e5825cba2e1 \ + --hash=sha256:5fa575a5240f04200c3088427d0d4b7b737f6e9018818a51d8d0f927a6a2517a \ + --hash=sha256:522194ad6a545735edd75c8a83f48d65d1af064e432a7d320d64f56bafc12e99 \ + --hash=sha256:e8c7b2d40943f71c99148c97f66caa7f5134147f57423f8db5b4825099ce9a09 \ + --hash=sha256:279024f0208601c3caa907c53876e37ad88625f7eaf1cb3842dbe360b2287017 \ + --hash=sha256:2e221a9eec7ccc58889a278ea13dcfed5ef939d80b07819a9a8b3cb1c681484f \ + --hash=sha256:69118965410ec86d44dc6b9017ee3ddbd582e0c0abeef62b3a19dbf6c8ad132b \ + --hash=sha256:d04df8686ec864d0cade8cf199f7f83aecd416109a20834d568f8310ded12dea \ + --hash=sha256:e75a947e15ee97e7e71e02ea302feb2fc62d3a2bb4668bf9dfbed43a506ac7e7 \ + --hash=sha256:4e45d22fb883222a5ab9f282a116fec5ee2e8d1a568ccff6a2d75bbd0eb6bcfc \ + --hash=sha256:bce9339bb3c7a55e0803b63d21c5839e8e479bc85c4adf42ae415b72f94facb2 \ + --hash=sha256:928138365245a0e8869a5999fbcc2a45475a0a6ed52a494d60dbdc540335fedd \ + --hash=sha256:0d841ba1bb840eea0e6489dc5ecafa6125554971f53b5acb87764441e61bceba \ + --hash=sha256:b09c8c1d47b3531c400e0195697f1414a63221de6ef478598a4f1460f7d9a392 +mock==1.0.1 \ + --hash=sha256:b839dd2d9c117c701430c149956918a423a9863b48b09c90e30a6013e7d2f44f \ + --hash=sha256:8f83080daa249d036cbccfb8ae5cc6ff007b88d6d937521371afabe7b19badbc + +# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. + +acme==0.6.0 \ + --hash=sha256:cbe4e7a340a19725a8740ed86e30abdbe18fc22c4c6022b7a8e56642d502bcc3 \ + --hash=sha256:ec4e6009dfbd629b58473eb06bbebfd9fb2a79fc8831c149e9205bc38a98ecc6 +certbot==0.6.0 \ + --hash=sha256:a893632d228864b0a751db9f3fdd93439ed34b988ea21b64fb0f0fa2ceded6a2 \ + --hash=sha256:80b0b7dc5afeec2816ef638a61e7c628d73cd72666eebf4984be426d1c2b492d +certbot-apache==0.6.0 \ + --hash=sha256:0ab077f0913b81ed5c1b141c3a7c4c0228ef3738d8d61a93db794d9a80718d43 \ + --hash=sha256:1cfbe751209079a803758f472200816fac559f2a36fdd582d25e3ba5601423a1 +letsencrypt==0.6.0 \ + --hash=sha256:93196c7dcd57272a753e525d145c5a9987c8968c22ec954bcf83dcc9d2499a76 \ + --hash=sha256:a16d6c395f1bf5fd61a28ef83dc78f42dbecbad9d00be6236f2ad8915645c154 +letsencrypt-apache==0.6.0 \ + --hash=sha256:02fadc52a0796e53978c508beec9c53e1fc047660240832b9bde5d53ab3a1379 \ + --hash=sha256:1c5522d94d7750bdb9bfa6201d2c263e914f662c9d0079e673167233cf4364f1 + +UNLIKELY_EOF + # ------------------------------------------------------------------------- + cat << "UNLIKELY_EOF" > "$TEMP_DIR/pipstrap.py" +#!/usr/bin/env python +"""A small script that can act as a trust root for installing pip 8 + +Embed this in your project, and your VCS checkout is all you have to trust. In +a post-peep era, this lets you claw your way to a hash-checking version of pip, +with which you can install the rest of your dependencies safely. All it assumes +is Python 2.6 or better and *some* version of pip already installed. If +anything goes wrong, it will exit with a non-zero status code. + +""" +# This is here so embedded copies are MIT-compliant: +# Copyright (c) 2016 Erik Rose +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +from __future__ import print_function +from hashlib import sha256 +from os.path import join +from pipes import quote +from shutil import rmtree +try: + from subprocess import check_output +except ImportError: + from subprocess import CalledProcessError, PIPE, Popen + + def check_output(*popenargs, **kwargs): + if 'stdout' in kwargs: + raise ValueError('stdout argument not allowed, it will be ' + 'overridden.') + process = Popen(stdout=PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise CalledProcessError(retcode, cmd) + return output +from sys import exit, version_info +from tempfile import mkdtemp +try: + from urllib2 import build_opener, HTTPHandler, HTTPSHandler +except ImportError: + from urllib.request import build_opener, HTTPHandler, HTTPSHandler +try: + from urlparse import urlparse +except ImportError: + from urllib.parse import urlparse # 3.4 + + +__version__ = 1, 1, 1 + + +# wheel has a conditional dependency on argparse: +maybe_argparse = ( + [('https://pypi.python.org/packages/source/a/argparse/' + 'argparse-1.4.0.tar.gz', + '62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4')] + if version_info < (2, 7, 0) else []) + + +PACKAGES = maybe_argparse + [ + # Pip has no dependencies, as it vendors everything: + ('https://pypi.python.org/packages/source/p/pip/pip-8.0.3.tar.gz', + '30f98b66f3fe1069c529a491597d34a1c224a68640c82caf2ade5f88aa1405e8'), + # This version of setuptools has only optional dependencies: + ('https://pypi.python.org/packages/source/s/setuptools/' + 'setuptools-20.2.2.tar.gz', + '24fcfc15364a9fe09a220f37d2dcedc849795e3de3e4b393ee988e66a9cbd85a'), + ('https://pypi.python.org/packages/source/w/wheel/wheel-0.29.0.tar.gz', + '1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648') +] + + +class HashError(Exception): + def __str__(self): + url, path, actual, expected = self.args + return ('{url} did not match the expected hash {expected}. Instead, ' + 'it was {actual}. The file (left at {path}) may have been ' + 'tampered with.'.format(**locals())) + + +def hashed_download(url, temp, digest): + """Download ``url`` to ``temp``, make sure it has the SHA-256 ``digest``, + and return its path.""" + # Based on pip 1.4.1's URLOpener but with cert verification removed. Python + # >=2.7.9 verifies HTTPS certs itself, and, in any case, the cert + # authenticity has only privacy (not arbitrary code execution) + # implications, since we're checking hashes. + def opener(): + opener = build_opener(HTTPSHandler()) + # Strip out HTTPHandler to prevent MITM spoof: + for handler in opener.handlers: + if isinstance(handler, HTTPHandler): + opener.handlers.remove(handler) + return opener + + def read_chunks(response, chunk_size): + while True: + chunk = response.read(chunk_size) + if not chunk: + break + yield chunk + + response = opener().open(url) + path = join(temp, urlparse(url).path.split('/')[-1]) + actual_hash = sha256() + with open(path, 'wb') as file: + for chunk in read_chunks(response, 4096): + file.write(chunk) + actual_hash.update(chunk) + + actual_digest = actual_hash.hexdigest() + if actual_digest != digest: + raise HashError(url, path, actual_digest, digest) + return path + + +def main(): + temp = mkdtemp(prefix='pipstrap-') + try: + downloads = [hashed_download(url, temp, digest) + for url, digest in PACKAGES] + check_output('pip install --no-index --no-deps -U ' + + ' '.join(quote(d) for d in downloads), + shell=True) + except HashError as exc: + print(exc) + except Exception: + rmtree(temp) + raise + else: + rmtree(temp) + return 0 + return 1 + + +if __name__ == '__main__': + exit(main()) + +UNLIKELY_EOF + # ------------------------------------------------------------------------- + # Set PATH so pipstrap upgrades the right (v)env: + PATH="$VENV_BIN:$PATH" "$VENV_BIN/python" "$TEMP_DIR/pipstrap.py" + set +e + PIP_OUT=`"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1` + PIP_STATUS=$? + set -e + rm -rf "$TEMP_DIR" + if [ "$PIP_STATUS" != 0 ]; then + # Report error. (Otherwise, be quiet.) + echo "Had a problem while installing Python packages:" + echo "$PIP_OUT" + rm -rf "$VENV_PATH" + exit 1 + fi + echo "Installation succeeded." + fi + echo "Requesting root privileges to run certbot..." + 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 + +else + # Phase 1: Upgrade certbot-auto if neceesary, then self-invoke. + # + # Each phase checks the version of only the thing it is responsible for + # upgrading. Phase 1 checks the version of the latest release of + # certbot-auto (which is always the same as that of the certbot + # package). Phase 2 checks the version of the locally installed certbot. + + if [ ! -f "$VENV_BIN/letsencrypt" ]; then + if [ "$HELP" = 1 ]; then + echo "$USAGE" + exit 0 + fi + # If it looks like we've never bootstrapped before, bootstrap: + Bootstrap + fi + if [ "$OS_PACKAGES_ONLY" = 1 ]; then + echo "OS packages installed." + exit 0 + fi + + if [ "$NO_SELF_UPGRADE" != 1 ]; then + echo "Checking for new version..." + TEMP_DIR=$(TempDir) + # --------------------------------------------------------------------------- + cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py" +"""Do downloading and JSON parsing without additional dependencies. :: + + # Print latest released version of LE to stdout: + python fetch.py --latest-version + + # Download letsencrypt-auto script from git tag v1.2.3 into the folder I'm + # in, and make sure its signature verifies: + python fetch.py --le-auto-script v1.2.3 + +On failure, return non-zero. + +""" +from distutils.version import LooseVersion +from json import loads +from os import devnull, environ +from os.path import dirname, join +import re +from subprocess import check_call, CalledProcessError +from sys import argv, exit +from urllib2 import build_opener, HTTPHandler, HTTPSHandler, HTTPError + +PUBLIC_KEY = environ.get('LE_AUTO_PUBLIC_KEY', """-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6MR8W/galdxnpGqBsYbq +OzQb2eyW15YFjDDEMI0ZOzt8f504obNs920lDnpPD2/KqgsfjOgw2K7xWDJIj/18 +xUvWPk3LDkrnokNiRkA3KOx3W6fHycKL+zID7zy+xZYBuh2fLyQtWV1VGQ45iNRp +9+Zo7rH86cdfgkdnWTlNSHyTLW9NbXvyv/E12bppPcEvgCTAQXgnDVJ0/sqmeiij +n9tTFh03aM+R2V/21h8aTraAS24qiPCz6gkmYGC8yr6mglcnNoYbsLNYZ69zF1XH +cXPduCPdPdfLlzVlKK1/U7hkA28eG3BIAMh6uJYBRJTpiGgaGdPd7YekUB8S6cy+ +CQIDAQAB +-----END PUBLIC KEY----- +""") + +class ExpectedError(Exception): + """A novice-readable exception that also carries the original exception for + debugging""" + + +class HttpsGetter(object): + def __init__(self): + """Build an HTTPS opener.""" + # Based on pip 1.4.1's URLOpener + # This verifies certs on only Python >=2.7.9. + self._opener = build_opener(HTTPSHandler()) + # Strip out HTTPHandler to prevent MITM spoof: + for handler in self._opener.handlers: + if isinstance(handler, HTTPHandler): + self._opener.handlers.remove(handler) + + def get(self, url): + """Return the document contents pointed to by an HTTPS URL. + + If something goes wrong (404, timeout, etc.), raise ExpectedError. + + """ + try: + return self._opener.open(url).read() + except (HTTPError, IOError) as exc: + raise ExpectedError("Couldn't download %s." % url, exc) + + +def write(contents, dir, filename): + """Write something to a file in a certain directory.""" + with open(join(dir, filename), 'w') as file: + file.write(contents) + + +def latest_stable_version(get): + """Return the latest stable release of letsencrypt.""" + metadata = loads(get( + environ.get('LE_AUTO_JSON_URL', + 'https://pypi.python.org/pypi/letsencrypt/json'))) + # metadata['info']['version'] actually returns the latest of any kind of + # release release, contrary to https://wiki.python.org/moin/PyPIJSON. + # The regex is a sufficient regex for picking out prereleases for most + # packages, LE included. + return str(max(LooseVersion(r) for r + in metadata['releases'].iterkeys() + if re.match('^[0-9.]+$', r))) + + +def verified_new_le_auto(get, tag, temp_dir): + """Return the path to a verified, up-to-date letsencrypt-auto script. + + If the download's signature does not verify or something else goes wrong + with the verification process, raise ExpectedError. + + """ + le_auto_dir = environ.get( + 'LE_AUTO_DIR_TEMPLATE', + 'https://raw.githubusercontent.com/letsencrypt/letsencrypt/%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') + write(PUBLIC_KEY, temp_dir, 'public_key.pem') + try: + with open(devnull, 'w') as dev_null: + check_call(['openssl', 'dgst', '-sha256', '-verify', + join(temp_dir, 'public_key.pem'), + '-signature', + join(temp_dir, 'letsencrypt-auto.sig'), + join(temp_dir, 'letsencrypt-auto')], + stdout=dev_null, + stderr=dev_null) + except CalledProcessError as exc: + raise ExpectedError("Couldn't verify signature of downloaded " + "certbot-auto.", exc) + + +def main(): + get = HttpsGetter().get + flag = argv[1] + try: + if flag == '--latest-version': + print latest_stable_version(get) + elif flag == '--le-auto-script': + tag = argv[2] + verified_new_le_auto(get, tag, dirname(argv[0])) + except ExpectedError as exc: + print exc.args[0], exc.args[1] + return 1 + else: + return 0 + + +if __name__ == '__main__': + exit(main()) + +UNLIKELY_EOF + # --------------------------------------------------------------------------- + DeterminePythonVersion + if ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then + echo "WARNING: unable to check for updates." + elif [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then + echo "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." + + # Now we drop into Python so we don't have to install even more + # dependencies (curl, etc.), for better flow control, and for the option of + # future Windows compatibility. + "$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION" + + # Install new copy of certbot-auto. + # TODO: Deal with quotes in pathnames. + echo "Replacing certbot-auto..." + # Clone permissions with cp. chmod and chown don't have a --reference + # option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD: + $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone" + $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone" + # Using mv rather than cp leaves the old file descriptor pointing to the + # original copy so the shell can continue to read it unmolested. mv across + # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the + # cp is unlikely to fail (esp. under sudo) if the rm doesn't. + $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" + # TODO: Clean up temp dir safely, even if it has quotes in its path. + rm -rf "$TEMP_DIR" + fi # A newer version is available. + fi # Self-upgrading is allowed. + + "$0" --le-auto-phase2 "$@" +fi diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index c62a10f89..ee2e128dd 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0.dev0' +version = '0.6.0' install_requires = [ 'certbot=={0}'.format(version), diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 0e5c27a0a..634092fff 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0.dev0' +version = '0.6.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index a48d62548..84022010b 100644 --- a/certbot/__init__.py +++ b/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '0.6.0.dev0' +__version__ = '0.6.0' diff --git a/letsencrypt-apache/setup.py b/letsencrypt-apache/setup.py index a52044f87..1718cc5b4 100644 --- a/letsencrypt-apache/setup.py +++ b/letsencrypt-apache/setup.py @@ -16,7 +16,7 @@ here = os.path.abspath(os.path.dirname(__file__)) readme = read_file(os.path.join(here, 'README.rst')) -version = '0.6.0.dev0' +version = '0.6.0' # This package is a simple shim around certbot-apache diff --git a/letsencrypt-auto b/letsencrypt-auto index 942fd8ea2..8c6e6c486 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -1,6 +1,6 @@ #!/bin/sh # -# Download and run the latest release version of the Let's Encrypt client. +# Download and run the latest release version of the Certbot client. # # NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING # @@ -19,11 +19,36 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.5.0" +LE_AUTO_VERSION="0.6.0" +BASENAME=$(basename $0) +USAGE="Usage: $BASENAME [OPTIONS] +A self-updating wrapper script for the Certbot ACME client. When run, updates +to both this script and certbot will be downloaded and installed. After +ensuring you have the latest versions installed, certbot will be invoked with +all arguments you have provided. + +Help for certbot itself cannot be provided until it is installed. + + --debug attempt experimental installation + -h, --help print this help + -n, --non-interactive, --noninteractive run without asking for user input + --no-self-upgrade do not download updates + --os-packages-only install OS dependencies and exit + -v, --verbose provide more output + +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 -# This script takes the same arguments as the main letsencrypt program, but it -# additionally responds to --verbose (more output) and --debug (allow support -# for experimental platforms) for arg in "$@" ; do case "$arg" in --debug) @@ -34,25 +59,26 @@ for arg in "$@" ; do # Do not upgrade this script (also prevents client upgrades, because each # copy of the script pins a hash of the python client) NO_SELF_UPGRADE=1;; + --help) + HELP=1;; + --noninteractive|--non-interactive) + ASSUME_YES=1;; --verbose) VERBOSE=1;; - [!-]*|-*[!v]*|-) - # Anything that isn't -v, -vv, etc.: that is, anything that does not - # start with a -, contains anything that's not a v, or is just "-" - ;; - *) # -v+ remains. - VERBOSE=1;; esac done -# letsencrypt-auto needs root access to bootstrap OS dependencies, and -# letsencrypt itself needs root access for almost all modes of operation +# 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 # this script *can* be run as root (not recommended), or fall back to using # `su` +SUDO_ENV="" +export CERTBOT_AUTO="$0" if test "`id -u`" -ne "0" ; then if command -v sudo 1>/dev/null 2>&1; then SUDO=sudo + SUDO_ENV="CERTBOT_AUTO=$0" else echo \"sudo\" is not available, will use \"su\" for installation steps... # Because the parameters in `su -c` has to be a string, @@ -81,6 +107,12 @@ 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 @@ -151,30 +183,45 @@ BootstrapDebCommon() { augeas_pkg="libaugeas0 augeas-lenses" AUGVERSION=`apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2` + if [ "$ASSUME_YES" = 1 ]; then + YES_FLAG="-y" + fi + AddBackportRepo() { # ARGS: BACKPORT_NAME="$1" BACKPORT_SOURCELINE="$2" + echo "To use the Apache Certbot plugin, augeas needs to be installed from $BACKPORT_NAME." if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then # This can theoretically error if sources.list.d is empty, but in that case we don't care. if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then - /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." - sleep 1s - /bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..." - sleep 1s - /bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..." - sleep 1s - if echo $BACKPORT_NAME | grep -q wheezy ; then - /bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")' + if [ "$ASSUME_YES" = 1 ]; then + /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." + sleep 1s + /bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..." + sleep 1s + /bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..." + sleep 1s + add_backports=1 + else + read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response + case $response in + [yY][eE][sS]|[yY]|"") + add_backports=1;; + *) + add_backports=0;; + esac + fi + if [ "$add_backports" = 1 ]; then + $SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list" + $SUDO apt-get update fi - - $SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list" - $SUDO apt-get update fi fi - $SUDO apt-get install -y --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg - augeas_pkg= - + if [ "$add_backports" != 0 ]; then + $SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg + augeas_pkg= + fi } @@ -186,12 +233,12 @@ BootstrapDebCommon() { AddBackportRepo precise-backports "deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse" else echo "No libaugeas0 version is available that's new enough to run the" - echo "Let's Encrypt apache plugin..." + echo "Certbot apache plugin..." fi # XXX add a case for ubuntu PPAs fi - $SUDO apt-get install -y --no-install-recommends \ + $SUDO apt-get install $YES_FLAG --no-install-recommends \ python \ python-dev \ $virtualenv \ @@ -212,9 +259,10 @@ BootstrapDebCommon() { BootstrapRpmCommon() { # Tested with: - # - Fedora 22, 23 (x64) + # - Fedora 20, 21, 22, 23 (x64) # - Centos 7 (x64: on DigitalOcean droplet) # - CentOS 7 Minimal install in a Hyper-V VM + # - CentOS 6 (EPEL must be installed manually) if type dnf 2>/dev/null then @@ -228,54 +276,62 @@ BootstrapRpmCommon() { exit 1 fi + pkgs=" + gcc + dialog + augeas-libs + openssl + openssl-devel + libffi-devel + redhat-rpm-config + ca-certificates + " + # Some distros and older versions of current distros use a "python27" # instead of "python" naming convention. Try both conventions. - if ! $SUDO $tool install -y \ - python \ - python-devel \ - python-virtualenv \ - python-tools \ - python-pip - then - if ! $SUDO $tool install -y \ - python27 \ - python27-devel \ - python27-virtualenv \ - python27-tools \ - python27-pip - then - echo "Could not install Python dependencies. Aborting bootstrap!" - exit 1 - fi + if $SUDO $tool list python >/dev/null 2>&1; then + pkgs="$pkgs + python + python-devel + python-virtualenv + python-tools + python-pip + " + else + pkgs="$pkgs + python27 + python27-devel + python27-virtualenv + python27-tools + python27-pip + " fi - if ! $SUDO $tool install -y \ - gcc \ - dialog \ - augeas-libs \ - openssl \ - openssl-devel \ - libffi-devel \ - redhat-rpm-config \ - ca-certificates - then - echo "Could not install additional dependencies. Aborting bootstrap!" - exit 1 - fi - - if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then - if ! $SUDO $tool install -y mod_ssl - then - echo "Apache found, but mod_ssl could not be installed." - fi + pkgs="$pkgs + mod_ssl + " + fi + + if [ "$ASSUME_YES" = 1 ]; then + yes_flag="-y" + fi + + if ! $SUDO $tool install $yes_flag $pkgs; then + echo "Could not install OS dependencies. Aborting bootstrap!" + exit 1 fi } BootstrapSuseCommon() { # SLE12 don't have python-virtualenv - $SUDO zypper -nq in -l \ + if [ "$ASSUME_YES" = 1 ]; then + zypper_flags="-nq" + install_flags="-l" + fi + + $SUDO zypper $zypper_flags in $install_flags \ python \ python-devel \ python-virtualenv \ @@ -310,8 +366,12 @@ BootstrapArchCommon() { # pacman -T exits with 127 if there are missing dependencies missing=$($SUDO pacman -T $deps) || true + if [ "$ASSUME_YES" = 1 ]; then + noconfirm="--noconfirm" + fi + if [ "$missing" ]; then - $SUDO pacman -S --needed $missing + $SUDO pacman -S --needed $missing $noconfirm fi } @@ -426,7 +486,7 @@ Bootstrap() { elif grep -iq "Amazon Linux" /etc/issue ; then ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon else - echo "Sorry, I don't know how to bootstrap Let's Encrypt on your operating system!" + echo "Sorry, I don't know how to bootstrap Certbot on your operating system!" echo echo "You will need to bootstrap, configure virtualenv, and run pip install manually." echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" @@ -446,7 +506,8 @@ if [ "$1" = "--le-auto-phase2" ]; then shift 1 # the --le-auto-phase2 arg if [ -f "$VENV_BIN/letsencrypt" ]; then # --version output ran through grep due to python-cryptography DeprecationWarnings - INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep ^letsencrypt | cut -d " " -f 2) + # grep for both certbot and letsencrypt until certbot and shim packages have been released + INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2) else INSTALLED_VERSION="none" fi @@ -465,8 +526,8 @@ if [ "$1" = "--le-auto-phase2" ]; then # There is no $ interpolation due to quotes on starting heredoc delimiter. # ------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt" -# This is the flattened list of packages letsencrypt-auto installs. To generate -# this, do `pip install --no-cache-dir -e acme -e . -e letsencrypt-apache`, and +# This is the flattened list of packages certbot-auto installs. To generate +# this, do `pip install --no-cache-dir -e acme -e . -e certbot-apache`, and # then use `hashin` or a more secure method to gather the hashes. argparse==1.4.0 \ @@ -645,15 +706,21 @@ mock==1.0.1 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.5.0 \ - --hash=sha256:ceb4127c13213f0006a564be82176b968c6b374d20d9fc78555d0658a252b275 \ - --hash=sha256:0605c63c656d33c883a05675f5db9cfb85d503f2771c885031800e0da7631abd -letsencrypt==0.5.0 \ - --hash=sha256:f90f883e99cdbdf8142335bdbf4f74a8af143ee4b4ec60fb49c6e47418c1114c \ - --hash=sha256:e38a2b70b82be79bc195307652244a3e012ec73d897d4dbd3f80cf698496d15a -letsencrypt-apache==0.5.0 \ - --hash=sha256:a767882164a7b09d9c12c80684a28a782135fdaf35654ef5a02c0b7b1d27ab8d \ - --hash=sha256:c20e7b9c517aa4a7d70e6bd9382da7259f00bc191b9e60d8e312e48837a00c41 +acme==0.6.0 \ + --hash=sha256:cbe4e7a340a19725a8740ed86e30abdbe18fc22c4c6022b7a8e56642d502bcc3 \ + --hash=sha256:ec4e6009dfbd629b58473eb06bbebfd9fb2a79fc8831c149e9205bc38a98ecc6 +certbot==0.6.0 \ + --hash=sha256:a893632d228864b0a751db9f3fdd93439ed34b988ea21b64fb0f0fa2ceded6a2 \ + --hash=sha256:80b0b7dc5afeec2816ef638a61e7c628d73cd72666eebf4984be426d1c2b492d +certbot-apache==0.6.0 \ + --hash=sha256:0ab077f0913b81ed5c1b141c3a7c4c0228ef3738d8d61a93db794d9a80718d43 \ + --hash=sha256:1cfbe751209079a803758f472200816fac559f2a36fdd582d25e3ba5601423a1 +letsencrypt==0.6.0 \ + --hash=sha256:93196c7dcd57272a753e525d145c5a9987c8968c22ec954bcf83dcc9d2499a76 \ + --hash=sha256:a16d6c395f1bf5fd61a28ef83dc78f42dbecbad9d00be6236f2ad8915645c154 +letsencrypt-apache==0.6.0 \ + --hash=sha256:02fadc52a0796e53978c508beec9c53e1fc047660240832b9bde5d53ab3a1379 \ + --hash=sha256:1c5522d94d7750bdb9bfa6201d2c263e914f662c9d0079e673167233cf4364f1 UNLIKELY_EOF # ------------------------------------------------------------------------- @@ -823,18 +890,30 @@ UNLIKELY_EOF fi echo "Installation succeeded." fi - echo "Requesting root privileges to run letsencrypt..." - echo " " $SUDO "$VENV_BIN/letsencrypt" "$@" - $SUDO "$VENV_BIN/letsencrypt" "$@" + echo "Requesting root privileges to run certbot..." + 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 + else - # Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke. + # Phase 1: Upgrade certbot-auto if neceesary, then self-invoke. # # Each phase checks the version of only the thing it is responsible for # upgrading. Phase 1 checks the version of the latest release of - # letsencrypt-auto (which is always the same as that of the letsencrypt - # package). Phase 2 checks the version of the locally installed letsencrypt. + # certbot-auto (which is always the same as that of the certbot + # package). Phase 2 checks the version of the locally installed certbot. if [ ! -f "$VENV_BIN/letsencrypt" ]; then + if [ "$HELP" = 1 ]; then + echo "$USAGE" + exit 0 + fi # If it looks like we've never bootstrapped before, bootstrap: Bootstrap fi @@ -953,7 +1032,7 @@ def verified_new_le_auto(get, tag, temp_dir): stderr=dev_null) except CalledProcessError as exc: raise ExpectedError("Couldn't verify signature of downloaded " - "letsencrypt-auto.", exc) + "certbot-auto.", exc) def main(): @@ -978,29 +1057,27 @@ if __name__ == '__main__': UNLIKELY_EOF # --------------------------------------------------------------------------- DeterminePythonVersion - REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` - if [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then - echo "Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." + if ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then + echo "WARNING: unable to check for updates." + elif [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then + echo "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." # Now we drop into Python so we don't have to install even more # dependencies (curl, etc.), for better flow control, and for the option of # future Windows compatibility. "$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION" - # Install new copy of letsencrypt-auto. + # Install new copy of certbot-auto. # TODO: Deal with quotes in pathnames. - echo "Replacing letsencrypt-auto..." + echo "Replacing certbot-auto..." # Clone permissions with cp. chmod and chown don't have a --reference # option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD: - echo " " $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone" $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone" - echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone" $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone" # Using mv rather than cp leaves the old file descriptor pointing to the # original copy so the shell can continue to read it unmolested. mv across # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the # cp is unlikely to fail (esp. under sudo) if the rm doesn't. - echo " " $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" # TODO: Clean up temp dir safely, even if it has quotes in its path. rm -rf "$TEMP_DIR" diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc new file mode 100644 index 000000000..8b4f34c70 --- /dev/null +++ b/letsencrypt-auto-source/certbot-auto.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1 + +iQEcBAABAgAGBQJXM9ZDAAoJEE0XyZXNl3XyzGkH/2KeR0jYxXKlvwfCkxU6hSC0 +eXcxZVQk59hCSvkNGE6Mj6rwQcyjSqmRp14MaJpq7NZADN6F+HWb6VB/Wq6moMQs +PJtthqwhF767Qg+Py9Hp6XmlKscjXB6AKCVxq5TBwEIOTtj0rhQRLF9/+GW6jFuf +kT6aUcDWNjOyWWUtp9vOVprDtegrltp0/2DNitlvPu263pKC+7I3GyLTq4fKP4EE +auZSAhFry9SNR3Usf2wD3kzhvLSrT3h9Yh5oA04oaX9H6e86EHwt6RJJRHpg8s6b +e0CBIIuaRJEmdiMUWlV/gAfH6M2PbG1wtJdxc0ThNEoWAjTsopr61BoHJ3cpCy4= +=+e7/ +-----END PGP SIGNATURE----- diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 8578feef2..8c6e6c486 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.6.0.dev0" +LE_AUTO_VERSION="0.6.0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -706,15 +706,21 @@ mock==1.0.1 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.5.0 \ - --hash=sha256:ceb4127c13213f0006a564be82176b968c6b374d20d9fc78555d0658a252b275 \ - --hash=sha256:0605c63c656d33c883a05675f5db9cfb85d503f2771c885031800e0da7631abd -letsencrypt==0.5.0 \ - --hash=sha256:f90f883e99cdbdf8142335bdbf4f74a8af143ee4b4ec60fb49c6e47418c1114c \ - --hash=sha256:e38a2b70b82be79bc195307652244a3e012ec73d897d4dbd3f80cf698496d15a -letsencrypt-apache==0.5.0 \ - --hash=sha256:a767882164a7b09d9c12c80684a28a782135fdaf35654ef5a02c0b7b1d27ab8d \ - --hash=sha256:c20e7b9c517aa4a7d70e6bd9382da7259f00bc191b9e60d8e312e48837a00c41 +acme==0.6.0 \ + --hash=sha256:cbe4e7a340a19725a8740ed86e30abdbe18fc22c4c6022b7a8e56642d502bcc3 \ + --hash=sha256:ec4e6009dfbd629b58473eb06bbebfd9fb2a79fc8831c149e9205bc38a98ecc6 +certbot==0.6.0 \ + --hash=sha256:a893632d228864b0a751db9f3fdd93439ed34b988ea21b64fb0f0fa2ceded6a2 \ + --hash=sha256:80b0b7dc5afeec2816ef638a61e7c628d73cd72666eebf4984be426d1c2b492d +certbot-apache==0.6.0 \ + --hash=sha256:0ab077f0913b81ed5c1b141c3a7c4c0228ef3738d8d61a93db794d9a80718d43 \ + --hash=sha256:1cfbe751209079a803758f472200816fac559f2a36fdd582d25e3ba5601423a1 +letsencrypt==0.6.0 \ + --hash=sha256:93196c7dcd57272a753e525d145c5a9987c8968c22ec954bcf83dcc9d2499a76 \ + --hash=sha256:a16d6c395f1bf5fd61a28ef83dc78f42dbecbad9d00be6236f2ad8915645c154 +letsencrypt-apache==0.6.0 \ + --hash=sha256:02fadc52a0796e53978c508beec9c53e1fc047660240832b9bde5d53ab3a1379 \ + --hash=sha256:1c5522d94d7750bdb9bfa6201d2c263e914f662c9d0079e673167233cf4364f1 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/letsencrypt-auto.sig b/letsencrypt-auto-source/letsencrypt-auto.sig index 36ab206aa47ee8d6348340e2e17e66ef840f4832..cb360f89ef5443af2c6bc157704a98d3cd68fcef 100644 GIT binary patch literal 256 zcmV+b0ssCk`Do-WYWlUAhmM)Jao($YX$9Q(cRVv8_jtP0o}fz5%~*%F!qFPG{FHTs zO#Q7Ny@?Hph=ylMIohpY9^{Zmm8Bm3`9U?K3CDJ~iXxyHmSNf`Uq7cCyf|^Mc+2uA z+A^~xvGqM}C5Xzw8cyZq9H=SydJxxr0AB GYGOMK)`FS< literal 256 zcmV+b0ssCNAlb`yp8ViHw_s6WQdeQ~rmeR1#f`~|;Lcvp1i>?dOn)2S?|UXU3-X4k zaZ%*t!KjDe7yUlErpaEi6!y=8HI`DRz)EuS7bCS?0nWEvmfo;6rg zd*P;)T`MMf6qh)Nq~anD`EcT+-{;e}X{!NGWzN5f-uFVW&D40h!-VgVXfn*mr{?;Y4vJd_;=@v>g=fCE0&HR8N!p!aAH z8#Erxi1sEj2Zdym%<&YjXJ9%;%Y|e9?#~icJ0k#V&W79xyG>~1A}+~ diff --git a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt index 3a1ce34f1..f4ceae536 100644 --- a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt +++ b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt @@ -178,12 +178,18 @@ mock==1.0.1 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.5.0 \ - --hash=sha256:ceb4127c13213f0006a564be82176b968c6b374d20d9fc78555d0658a252b275 \ - --hash=sha256:0605c63c656d33c883a05675f5db9cfb85d503f2771c885031800e0da7631abd -letsencrypt==0.5.0 \ - --hash=sha256:f90f883e99cdbdf8142335bdbf4f74a8af143ee4b4ec60fb49c6e47418c1114c \ - --hash=sha256:e38a2b70b82be79bc195307652244a3e012ec73d897d4dbd3f80cf698496d15a -letsencrypt-apache==0.5.0 \ - --hash=sha256:a767882164a7b09d9c12c80684a28a782135fdaf35654ef5a02c0b7b1d27ab8d \ - --hash=sha256:c20e7b9c517aa4a7d70e6bd9382da7259f00bc191b9e60d8e312e48837a00c41 +acme==0.6.0 \ + --hash=sha256:cbe4e7a340a19725a8740ed86e30abdbe18fc22c4c6022b7a8e56642d502bcc3 \ + --hash=sha256:ec4e6009dfbd629b58473eb06bbebfd9fb2a79fc8831c149e9205bc38a98ecc6 +certbot==0.6.0 \ + --hash=sha256:a893632d228864b0a751db9f3fdd93439ed34b988ea21b64fb0f0fa2ceded6a2 \ + --hash=sha256:80b0b7dc5afeec2816ef638a61e7c628d73cd72666eebf4984be426d1c2b492d +certbot-apache==0.6.0 \ + --hash=sha256:0ab077f0913b81ed5c1b141c3a7c4c0228ef3738d8d61a93db794d9a80718d43 \ + --hash=sha256:1cfbe751209079a803758f472200816fac559f2a36fdd582d25e3ba5601423a1 +letsencrypt==0.6.0 \ + --hash=sha256:93196c7dcd57272a753e525d145c5a9987c8968c22ec954bcf83dcc9d2499a76 \ + --hash=sha256:a16d6c395f1bf5fd61a28ef83dc78f42dbecbad9d00be6236f2ad8915645c154 +letsencrypt-apache==0.6.0 \ + --hash=sha256:02fadc52a0796e53978c508beec9c53e1fc047660240832b9bde5d53ab3a1379 \ + --hash=sha256:1c5522d94d7750bdb9bfa6201d2c263e914f662c9d0079e673167233cf4364f1 diff --git a/letsencrypt-nginx/setup.py b/letsencrypt-nginx/setup.py index b94b7f69f..12578cc18 100644 --- a/letsencrypt-nginx/setup.py +++ b/letsencrypt-nginx/setup.py @@ -16,7 +16,7 @@ here = os.path.abspath(os.path.dirname(__file__)) readme = read_file(os.path.join(here, 'README.rst')) -version = '0.6.0.dev0' +version = '0.6.0' # This package is a simple shim around certbot-nginx diff --git a/letsencrypt/setup.py b/letsencrypt/setup.py index 708c31f4b..d30146621 100644 --- a/letsencrypt/setup.py +++ b/letsencrypt/setup.py @@ -20,7 +20,7 @@ readme = read_file(os.path.join(here, 'README.rst')) install_requires = ['certbot'] -version = '0.6.0.dev0' +version = '0.6.0' setup( diff --git a/letshelp-certbot/setup.py b/letshelp-certbot/setup.py index 8359d2766..8c302472a 100644 --- a/letshelp-certbot/setup.py +++ b/letshelp-certbot/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0.dev0' +version = '0.6.0' install_requires = [ 'setuptools', # pkg_resources diff --git a/letshelp-letsencrypt/setup.py b/letshelp-letsencrypt/setup.py index 875c6fc92..bc4141513 100644 --- a/letshelp-letsencrypt/setup.py +++ b/letshelp-letsencrypt/setup.py @@ -16,7 +16,7 @@ here = os.path.abspath(os.path.dirname(__file__)) readme = read_file(os.path.join(here, 'README.rst')) -version = '0.6.0.dev0' +version = '0.6.0' # This package is a simple shim around letshelp-certbot From c8cf0b460045c9853136d74772c4235817c1d1e4 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 11 May 2016 18:04:27 -0700 Subject: [PATCH 093/186] Bump version to 0.7.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-compatibility-test/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/__init__.py | 2 +- letsencrypt-apache/setup.py | 2 +- letsencrypt-auto-source/letsencrypt-auto | 2 +- letsencrypt-nginx/setup.py | 2 +- letsencrypt/setup.py | 2 +- letshelp-certbot/setup.py | 2 +- letshelp-letsencrypt/setup.py | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 20c7c7226..d38864dc1 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0' +version = '0.7.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 538a68139..56c6a451d 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0' +version = '0.7.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index ee2e128dd..8f9452c5a 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0' +version = '0.7.0.dev0' install_requires = [ 'certbot=={0}'.format(version), diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 634092fff..a74b93093 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0' +version = '0.7.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index 84022010b..85f370e7a 100644 --- a/certbot/__init__.py +++ b/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '0.6.0' +__version__ = '0.7.0.dev0' diff --git a/letsencrypt-apache/setup.py b/letsencrypt-apache/setup.py index 1718cc5b4..b94746150 100644 --- a/letsencrypt-apache/setup.py +++ b/letsencrypt-apache/setup.py @@ -16,7 +16,7 @@ here = os.path.abspath(os.path.dirname(__file__)) readme = read_file(os.path.join(here, 'README.rst')) -version = '0.6.0' +version = '0.7.0.dev0' # This package is a simple shim around certbot-apache diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 8c6e6c486..b255a99a7 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.6.0" +LE_AUTO_VERSION="0.7.0.dev0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates diff --git a/letsencrypt-nginx/setup.py b/letsencrypt-nginx/setup.py index 12578cc18..95ffd6cd8 100644 --- a/letsencrypt-nginx/setup.py +++ b/letsencrypt-nginx/setup.py @@ -16,7 +16,7 @@ here = os.path.abspath(os.path.dirname(__file__)) readme = read_file(os.path.join(here, 'README.rst')) -version = '0.6.0' +version = '0.7.0.dev0' # This package is a simple shim around certbot-nginx diff --git a/letsencrypt/setup.py b/letsencrypt/setup.py index d30146621..7c974ea9b 100644 --- a/letsencrypt/setup.py +++ b/letsencrypt/setup.py @@ -20,7 +20,7 @@ readme = read_file(os.path.join(here, 'README.rst')) install_requires = ['certbot'] -version = '0.6.0' +version = '0.7.0.dev0' setup( diff --git a/letshelp-certbot/setup.py b/letshelp-certbot/setup.py index 8c302472a..b616da688 100644 --- a/letshelp-certbot/setup.py +++ b/letshelp-certbot/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.6.0' +version = '0.7.0.dev0' install_requires = [ 'setuptools', # pkg_resources diff --git a/letshelp-letsencrypt/setup.py b/letshelp-letsencrypt/setup.py index bc4141513..10380c49b 100644 --- a/letshelp-letsencrypt/setup.py +++ b/letshelp-letsencrypt/setup.py @@ -16,7 +16,7 @@ here = os.path.abspath(os.path.dirname(__file__)) readme = read_file(os.path.join(here, 'README.rst')) -version = '0.6.0' +version = '0.7.0.dev0' # This package is a simple shim around letshelp-certbot From f53f4dd4913b1dbfd82d34e05927d91cf228d56f Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 12 May 2016 09:30:45 -0700 Subject: [PATCH 094/186] fix docs copyright --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index b2b31ac5d..e387e1eae 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -65,7 +65,7 @@ master_doc = 'index' # General information about the project. project = u'Certbot' -copyright = u'2014-2016, Certbot Project' +copyright = u'2014-2016 - The Certbot software and documentation are licensed under the Apache 2.0 license as described at https://eff.org/cb-license ' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the From 0d5c1638e72d6a9e347cbcdfd1baf58df83fab6e Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 12 May 2016 10:06:11 -0700 Subject: [PATCH 095/186] add certbot-auto and PGP sig --- certbot-auto | 1011 ++++++++++++++++++++++ letsencrypt-auto-source/certbot-auto.asc | 11 + 2 files changed, 1022 insertions(+) create mode 100755 certbot-auto create mode 100644 letsencrypt-auto-source/certbot-auto.asc diff --git a/certbot-auto b/certbot-auto new file mode 100755 index 000000000..942fd8ea2 --- /dev/null +++ b/certbot-auto @@ -0,0 +1,1011 @@ +#!/bin/sh +# +# Download and run the latest release version of the Let's Encrypt client. +# +# NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING +# +# IF YOU WANT TO EDIT IT LOCALLY, *ALWAYS* RUN YOUR COPY WITH THE +# "--no-self-upgrade" FLAG +# +# IF YOU WANT TO SEND PULL REQUESTS, THE REAL SOURCE FOR THIS FILE IS +# letsencrypt-auto-source/letsencrypt-auto.template AND +# letsencrypt-auto-source/pieces/bootstrappers/* + +set -e # Work even if somebody does "sh thisscript.sh". + +# Note: you can set XDG_DATA_HOME or VENV_PATH before running this script, +# if you want to change where the virtual environment will be installed +XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} +VENV_NAME="letsencrypt" +VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} +VENV_BIN="$VENV_PATH/bin" +LE_AUTO_VERSION="0.5.0" + +# This script takes the same arguments as the main letsencrypt program, but it +# additionally responds to --verbose (more output) and --debug (allow support +# for experimental platforms) +for arg in "$@" ; do + case "$arg" in + --debug) + DEBUG=1;; + --os-packages-only) + OS_PACKAGES_ONLY=1;; + --no-self-upgrade) + # Do not upgrade this script (also prevents client upgrades, because each + # copy of the script pins a hash of the python client) + NO_SELF_UPGRADE=1;; + --verbose) + VERBOSE=1;; + [!-]*|-*[!v]*|-) + # Anything that isn't -v, -vv, etc.: that is, anything that does not + # start with a -, contains anything that's not a v, or is just "-" + ;; + *) # -v+ remains. + VERBOSE=1;; + esac +done + +# letsencrypt-auto needs root access to bootstrap OS dependencies, and +# letsencrypt 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 +# this script *can* be run as root (not recommended), or fall back to using +# `su` +if test "`id -u`" -ne "0" ; then + if command -v sudo 1>/dev/null 2>&1; then + SUDO=sudo + else + echo \"sudo\" is not available, will use \"su\" for installation steps... + # Because the parameters in `su -c` has to be a string, + # we need properly escape it + su_sudo() { + args="" + # This `while` loop iterates over all parameters given to this function. + # For each parameter, all `'` will be replace by `'"'"'`, and the escaped string + # will be wrapped in a pair of `'`, then appended to `$args` string + # For example, `echo "It's only 1\$\!"` will be escaped to: + # 'echo' 'It'"'"'s only 1$!' + # │ │└┼┘│ + # │ │ │ └── `'s only 1$!'` the literal string + # │ │ └── `\"'\"` is a single quote (as a string) + # │ └── `'It'`, to be concatenated with the strings following it + # └── `echo` wrapped in a pair of `'`, it's totally fine for the shell command itself + while [ $# -ne 0 ]; do + args="$args'$(printf "%s" "$1" | sed -e "s/'/'\"'\"'/g")' " + shift + done + su root -c "$args" + } + SUDO=su_sudo + fi +else + SUDO= +fi + +ExperimentalBootstrap() { + # Arguments: Platform name, bootstrap function name + if [ "$DEBUG" = 1 ]; then + if [ "$2" != "" ]; then + echo "Bootstrapping dependencies via $1..." + $2 + fi + else + echo "WARNING: $1 support is very experimental at present..." + echo "if you would like to work on improving it, please ensure you have backups" + echo "and then run this script again with the --debug flag!" + exit 1 + fi +} + +DeterminePythonVersion() { + for LE_PYTHON in "$LE_PYTHON" python2.7 python27 python2 python; do + # Break (while keeping the LE_PYTHON value) if found. + command -v "$LE_PYTHON" > /dev/null && break + done + if [ "$?" != "0" ]; then + echo "Cannot find any Pythons; please install one!" + exit 1 + fi + export LE_PYTHON + + PYVER=`"$LE_PYTHON" -V 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | sed 's/\.//'` + if [ "$PYVER" -lt 26 ]; then + echo "You have an ancient version of Python entombed in your operating system..." + echo "This isn't going to work; you'll need at least version 2.6." + exit 1 + fi +} + +BootstrapDebCommon() { + # Current version tested with: + # + # - Ubuntu + # - 14.04 (x64) + # - 15.04 (x64) + # - Debian + # - 7.9 "wheezy" (x64) + # - sid (2015-10-21) (x64) + + # Past versions tested with: + # + # - Debian 8.0 "jessie" (x64) + # - Raspbian 7.8 (armhf) + + # Believed not to work: + # + # - Debian 6.0.10 "squeeze" (x64) + + $SUDO apt-get update || echo apt-get update hit problems but continuing anyway... + + # virtualenv binary can be found in different packages depending on + # distro version (#346) + + virtualenv= + if apt-cache show virtualenv > /dev/null 2>&1; then + virtualenv="virtualenv" + fi + + if apt-cache show python-virtualenv > /dev/null 2>&1; then + virtualenv="$virtualenv python-virtualenv" + fi + + augeas_pkg="libaugeas0 augeas-lenses" + AUGVERSION=`apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2` + + AddBackportRepo() { + # ARGS: + BACKPORT_NAME="$1" + BACKPORT_SOURCELINE="$2" + if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then + # This can theoretically error if sources.list.d is empty, but in that case we don't care. + if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then + /bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..." + sleep 1s + /bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..." + sleep 1s + /bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..." + sleep 1s + if echo $BACKPORT_NAME | grep -q wheezy ; then + /bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")' + fi + + $SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list" + $SUDO apt-get update + fi + fi + $SUDO apt-get install -y --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg + augeas_pkg= + + } + + + if dpkg --compare-versions 1.0 gt "$AUGVERSION" ; then + if lsb_release -a | grep -q wheezy ; then + AddBackportRepo wheezy-backports "deb http://http.debian.net/debian wheezy-backports main" + elif lsb_release -a | grep -q precise ; then + # XXX add ARM case + AddBackportRepo precise-backports "deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse" + else + echo "No libaugeas0 version is available that's new enough to run the" + echo "Let's Encrypt apache plugin..." + fi + # XXX add a case for ubuntu PPAs + fi + + $SUDO apt-get install -y --no-install-recommends \ + python \ + python-dev \ + $virtualenv \ + gcc \ + dialog \ + $augeas_pkg \ + libssl-dev \ + libffi-dev \ + ca-certificates \ + + + + if ! command -v virtualenv > /dev/null ; then + echo Failed to install a working \"virtualenv\" command, exiting + exit 1 + fi +} + +BootstrapRpmCommon() { + # Tested with: + # - Fedora 22, 23 (x64) + # - Centos 7 (x64: on DigitalOcean droplet) + # - CentOS 7 Minimal install in a Hyper-V VM + + if type dnf 2>/dev/null + then + tool=dnf + elif type yum 2>/dev/null + then + tool=yum + + else + echo "Neither yum nor dnf found. Aborting bootstrap!" + exit 1 + fi + + # Some distros and older versions of current distros use a "python27" + # instead of "python" naming convention. Try both conventions. + if ! $SUDO $tool install -y \ + python \ + python-devel \ + python-virtualenv \ + python-tools \ + python-pip + then + if ! $SUDO $tool install -y \ + python27 \ + python27-devel \ + python27-virtualenv \ + python27-tools \ + python27-pip + then + echo "Could not install Python dependencies. Aborting bootstrap!" + exit 1 + fi + fi + + if ! $SUDO $tool install -y \ + gcc \ + dialog \ + augeas-libs \ + openssl \ + openssl-devel \ + libffi-devel \ + redhat-rpm-config \ + ca-certificates + then + echo "Could not install additional dependencies. Aborting bootstrap!" + exit 1 + fi + + + if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then + if ! $SUDO $tool install -y mod_ssl + then + echo "Apache found, but mod_ssl could not be installed." + fi + fi +} + +BootstrapSuseCommon() { + # SLE12 don't have python-virtualenv + + $SUDO zypper -nq in -l \ + python \ + python-devel \ + python-virtualenv \ + gcc \ + dialog \ + augeas-lenses \ + libopenssl-devel \ + libffi-devel \ + ca-certificates +} + +BootstrapArchCommon() { + # Tested with: + # - ArchLinux (x86_64) + # + # "python-virtualenv" is Python3, but "python2-virtualenv" provides + # only "virtualenv2" binary, not "virtualenv" necessary in + # ./tools/_venv_common.sh + + deps=" + python2 + python-virtualenv + gcc + dialog + augeas + openssl + libffi + ca-certificates + pkg-config + " + + # pacman -T exits with 127 if there are missing dependencies + missing=$($SUDO pacman -T $deps) || true + + if [ "$missing" ]; then + $SUDO pacman -S --needed $missing + fi +} + +BootstrapGentooCommon() { + PACKAGES=" + dev-lang/python:2.7 + dev-python/virtualenv + dev-util/dialog + app-admin/augeas + dev-libs/openssl + dev-libs/libffi + app-misc/ca-certificates + virtual/pkgconfig" + + case "$PACKAGE_MANAGER" in + (paludis) + $SUDO cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x + ;; + (pkgcore) + $SUDO pmerge --noreplace --oneshot $PACKAGES + ;; + (portage|*) + $SUDO emerge --noreplace --oneshot $PACKAGES + ;; + esac +} + +BootstrapFreeBsd() { + $SUDO pkg install -Ay \ + python \ + py27-virtualenv \ + augeas \ + libffi +} + +BootstrapMac() { + if hash brew 2>/dev/null; then + echo "Using Homebrew to install dependencies..." + pkgman=brew + pkgcmd="brew install" + elif hash port 2>/dev/null; then + echo "Using MacPorts to install dependencies..." + pkgman=port + pkgcmd="$SUDO port install" + else + echo "No Homebrew/MacPorts; installing Homebrew..." + ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + pkgman=brew + pkgcmd="brew install" + fi + + $pkgcmd augeas + $pkgcmd dialog + if [ "$(which python)" = "/System/Library/Frameworks/Python.framework/Versions/2.7/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..." + $pkgcmd python + fi + + # 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 + fi + + if ! hash pip 2>/dev/null; then + echo "pip not installed" + echo "Installing pip..." + curl --silent --show-error --retry 5 https://bootstrap.pypa.io/get-pip.py | python + fi + + if ! hash virtualenv 2>/dev/null; then + echo "virtualenv not installed." + echo "Installing with pip..." + pip install virtualenv + fi +} + + +# Install required OS packages: +Bootstrap() { + if [ -f /etc/debian_version ]; then + echo "Bootstrapping dependencies for Debian-based OSes..." + BootstrapDebCommon + elif [ -f /etc/redhat-release ]; then + echo "Bootstrapping dependencies for RedHat-based OSes..." + BootstrapRpmCommon + elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then + echo "Bootstrapping dependencies for openSUSE-based OSes..." + BootstrapSuseCommon + elif [ -f /etc/arch-release ]; then + if [ "$DEBUG" = 1 ]; then + echo "Bootstrapping dependencies for Archlinux..." + BootstrapArchCommon + else + echo "Please use pacman to install letsencrypt packages:" + echo "# pacman -S letsencrypt letsencrypt-apache" + echo + echo "If you would like to use the virtualenv way, please run the script again with the" + echo "--debug flag." + exit 1 + fi + elif [ -f /etc/manjaro-release ]; then + ExperimentalBootstrap "Manjaro Linux" BootstrapArchCommon + elif [ -f /etc/gentoo-release ]; then + ExperimentalBootstrap "Gentoo" BootstrapGentooCommon + elif uname | grep -iq FreeBSD ; then + ExperimentalBootstrap "FreeBSD" BootstrapFreeBsd + elif uname | grep -iq Darwin ; then + ExperimentalBootstrap "Mac OS X" BootstrapMac + elif grep -iq "Amazon Linux" /etc/issue ; then + ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon + else + echo "Sorry, I don't know how to bootstrap Let's Encrypt on your operating system!" + echo + echo "You will need to bootstrap, configure virtualenv, and run pip install manually." + echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" + echo "for more info." + fi +} + +TempDir() { + mktemp -d 2>/dev/null || mktemp -d -t 'le' # Linux || OS X +} + + + +if [ "$1" = "--le-auto-phase2" ]; then + # Phase 2: Create venv, install LE, and run. + + shift 1 # the --le-auto-phase2 arg + if [ -f "$VENV_BIN/letsencrypt" ]; then + # --version output ran through grep due to python-cryptography DeprecationWarnings + INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep ^letsencrypt | cut -d " " -f 2) + else + INSTALLED_VERSION="none" + fi + if [ "$LE_AUTO_VERSION" != "$INSTALLED_VERSION" ]; then + echo "Creating virtual environment..." + DeterminePythonVersion + rm -rf "$VENV_PATH" + if [ "$VERBOSE" = 1 ]; then + virtualenv --no-site-packages --python "$LE_PYTHON" "$VENV_PATH" + else + virtualenv --no-site-packages --python "$LE_PYTHON" "$VENV_PATH" > /dev/null + fi + + echo "Installing Python packages..." + TEMP_DIR=$(TempDir) + # There is no $ interpolation due to quotes on starting heredoc delimiter. + # ------------------------------------------------------------------------- + cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt" +# This is the flattened list of packages letsencrypt-auto installs. To generate +# this, do `pip install --no-cache-dir -e acme -e . -e letsencrypt-apache`, and +# then use `hashin` or a more secure method to gather the hashes. + +argparse==1.4.0 \ + --hash=sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314 \ + --hash=sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4 + +# This comes before cffi because cffi will otherwise install an unchecked +# version via setup_requires. +pycparser==2.14 \ + --hash=sha256:7959b4a74abdc27b312fed1c21e6caf9309ce0b29ea86b591fd2e99ecdf27f73 + +cffi==1.4.2 \ + --hash=sha256:53c1c9ddb30431513eb7f3cdef0a3e06b0f1252188aaa7744af0f5a4cd45dbaf \ + --hash=sha256:a568f49dfca12a8d9f370187257efc58a38109e1eee714d928561d7a018a64f8 \ + --hash=sha256:809c6ca8cfbcaeebfbd432b4576001b40d38ff2463773cb57577d75e1a020bc3 \ + --hash=sha256:86cdca2cd9cba41422230390df17dfeaa9f344a911e3975c8be9da57b35548e9 \ + --hash=sha256:24b13db84aec385ca23c7b8ded83ef8bb4177bc181d14758f9f975be5d020d86 \ + --hash=sha256:969aeffd7c0e097f6be1efd682c156ae226591a0793a94b6c2d5e4293f4c8d4e \ + --hash=sha256:000f358d4b0fa249feaab9c1ce7d5b2fe7e02e7bdf6806c26418505fc685e268 \ + --hash=sha256:a9d86f460bbd8358a2d513ad779e3f3fc878e3b93a00b5002faebf616ffe6b9c \ + --hash=sha256:3127b3ab33eb23ccac071f9a0802748e5cf7c5cbcd02482bb063e35b41dbb0b0 \ + --hash=sha256:e2b2d42236469a40224d39e7b6c60575f388b2f423f354c7ee90a5b7f58c8065 \ + --hash=sha256:8c2dccafee89b1b424b0bec6ad2dd9622c949d2024e929f5da1ed801eac75f1d \ + --hash=sha256:a4de7a4d11aed488bab4fb14f4988587a829bece5a20433f780d6e33b08083cb \ + --hash=sha256:5ca8fe30425265a49274e4b0213a1bc98f4b13449ae5e96f984771e5d83e58c1 \ + --hash=sha256:a4fd38802f59e714eba81a024f62db710b27dbe27a7ea12e911537327aa84d30 \ + --hash=sha256:86cd6912bbc83e9405d4a73cd7f4b4ee8353652d2dbc7c820106ed5b4d1bab3a \ + --hash=sha256:8f1d177d364ea35900415ae24ca3e471be3d5334ed0419294068c49f45913998 +ConfigArgParse==0.10.0 \ + --hash=sha256:3b50a83dd58149dfcee98cb6565265d10b53e9c0a2bca7eeef7fb5f5524890a7 +configobj==5.0.6 \ + --hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902 +cryptography==1.2.3 \ + --hash=sha256:031938f73a5c5eb3e809e18ff7caeb6865351871417be6050cb8c86a9a202b9a \ + --hash=sha256:a179a38d50f8d68b491d7a313db78f8cabe290842cecddddc7b34d408e59db0a \ + --hash=sha256:906c88b2aadcf99cfabb24098263d1bf65ab0c8688acde10dae1f09d865920f1 \ + --hash=sha256:6e706c5c6088770b1d1b634e959e21963e315b0255f5f4777125ad3d54082977 \ + --hash=sha256:f5ebf8e31c48f8707921dca0e994de77813a9c9b9bf03c119c5ddf97bdcffe73 \ + --hash=sha256:c7b89e42288cc7fbee3812e99ef5c744f22452e11d6822f6807afc6d6b3be83e \ + --hash=sha256:8408d29865947109d8b68f1837a7cde1aa4dc86e0f79ca3ba58c0c44e443d6a5 \ + --hash=sha256:c7e76cf3c3d925dd31fa238cfb806cffba718c0f08707d77a538768477969956 \ + --hash=sha256:7d8de35380f31702758b7753bb5c40723832c73006dedb2f9099bf61a37f7287 \ + --hash=sha256:5edbee71fae5469ee83fe0a37866b9398c8ce3a46325c24fcedfbf097bb48a19 \ + --hash=sha256:594edafe4801c13bdc1cc305e7704a90c19617e95936f6ab457ee4ffe000ba50 \ + --hash=sha256:b7fdb16a0a7f481be42da744bfe1ea2163025de21f90f2c688a316f3c354da9c \ + --hash=sha256:207b8bf0fe0907336df38b733b487521cf9e138189aba9234ad54fe545dd0db8 \ + --hash=sha256:509a2f05386270cf783993c90d49ffefb3dd62aee45bf1ea8ce3d2cde7271c21 \ + --hash=sha256:ac69b65dd1af0179ede40c9f15788c88f73e628ea6c0519de3838e279bb388c6 \ + --hash=sha256:8df6fad6c6ae12fd7004ea29357f0a2b4d3774eaeca7656530d08d2d90cd41aa \ + --hash=sha256:0b8b96dd81cc1533a04f30382c0fe21c1972e189f794d0c4261a18cec08fd9b5 \ + --hash=sha256:cae8fca1883f23c50ea78d89de6fe4fefdb4cea83177760f47177559414ded93 \ + --hash=sha256:1a471ca576a9cdce1b1cd9f3a22b1d09ee44d46862037557de17919c0db44425 \ + --hash=sha256:8ec4e8e3d453b3a1b63b5f57737a434dcf1ee4a2f26f6ff7c5a37c3f679104d2 \ + --hash=sha256:8eb11c77dd8e73f48df6b2f7a7e16173fe0fe8fdfe266232832e88477e08454e +enum34==1.1.2 \ + --hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \ + --hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501 +funcsigs==0.4 \ + --hash=sha256:ff5ad9e2f8d9e5d1e8bbfbcf47722ab527cf0d51caeeed9da6d0f40799383fde \ + --hash=sha256:d83ce6df0b0ea6618700fe1db353526391a8a3ada1b7aba52fed7a61da772033 +idna==2.0 \ + --hash=sha256:9b2fc50bd3c4ba306b9651b69411ef22026d4d8335b93afc2214cef1246ce707 \ + --hash=sha256:16199aad938b290f5be1057c0e1efc6546229391c23cea61ca940c115f7d3d3b +ipaddress==1.0.16 \ + --hash=sha256:935712800ce4760701d89ad677666cd52691fd2f6f0b340c8b4239a3c17988a5 \ + --hash=sha256:5a3182b322a706525c46282ca6f064d27a02cffbd449f9f47416f1dc96aa71b0 +linecache2==1.0.0 \ + --hash=sha256:e78be9c0a0dfcbac712fe04fbf92b96cddae80b1b842f24248214c8496f006ef \ + --hash=sha256:4b26ff4e7110db76eeb6f5a7b64a82623839d595c2038eeda662f2a2db78e97c +ndg-httpsclient==0.4.0 \ + --hash=sha256:e8c155fdebd9c4bcb0810b4ed01ae1987554b1ee034dd7532d7b8fdae38a6274 +ordereddict==1.1 \ + --hash=sha256:1c35b4ac206cef2d24816c89f89cf289dd3d38cf7c449bb3fab7bf6d43f01b1f +parsedatetime==2.1 \ + --hash=sha256:ce9d422165cf6e963905cd5f74f274ebf7cc98c941916169178ef93f0e557838 \ + --hash=sha256:17c578775520c99131634e09cfca5a05ea9e1bd2a05cd06967ebece10df7af2d +pbr==1.8.1 \ + --hash=sha256:46c8db75ae75a056bd1cc07fa21734fe2e603d11a07833ecc1eeb74c35c72e0c \ + --hash=sha256:e2127626a91e6c885db89668976db31020f0af2da728924b56480fc7ccf09649 +psutil==3.3.0 \ + --hash=sha256:584f0b29fcc5d523b433cb8918b2fc74d67e30ee0b44a95baf031528f424619f \ + --hash=sha256:28ca0b6e9d99aa8dc286e8747a4471362b69812a25291de29b6a8d70a1545a0d \ + --hash=sha256:167ad5fff52a672c4ddc1c1a0b25146d6813ebb08a9aab0a3ac45f8a5b669c3b \ + --hash=sha256:e6dea6173a988727bb223d3497349ad5cdef5c0b282eff2d83e5f9065c53f85f \ + --hash=sha256:2af5e0a4aad66049955d0734aa4e3dc8caa17a9eaf8b4c1a27a5f1ee6e40f6fc \ + --hash=sha256:d9884dc0dc2e55e2448e495778dc9899c1c8bf37aeb2f434c1bea74af93c2683 \ + --hash=sha256:e27c2fe6dfcc8738be3d2c5a022f785eb72971057e1a9e1e34fba73bce8a71a6 \ + --hash=sha256:65afd6fecc8f3aed09ee4be63583bc8eb472f06ceaa4fe24c4d1d5a1a3c0e13f \ + --hash=sha256:ba1c558fbfcdf94515c2394b1155c1dc56e2bc2a9c17d30349827c9ed8a67e46 \ + --hash=sha256:ba95ea0022dcb64d36f0c1335c0605fae35bdf3e0fea8d92f5d0f6456a35e55b \ + --hash=sha256:421b6591d16b509aaa8d8c15821d66bb94cb4a8dc4385cad5c51b85d4a096d85 \ + --hash=sha256:326b305cbdb6f94dafbfe2c26b11da88b0ab07b8a07f8188ab9d75ff0c6e841a \ + --hash=sha256:9aede5b2b6fe46b3748ea8e5214443890d1634027bef3d33b7dad16556830278 \ + --hash=sha256:73bed1db894d1aa9c3c7e611d302cdeab7ae8a0dc0eeaf76727878db1ac5cd87 \ + --hash=sha256:935b5dd6d558af512f42501a7c08f41d7aff139af1bb3959daa3abb859234d6c \ + --hash=sha256:4ca0111cf157dcc0f2f69a323c5b5478718d68d45fc9435d84be0ec0f186215b \ + --hash=sha256:b6f13c95398a3fcf0226c4dcfa448560ba5865259cd96ec2810658651e932189 \ + --hash=sha256:ee6be30d1635bbdea4c4325d507dc8a0dbbde7e1c198bd62ddb9f43198b9e214 \ + --hash=sha256:dfa786858c268d7fbbe1b6175e001ec02738d7cfae0a7ce77bf9b651af676729 \ + --hash=sha256:aa77f9de72af9c16cc288cd4a24cf58824388f57d7a81e400c4616457629870e \ + --hash=sha256:f500093357d04da8140d87932cac2e54ef592a54ca8a743abb2850f60c2c22eb +pyasn1==0.1.9 \ + --hash=sha256:61f9d99e3cef65feb1bfe3a2eef7a93eb93819d345bf54bcd42f4e63d5204dae \ + --hash=sha256:1802a6dd32045e472a419db1441aecab469d33e0d2749e192abdec52101724af \ + --hash=sha256:35025cd9422c96504912f04e2f15fe79390a8597b430c2ca5d0534cf9309ffa0 \ + --hash=sha256:2f96ed5a0c329ca16230b326ca12b7461ec8f65e0be3e4f997516f36bf82a345 \ + --hash=sha256:28fee44217991cfad9e6a0b9f7e3f26041e21ebc96629e94e585ccd05d49fa65 \ + --hash=sha256:326e7a854a17fab07691204747695f8f692d674588a355c441fb14f660bf4e68 \ + --hash=sha256:cda5a90485709ca6795c86056c3e5fe7266028b05e53f1d527fdf93a6365a6b8 \ + --hash=sha256:0cb2a14742b543fdd68f931a14ce3829186ed2b1b2267a06787388c96b2dd9be \ + --hash=sha256:5191ff6b9126d2c039dd87f8ff025bed274baf07fa78afa46f556b1ad7265d6e \ + --hash=sha256:8323e03637b2d072cc7041300bac6ec448c3c28950ab40376036788e9a1af629 \ + --hash=sha256:853cacd96d1f701ddd67aa03ecc05f51890135b7262e922710112f12a2ed2a7f +pyOpenSSL==0.15.1 \ + --hash=sha256:88e45e6bb25dfed272a1ef2e728461d44b634c2cd689e989b6e56a349c5a3ae5 \ + --hash=sha256:f0a26070d6db0881de8bcc7846934b7c3c930d8f9c79d45883ee48984bc0d672 +pyRFC3339==1.0 \ + --hash=sha256:eea31835c56e2096af4363a5745a784878a61d043e247d3a6d6a0a32a9741f56 \ + --hash=sha256:8dfbc6c458b8daba1c0f3620a8c78008b323a268b27b7359e92a4ae41325f535 +python-augeas==0.5.0 \ + --hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2 +python2-pythondialog==3.3.0 \ + --hash=sha256:04e93f24995c43dd90f338d5d865ca72ce3fb5a5358d4daa4965571db35fc3ec \ + --hash=sha256:3e6f593fead98f8a526bc3e306933533236e33729f552f52896ea504f55313fa +pytz==2015.7 \ + --hash=sha256:3abe6a6d3fc2fbbe4c60144211f45da2edbe3182a6f6511af6bbba0598b1f992 \ + --hash=sha256:939ef9c1e1224d980405689a97ffcf7828c56d1517b31d73464356c1f2b7769e \ + --hash=sha256:ead4aefa7007249e05e51b01095719d5a8dd95760089f5730aac5698b1932918 \ + --hash=sha256:3cca0df08bd0ed98432390494ce3ded003f5e661aa460be7a734bffe35983605 \ + --hash=sha256:3ede470d3d17ba3c07638dfa0d10452bc1b6e5ad326127a65ba77e6aaeb11bec \ + --hash=sha256:68c47964f7186eec306b13629627722b9079cd4447ed9e5ecaecd4eac84ca734 \ + --hash=sha256:dd5d3991950aae40a6c81de1578942e73d629808cefc51d12cd157980e6cfc18 \ + --hash=sha256:a77c52062c07eb7c7b30545dbc73e32995b7e117eea750317b5cb5c7a4618f14 \ + --hash=sha256:81af9aec4bc960a9a0127c488f18772dae4634689233f06f65443e7b11ebeb51 \ + --hash=sha256:e079b1dadc5c06246cc1bb6fe1b23a50b1d1173f2edd5104efd40bb73a28f406 \ + --hash=sha256:fbd26746772c24cb93c8b97cbdad5cb9e46c86bbdb1b9d8a743ee00e2fb1fc5d \ + --hash=sha256:99266ef30a37e43932deec2b7ca73e83c8dbc3b9ff703ec73eca6b1dae6befea \ + --hash=sha256:8b6ce1c993909783bc96e0b4f34ea223bff7a4df2c90bdb9c4e0f1ac928689e3 +requests==2.9.1 \ + --hash=sha256:113fbba5531a9e34945b7d36b33a084e8ba5d0664b703c81a7c572d91919a5b8 \ + --hash=sha256:c577815dd00f1394203fc44eb979724b098f88264a9ef898ee45b8e5e9cf587f +six==1.10.0 \ + --hash=sha256:0ff78c403d9bccf5a425a6d31a12aa6b47f1c21ca4dc2573a7e2f32a97335eb1 \ + --hash=sha256:105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a +traceback2==1.4.0 \ + --hash=sha256:8253cebec4b19094d67cc5ed5af99bf1dba1285292226e98a31929f87a5d6b23 \ + --hash=sha256:05acc67a09980c2ecfedd3423f7ae0104839eccb55fc645773e1caa0951c3030 +unittest2==1.1.0 \ + --hash=sha256:13f77d0875db6d9b435e1d4f41e74ad4cc2eb6e1d5c824996092b3430f088bb8 \ + --hash=sha256:22882a0e418c284e1f718a822b3b022944d53d2d908e1690b319a9d3eb2c0579 +zope.component==4.2.2 \ + --hash=sha256:282c112b55dd8e3c869a3571f86767c150ab1284a9ace2bdec226c592acaf81a +zope.event==4.1.0 \ + --hash=sha256:dc7a59a2fd91730d3793131a5d261b29e93ec4e2a97f1bc487ce8defee2fe786 +zope.interface==4.1.3 \ + --hash=sha256:f07b631f7a601cd8cbd3332d54f43142c7088a83299f859356f08d1d4d4259b3 \ + --hash=sha256:de5cca083b9439d8002fb76bbe6b4998c5a5a721fab25b84298967f002df4c94 \ + --hash=sha256:6788416f7ea7f5b8a97be94825377aa25e8bdc73463e07baaf9858b29e737077 \ + --hash=sha256:6f3230f7254518201e5a3708cbb2de98c848304f06e3ded8bfb39e5825cba2e1 \ + --hash=sha256:5fa575a5240f04200c3088427d0d4b7b737f6e9018818a51d8d0f927a6a2517a \ + --hash=sha256:522194ad6a545735edd75c8a83f48d65d1af064e432a7d320d64f56bafc12e99 \ + --hash=sha256:e8c7b2d40943f71c99148c97f66caa7f5134147f57423f8db5b4825099ce9a09 \ + --hash=sha256:279024f0208601c3caa907c53876e37ad88625f7eaf1cb3842dbe360b2287017 \ + --hash=sha256:2e221a9eec7ccc58889a278ea13dcfed5ef939d80b07819a9a8b3cb1c681484f \ + --hash=sha256:69118965410ec86d44dc6b9017ee3ddbd582e0c0abeef62b3a19dbf6c8ad132b \ + --hash=sha256:d04df8686ec864d0cade8cf199f7f83aecd416109a20834d568f8310ded12dea \ + --hash=sha256:e75a947e15ee97e7e71e02ea302feb2fc62d3a2bb4668bf9dfbed43a506ac7e7 \ + --hash=sha256:4e45d22fb883222a5ab9f282a116fec5ee2e8d1a568ccff6a2d75bbd0eb6bcfc \ + --hash=sha256:bce9339bb3c7a55e0803b63d21c5839e8e479bc85c4adf42ae415b72f94facb2 \ + --hash=sha256:928138365245a0e8869a5999fbcc2a45475a0a6ed52a494d60dbdc540335fedd \ + --hash=sha256:0d841ba1bb840eea0e6489dc5ecafa6125554971f53b5acb87764441e61bceba \ + --hash=sha256:b09c8c1d47b3531c400e0195697f1414a63221de6ef478598a4f1460f7d9a392 +mock==1.0.1 \ + --hash=sha256:b839dd2d9c117c701430c149956918a423a9863b48b09c90e30a6013e7d2f44f \ + --hash=sha256:8f83080daa249d036cbccfb8ae5cc6ff007b88d6d937521371afabe7b19badbc + +# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. + +acme==0.5.0 \ + --hash=sha256:ceb4127c13213f0006a564be82176b968c6b374d20d9fc78555d0658a252b275 \ + --hash=sha256:0605c63c656d33c883a05675f5db9cfb85d503f2771c885031800e0da7631abd +letsencrypt==0.5.0 \ + --hash=sha256:f90f883e99cdbdf8142335bdbf4f74a8af143ee4b4ec60fb49c6e47418c1114c \ + --hash=sha256:e38a2b70b82be79bc195307652244a3e012ec73d897d4dbd3f80cf698496d15a +letsencrypt-apache==0.5.0 \ + --hash=sha256:a767882164a7b09d9c12c80684a28a782135fdaf35654ef5a02c0b7b1d27ab8d \ + --hash=sha256:c20e7b9c517aa4a7d70e6bd9382da7259f00bc191b9e60d8e312e48837a00c41 + +UNLIKELY_EOF + # ------------------------------------------------------------------------- + cat << "UNLIKELY_EOF" > "$TEMP_DIR/pipstrap.py" +#!/usr/bin/env python +"""A small script that can act as a trust root for installing pip 8 + +Embed this in your project, and your VCS checkout is all you have to trust. In +a post-peep era, this lets you claw your way to a hash-checking version of pip, +with which you can install the rest of your dependencies safely. All it assumes +is Python 2.6 or better and *some* version of pip already installed. If +anything goes wrong, it will exit with a non-zero status code. + +""" +# This is here so embedded copies are MIT-compliant: +# Copyright (c) 2016 Erik Rose +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +from __future__ import print_function +from hashlib import sha256 +from os.path import join +from pipes import quote +from shutil import rmtree +try: + from subprocess import check_output +except ImportError: + from subprocess import CalledProcessError, PIPE, Popen + + def check_output(*popenargs, **kwargs): + if 'stdout' in kwargs: + raise ValueError('stdout argument not allowed, it will be ' + 'overridden.') + process = Popen(stdout=PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise CalledProcessError(retcode, cmd) + return output +from sys import exit, version_info +from tempfile import mkdtemp +try: + from urllib2 import build_opener, HTTPHandler, HTTPSHandler +except ImportError: + from urllib.request import build_opener, HTTPHandler, HTTPSHandler +try: + from urlparse import urlparse +except ImportError: + from urllib.parse import urlparse # 3.4 + + +__version__ = 1, 1, 1 + + +# wheel has a conditional dependency on argparse: +maybe_argparse = ( + [('https://pypi.python.org/packages/source/a/argparse/' + 'argparse-1.4.0.tar.gz', + '62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4')] + if version_info < (2, 7, 0) else []) + + +PACKAGES = maybe_argparse + [ + # Pip has no dependencies, as it vendors everything: + ('https://pypi.python.org/packages/source/p/pip/pip-8.0.3.tar.gz', + '30f98b66f3fe1069c529a491597d34a1c224a68640c82caf2ade5f88aa1405e8'), + # This version of setuptools has only optional dependencies: + ('https://pypi.python.org/packages/source/s/setuptools/' + 'setuptools-20.2.2.tar.gz', + '24fcfc15364a9fe09a220f37d2dcedc849795e3de3e4b393ee988e66a9cbd85a'), + ('https://pypi.python.org/packages/source/w/wheel/wheel-0.29.0.tar.gz', + '1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648') +] + + +class HashError(Exception): + def __str__(self): + url, path, actual, expected = self.args + return ('{url} did not match the expected hash {expected}. Instead, ' + 'it was {actual}. The file (left at {path}) may have been ' + 'tampered with.'.format(**locals())) + + +def hashed_download(url, temp, digest): + """Download ``url`` to ``temp``, make sure it has the SHA-256 ``digest``, + and return its path.""" + # Based on pip 1.4.1's URLOpener but with cert verification removed. Python + # >=2.7.9 verifies HTTPS certs itself, and, in any case, the cert + # authenticity has only privacy (not arbitrary code execution) + # implications, since we're checking hashes. + def opener(): + opener = build_opener(HTTPSHandler()) + # Strip out HTTPHandler to prevent MITM spoof: + for handler in opener.handlers: + if isinstance(handler, HTTPHandler): + opener.handlers.remove(handler) + return opener + + def read_chunks(response, chunk_size): + while True: + chunk = response.read(chunk_size) + if not chunk: + break + yield chunk + + response = opener().open(url) + path = join(temp, urlparse(url).path.split('/')[-1]) + actual_hash = sha256() + with open(path, 'wb') as file: + for chunk in read_chunks(response, 4096): + file.write(chunk) + actual_hash.update(chunk) + + actual_digest = actual_hash.hexdigest() + if actual_digest != digest: + raise HashError(url, path, actual_digest, digest) + return path + + +def main(): + temp = mkdtemp(prefix='pipstrap-') + try: + downloads = [hashed_download(url, temp, digest) + for url, digest in PACKAGES] + check_output('pip install --no-index --no-deps -U ' + + ' '.join(quote(d) for d in downloads), + shell=True) + except HashError as exc: + print(exc) + except Exception: + rmtree(temp) + raise + else: + rmtree(temp) + return 0 + return 1 + + +if __name__ == '__main__': + exit(main()) + +UNLIKELY_EOF + # ------------------------------------------------------------------------- + # Set PATH so pipstrap upgrades the right (v)env: + PATH="$VENV_BIN:$PATH" "$VENV_BIN/python" "$TEMP_DIR/pipstrap.py" + set +e + PIP_OUT=`"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1` + PIP_STATUS=$? + set -e + rm -rf "$TEMP_DIR" + if [ "$PIP_STATUS" != 0 ]; then + # Report error. (Otherwise, be quiet.) + echo "Had a problem while installing Python packages:" + echo "$PIP_OUT" + rm -rf "$VENV_PATH" + exit 1 + fi + echo "Installation succeeded." + fi + echo "Requesting root privileges to run letsencrypt..." + echo " " $SUDO "$VENV_BIN/letsencrypt" "$@" + $SUDO "$VENV_BIN/letsencrypt" "$@" +else + # Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke. + # + # Each phase checks the version of only the thing it is responsible for + # upgrading. Phase 1 checks the version of the latest release of + # letsencrypt-auto (which is always the same as that of the letsencrypt + # package). Phase 2 checks the version of the locally installed letsencrypt. + + if [ ! -f "$VENV_BIN/letsencrypt" ]; then + # If it looks like we've never bootstrapped before, bootstrap: + Bootstrap + fi + if [ "$OS_PACKAGES_ONLY" = 1 ]; then + echo "OS packages installed." + exit 0 + fi + + if [ "$NO_SELF_UPGRADE" != 1 ]; then + echo "Checking for new version..." + TEMP_DIR=$(TempDir) + # --------------------------------------------------------------------------- + cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py" +"""Do downloading and JSON parsing without additional dependencies. :: + + # Print latest released version of LE to stdout: + python fetch.py --latest-version + + # Download letsencrypt-auto script from git tag v1.2.3 into the folder I'm + # in, and make sure its signature verifies: + python fetch.py --le-auto-script v1.2.3 + +On failure, return non-zero. + +""" +from distutils.version import LooseVersion +from json import loads +from os import devnull, environ +from os.path import dirname, join +import re +from subprocess import check_call, CalledProcessError +from sys import argv, exit +from urllib2 import build_opener, HTTPHandler, HTTPSHandler, HTTPError + +PUBLIC_KEY = environ.get('LE_AUTO_PUBLIC_KEY', """-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6MR8W/galdxnpGqBsYbq +OzQb2eyW15YFjDDEMI0ZOzt8f504obNs920lDnpPD2/KqgsfjOgw2K7xWDJIj/18 +xUvWPk3LDkrnokNiRkA3KOx3W6fHycKL+zID7zy+xZYBuh2fLyQtWV1VGQ45iNRp +9+Zo7rH86cdfgkdnWTlNSHyTLW9NbXvyv/E12bppPcEvgCTAQXgnDVJ0/sqmeiij +n9tTFh03aM+R2V/21h8aTraAS24qiPCz6gkmYGC8yr6mglcnNoYbsLNYZ69zF1XH +cXPduCPdPdfLlzVlKK1/U7hkA28eG3BIAMh6uJYBRJTpiGgaGdPd7YekUB8S6cy+ +CQIDAQAB +-----END PUBLIC KEY----- +""") + +class ExpectedError(Exception): + """A novice-readable exception that also carries the original exception for + debugging""" + + +class HttpsGetter(object): + def __init__(self): + """Build an HTTPS opener.""" + # Based on pip 1.4.1's URLOpener + # This verifies certs on only Python >=2.7.9. + self._opener = build_opener(HTTPSHandler()) + # Strip out HTTPHandler to prevent MITM spoof: + for handler in self._opener.handlers: + if isinstance(handler, HTTPHandler): + self._opener.handlers.remove(handler) + + def get(self, url): + """Return the document contents pointed to by an HTTPS URL. + + If something goes wrong (404, timeout, etc.), raise ExpectedError. + + """ + try: + return self._opener.open(url).read() + except (HTTPError, IOError) as exc: + raise ExpectedError("Couldn't download %s." % url, exc) + + +def write(contents, dir, filename): + """Write something to a file in a certain directory.""" + with open(join(dir, filename), 'w') as file: + file.write(contents) + + +def latest_stable_version(get): + """Return the latest stable release of letsencrypt.""" + metadata = loads(get( + environ.get('LE_AUTO_JSON_URL', + 'https://pypi.python.org/pypi/letsencrypt/json'))) + # metadata['info']['version'] actually returns the latest of any kind of + # release release, contrary to https://wiki.python.org/moin/PyPIJSON. + # The regex is a sufficient regex for picking out prereleases for most + # packages, LE included. + return str(max(LooseVersion(r) for r + in metadata['releases'].iterkeys() + if re.match('^[0-9.]+$', r))) + + +def verified_new_le_auto(get, tag, temp_dir): + """Return the path to a verified, up-to-date letsencrypt-auto script. + + If the download's signature does not verify or something else goes wrong + with the verification process, raise ExpectedError. + + """ + le_auto_dir = environ.get( + 'LE_AUTO_DIR_TEMPLATE', + 'https://raw.githubusercontent.com/letsencrypt/letsencrypt/%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') + write(PUBLIC_KEY, temp_dir, 'public_key.pem') + try: + with open(devnull, 'w') as dev_null: + check_call(['openssl', 'dgst', '-sha256', '-verify', + join(temp_dir, 'public_key.pem'), + '-signature', + join(temp_dir, 'letsencrypt-auto.sig'), + join(temp_dir, 'letsencrypt-auto')], + stdout=dev_null, + stderr=dev_null) + except CalledProcessError as exc: + raise ExpectedError("Couldn't verify signature of downloaded " + "letsencrypt-auto.", exc) + + +def main(): + get = HttpsGetter().get + flag = argv[1] + try: + if flag == '--latest-version': + print latest_stable_version(get) + elif flag == '--le-auto-script': + tag = argv[2] + verified_new_le_auto(get, tag, dirname(argv[0])) + except ExpectedError as exc: + print exc.args[0], exc.args[1] + return 1 + else: + return 0 + + +if __name__ == '__main__': + exit(main()) + +UNLIKELY_EOF + # --------------------------------------------------------------------------- + DeterminePythonVersion + REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` + if [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then + echo "Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION..." + + # Now we drop into Python so we don't have to install even more + # dependencies (curl, etc.), for better flow control, and for the option of + # future Windows compatibility. + "$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION" + + # Install new copy of letsencrypt-auto. + # TODO: Deal with quotes in pathnames. + echo "Replacing letsencrypt-auto..." + # Clone permissions with cp. chmod and chown don't have a --reference + # option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD: + echo " " $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone" + $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone" + echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone" + $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone" + # Using mv rather than cp leaves the old file descriptor pointing to the + # original copy so the shell can continue to read it unmolested. mv across + # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the + # cp is unlikely to fail (esp. under sudo) if the rm doesn't. + echo " " $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" + $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" + # TODO: Clean up temp dir safely, even if it has quotes in its path. + rm -rf "$TEMP_DIR" + fi # A newer version is available. + fi # Self-upgrading is allowed. + + "$0" --le-auto-phase2 "$@" +fi diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc new file mode 100644 index 000000000..593e644ec --- /dev/null +++ b/letsencrypt-auto-source/certbot-auto.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1 + +iQEcBAABAgAGBQJXNLdqAAoJEE0XyZXNl3Xyk3cH/1OxJ16VbX9PK4U60mVRPseA +wzaCFOCVVB3Ub9m6PMzOw6kV9KLXuiMgh1qj9j4AH5UdFwynv6WNe+pxO3deYO6O +DBhlW0ibDoIGLb2nvHDmBXfX+CE8ixvo2pp7ao/StV5MTHSoDHfMZbT7ql1xpx7U +XOaPfl8MlmIlii6QFrBNZpUjE03NE8xUpocZq53eXxZiCRHLbO9z4j1e6NkaTotj +4Q1o9ERdAc5S7czF9TFwPgQWXoVxiMjhUUpNjfVFFjFB6r76AdVzz5PG6icZ6icM +C3kD1N4gm0sggNkWwDOfNAgTanVa/pmIv/wi7tkm/jpCfkErttnq9AjEhichaSY= +=SJou +-----END PGP SIGNATURE----- From a7d0b1a7d38111eeea96bf3aaa0eedee46ecc234 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 12 May 2016 17:49:44 -0700 Subject: [PATCH 096/186] Address review comments --- certbot/cli.py | 2 +- certbot/crypto_util.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/certbot/cli.py b/certbot/cli.py index 796925c1d..430384a5a 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -349,7 +349,7 @@ class HelpfulArgumentParser(object): def set_test_server(self, parsed_args): - "We have --staging/--dry-run; perform sanity check and set config.server" + """We have --staging/--dry-run; perform sanity check and set config.server""" if parsed_args.server not in (flag_default("server"), constants.STAGING_URI): conflicts = ["--staging"] if parsed_args.staging else [] diff --git a/certbot/crypto_util.py b/certbot/crypto_util.py index ceec6db71..07e7f9fd2 100644 --- a/certbot/crypto_util.py +++ b/certbot/crypto_util.py @@ -178,11 +178,11 @@ def import_csr_file(csrfile, contents): :param str csrfile: CSR filename :param str contents: contens of the CSR file - :rtype: tuple - :returns: (le_util.CSR object representing the CSR, - OpenSSL FILETYPE_ representing DER or PEM, + `OpenSSL.crypto.FILETYPE_PEM` or `OpenSSL.crypto.FILETYPE_ASN1`, list of domains requested in the CSR) + + :rtype: tuple """ try: csr = le_util.CSR(file=csrfile, data=contents, form="der") From 5b058fd18f2565624642862d5c8a51ec84f793e8 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 12 May 2016 19:06:09 -0700 Subject: [PATCH 097/186] Import third party plugin list from the wiki And clean up the confusing section about third party plugins --- docs/using.rst | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index e7e0e9474..469e302ee 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -82,6 +82,9 @@ manual_ Y N Helps you obtain a cert by giving you instructions to perf nginx_ Y Y Very experimental and not included in letsencrypt-auto_. =========== ==== ==== =============================================================== +Third-party plugins +------------------- + There are also a number of third-party plugins for the client, provided by other developers: =========== ==== ==== =============================================================== @@ -91,15 +94,25 @@ plesk_ Y Y Integration with the Plesk web hosting tool haproxy_ Y Y Integration with the HAProxy load balancer s3front_ Y Y Integration with Amazon CloudFront distribution of S3 buckets gandi_ Y Y Integration with Gandi's hosting products and API +varnish_ Y N Obtain certs via a Varnish server +external_ Y N A plugin for convenient scripting (See also ticket 2782_) +icecast_ N Y Deploy certs to Icecast 2 streaming media servers +pritunl_ N Y Install certs in pritunl distributed OpenVPN servers +proxmox_ N Y Install certs in Proxmox Virtualization servers + =========== ==== ==== =============================================================== .. _plesk: https://github.com/plesk/letsencrypt-plesk .. _haproxy: https://code.greenhost.net/open/letsencrypt-haproxy .. _s3front: https://github.com/dlapiduz/letsencrypt-s3front .. _gandi: https://github.com/Gandi/letsencrypt-gandi +.. _icecast: https://github.com/e00E/lets-encrypt-icecast +.. _varnish: http://git.sesse.net/?p=letsencrypt-varnish-plugin +.. _2782: https://github.com/certbot/certbot/issues/2782 +.. _pritunl: https://github.com/kharkevich/letsencrypt-pritunl +.. _proxmox: https://github.com/kharkevich/letsencrypt-proxmox -Future plugins for IMAP servers, SMTP servers, IRC servers, etc, are likely to -be installers but not authenticators. +If you're interested, you can also :ref:`write your own plugin `. Apache ------ @@ -190,12 +203,6 @@ still experimental, however, and is not installed with letsencrypt-auto_. If installed, you can select this plugin on the command line by including ``--nginx``. -Third-party plugins -------------------- - -These plugins are listed at -https://github.com/letsencrypt/letsencrypt/wiki/Plugins. If you're -interested, you can also :ref:`write your own plugin `. Renewal ======= From b905cb448134065a502cd25958c1a15392060962 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 12 May 2016 19:09:59 -0700 Subject: [PATCH 098/186] Missing link --- docs/using.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/using.rst b/docs/using.rst index 469e302ee..8383f9690 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -111,6 +111,7 @@ proxmox_ N Y Install certs in Proxmox Virtualization servers .. _2782: https://github.com/certbot/certbot/issues/2782 .. _pritunl: https://github.com/kharkevich/letsencrypt-pritunl .. _proxmox: https://github.com/kharkevich/letsencrypt-proxmox +.. _external: https://github.com/marcan/letsencrypt-external If you're interested, you can also :ref:`write your own plugin `. From 2dc983db4943bd87620a88c6c9e34bcf04f56e07 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 12 May 2016 19:17:19 -0700 Subject: [PATCH 099/186] STLSE is a prototype Postfix plugin - it partially uses IInstaller - it will also support Exim in the future --- docs/using.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index 8383f9690..47746c110 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -99,7 +99,7 @@ external_ Y N A plugin for convenient scripting (See also ticket 2782_) icecast_ N Y Deploy certs to Icecast 2 streaming media servers pritunl_ N Y Install certs in pritunl distributed OpenVPN servers proxmox_ N Y Install certs in Proxmox Virtualization servers - +postfix_ N Y STARTTLS Everywhere is becoming a Certbot Postfix/Exim plugin =========== ==== ==== =============================================================== .. _plesk: https://github.com/plesk/letsencrypt-plesk @@ -112,6 +112,7 @@ proxmox_ N Y Install certs in Proxmox Virtualization servers .. _pritunl: https://github.com/kharkevich/letsencrypt-pritunl .. _proxmox: https://github.com/kharkevich/letsencrypt-proxmox .. _external: https://github.com/marcan/letsencrypt-external +.. _postfix: https://github.com/EFForg/starttls-everywhere If you're interested, you can also :ref:`write your own plugin `. From 3c279c4fadfc4c08a3119f39317865a1ef3dcff1 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 13 May 2016 12:22:19 -0700 Subject: [PATCH 100/186] Create a man page for ourselves! --- docs/cli-help.txt | 340 +++++++++++++++++++++++++++++++++++++++++++ docs/man/certbot.rst | 2 +- 2 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 docs/cli-help.txt diff --git a/docs/cli-help.txt b/docs/cli-help.txt new file mode 100644 index 000000000..cb4bace58 --- /dev/null +++ b/docs/cli-help.txt @@ -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 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 diff --git a/docs/man/certbot.rst b/docs/man/certbot.rst index 7382d7811..8fb03db49 100644 --- a/docs/man/certbot.rst +++ b/docs/man/certbot.rst @@ -1 +1 @@ -.. program-output:: certbot --help all +.. literalinclude:: cli-help.txt From c55d8e4741bfcd02934c37902f9ba6edf33cb8ee Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 13 May 2016 12:22:35 -0700 Subject: [PATCH 101/186] Build the text for the man page at release --- tools/release.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/release.sh b/tools/release.sh index 8c2d04cd4..abaad09ff 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -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" From f16104e3cb1b1de34d4683853d3b255229c9ae4d Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 13 May 2016 12:22:55 -0700 Subject: [PATCH 102/186] Lots of doc cleanups --- README.rst | 14 +++++--- certbot/cli.py | 3 +- docs/contributing.rst | 2 +- docs/intro.rst | 6 ++-- docs/using.rst | 78 +++++++++++++++---------------------------- 5 files changed, 42 insertions(+), 61 deletions(-) diff --git a/README.rst b/README.rst index 20b49083f..c71079f9a 100644 --- a/README.rst +++ b/README.rst @@ -31,14 +31,17 @@ Contributing If you'd like to contribute to this project please read `Developer Guide `_. +.. _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/ diff --git a/certbot/cli.py b/certbot/cli.py index 90e86a751..65715ac57 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -745,7 +745,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", diff --git a/docs/contributing.rst b/docs/contributing.rst index 49e9e146d..b56a04c7d 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -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. diff --git a/docs/intro.rst b/docs/intro.rst index 188ff4302..2fffbec68 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -1,6 +1,6 @@ -============ -Introduction -============ +===================== +README / Introduction +===================== .. include:: ../README.rst .. include:: ../CHANGES.rst diff --git a/docs/using.rst b/docs/using.rst index 997134de5..6558e9e16 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -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 `__ + +__ 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 @@ -275,17 +247,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 @@ -391,7 +367,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 ============================= From e85b387e4283d0577384ea6fa0184e6b0c801713 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 13 May 2016 13:21:49 -0700 Subject: [PATCH 103/186] Move 3rd party plugins back below others --- docs/using.rst | 74 ++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 2c3465324..9371f44b4 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -82,39 +82,7 @@ manual_ Y N Helps you obtain a cert by giving you instructions to perf nginx_ Y Y Very experimental and not included in certbot-auto_. =========== ==== ==== =============================================================== -Third-party plugins -------------------- - -There are also a number of third-party plugins for the client, provided by other developers: - -=========== ==== ==== =============================================================== -Plugin Auth Inst Notes -=========== ==== ==== =============================================================== -plesk_ Y Y Integration with the Plesk web hosting tool -haproxy_ Y Y Integration with the HAProxy load balancer -s3front_ Y Y Integration with Amazon CloudFront distribution of S3 buckets -gandi_ Y Y Integration with Gandi's hosting products and API -varnish_ Y N Obtain certs via a Varnish server -external_ Y N A plugin for convenient scripting (See also ticket 2782_) -icecast_ N Y Deploy certs to Icecast 2 streaming media servers -pritunl_ N Y Install certs in pritunl distributed OpenVPN servers -proxmox_ N Y Install certs in Proxmox Virtualization servers -postfix_ N Y STARTTLS Everywhere is becoming a Certbot Postfix/Exim plugin -=========== ==== ==== =============================================================== - -.. _plesk: https://github.com/plesk/letsencrypt-plesk -.. _haproxy: https://code.greenhost.net/open/letsencrypt-haproxy -.. _s3front: https://github.com/dlapiduz/letsencrypt-s3front -.. _gandi: https://github.com/Gandi/letsencrypt-gandi -.. _icecast: https://github.com/e00E/lets-encrypt-icecast -.. _varnish: http://git.sesse.net/?p=letsencrypt-varnish-plugin -.. _2782: https://github.com/certbot/certbot/issues/2782 -.. _pritunl: https://github.com/kharkevich/letsencrypt-pritunl -.. _proxmox: https://github.com/kharkevich/letsencrypt-proxmox -.. _external: https://github.com/marcan/letsencrypt-external -.. _postfix: https://github.com/EFForg/starttls-everywhere - -If you're interested, you can also :ref:`write your own plugin `. +There are many third-party-plugins_ available. Apache ------ @@ -205,6 +173,46 @@ still experimental, however, and is not installed with certbot-auto_. If installed, you can select this plugin on the command line by including ``--nginx``. +.. _third-party-plugins: + +Third-party plugins +------------------- + +There are also a number of third-party plugins for the client, provided by +other developers. Many are beta/experimental, but some are already in +widespread use: + +=========== ==== ==== =============================================================== +Plugin Auth Inst Notes +=========== ==== ==== =============================================================== +plesk_ Y Y Integration with the Plesk web hosting tool +haproxy_ Y Y Integration with the HAProxy load balancer +s3front_ Y Y Integration with Amazon CloudFront distribution of S3 buckets +gandi_ Y Y Integration with Gandi's hosting products and API +varnish_ Y N Obtain certs via a Varnish server +external_ Y N A plugin for convenient scripting (See also ticket 2782_) +icecast_ N Y Deploy certs to Icecast 2 streaming media servers +pritunl_ N Y Install certs in pritunl distributed OpenVPN servers +proxmox_ N Y Install certs in Proxmox Virtualization servers +postfix_ N Y STARTTLS Everywhere is becoming a Certbot Postfix/Exim plugin +=========== ==== ==== =============================================================== + +.. _plesk: https://github.com/plesk/letsencrypt-plesk +.. _haproxy: https://code.greenhost.net/open/letsencrypt-haproxy +.. _s3front: https://github.com/dlapiduz/letsencrypt-s3front +.. _gandi: https://github.com/Gandi/letsencrypt-gandi +.. _icecast: https://github.com/e00E/lets-encrypt-icecast +.. _varnish: http://git.sesse.net/?p=letsencrypt-varnish-plugin +.. _2782: https://github.com/certbot/certbot/issues/2782 +.. _pritunl: https://github.com/kharkevich/letsencrypt-pritunl +.. _proxmox: https://github.com/kharkevich/letsencrypt-proxmox +.. _external: https://github.com/marcan/letsencrypt-external +.. _postfix: https://github.com/EFForg/starttls-everywhere + +If you're interested, you can also :ref:`write your own plugin `. + + + Renewal ======= From 1aff941ad090c7d7673b6f36bb5a2cc95cbdbad9 Mon Sep 17 00:00:00 2001 From: John Reed Date: Fri, 13 May 2016 18:37:43 -0500 Subject: [PATCH 104/186] Updating broken link to Google Python Style guide Old link: https://google-styleguide.googlecode.com/svn/trunk/pyguide.html New link: https://google.github.io/styleguide/pyguide.html --- docs/contributing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 49e9e146d..2ac38225c 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -297,7 +297,7 @@ Please: 4. Remember to use ``pylint``. .. _Google Python Style Guide: - https://google-styleguide.googlecode.com/svn/trunk/pyguide.html + https://google.github.io/styleguide/pyguide.html .. _Sphinx-style: http://sphinx-doc.org/ .. _PEP 8 - Style Guide for Python Code: https://www.python.org/dev/peps/pep-0008 From 3ddd97235642a5db872018a17b911620cfb58971 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 13 May 2016 18:19:57 -0700 Subject: [PATCH 105/186] Update the renewal-related message we print after obtaining a cert --- certbot/main.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/certbot/main.py b/certbot/main.py index 0405d6eb5..66804143c 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -97,7 +97,7 @@ def _auth_from_domains(le_client, config, domains, lineage=None): hooks.post_hook(config) 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): From f4103bdbb3163c6e62de5e5356d0b77a6d902d9e Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 13 May 2016 18:49:01 -0700 Subject: [PATCH 106/186] post-hook only runs if pre-hook was (or would have been, if it existed) --- certbot/cli.py | 3 ++- certbot/hooks.py | 7 ++++++- certbot/main.py | 2 +- certbot/tests/hook_test.py | 8 ++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/certbot/cli.py b/certbot/cli.py index d4695ba4d..41d31fa35 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -760,7 +760,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." diff --git a/certbot/hooks.py b/certbot/hooks.py index 138e2addc..f5c2e47ae 100644 --- a/certbot/hooks.py +++ b/certbot/hooks.py @@ -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) diff --git a/certbot/main.py b/certbot/main.py index 0405d6eb5..548243bf6 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -94,7 +94,7 @@ 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) diff --git a/certbot/tests/hook_test.py b/certbot/tests/hook_test.py index ce78b5dc9..be7fb852d 100644 --- a/certbot/tests/hook_test.py +++ b/certbot/tests/hook_test.py @@ -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) From 4cb35eaeb346e11963c59fd4aa5170a7e01f7190 Mon Sep 17 00:00:00 2001 From: Tapple Gao Date: Sun, 15 May 2016 11:44:48 +0200 Subject: [PATCH 107/186] system python path has changed on el capitan. Look for both old and new path --- letsencrypt-auto-source/pieces/bootstrappers/mac.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/letsencrypt-auto-source/pieces/bootstrappers/mac.sh b/letsencrypt-auto-source/pieces/bootstrappers/mac.sh index e41db04b1..2b04977c8 100755 --- a/letsencrypt-auto-source/pieces/bootstrappers/mac.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/mac.sh @@ -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..." From 8f696b3ad77dea64b19510bf084af28ea5f5a0b2 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sun, 15 May 2016 13:48:51 -0700 Subject: [PATCH 108/186] Reuse HTTP connections. (#2855) Fixes #2778 --- acme/acme/client.py | 6 +++- acme/acme/client_test.py | 63 +++++++++++++++++++++++----------------- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/acme/acme/client.py b/acme/acme/client.py index 225245686..117ee6b7d 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -512,6 +512,10 @@ class ClientNetwork(object): # pylint: disable=too-many-instance-attributes self.verify_ssl = verify_ssl self._nonces = set() self.user_agent = user_agent + self.session = requests.Session() + + def __del__(self): + self.session.close() def _wrap_in_jws(self, obj, nonce): """Wrap `JSONDeSerializable` object in JWS. @@ -606,7 +610,7 @@ class ClientNetwork(object): # pylint: disable=too-many-instance-attributes kwargs['verify'] = self.verify_ssl kwargs.setdefault('headers', {}) kwargs['headers'].setdefault('User-Agent', self.user_agent) - response = requests.request(method, url, *args, **kwargs) + response = self.session.request(method, url, *args, **kwargs) logging.debug('Received %s. Headers: %s. Content: %r', response, response.headers, response.content) return response diff --git a/acme/acme/client_test.py b/acme/acme/client_test.py index 7403cde81..33e80aab7 100644 --- a/acme/acme/client_test.py +++ b/acme/acme/client_test.py @@ -530,40 +530,49 @@ class ClientNetworkTest(unittest.TestCase): self.assertEqual( self.response, self.net._check_response(self.response)) - @mock.patch('acme.client.requests') - def test_send_request(self, mock_requests): - mock_requests.request.return_value = self.response + def test_send_request(self): + self.net.session = mock.MagicMock() + self.net.session.request.return_value = self.response # pylint: disable=protected-access self.assertEqual(self.response, self.net._send_request( - 'HEAD', 'url', 'foo', bar='baz')) - mock_requests.request.assert_called_once_with( - 'HEAD', 'url', 'foo', verify=mock.ANY, bar='baz', headers=mock.ANY) + 'HEAD', 'http://example.com/', 'foo', bar='baz')) + self.net.session.request.assert_called_once_with( + 'HEAD', 'http://example.com/', 'foo', + headers=mock.ANY, verify=mock.ANY, bar='baz') - @mock.patch('acme.client.requests') - def test_send_request_verify_ssl(self, mock_requests): + def test_send_request_verify_ssl(self): # pylint: disable=protected-access for verify in True, False: - mock_requests.request.reset_mock() - mock_requests.request.return_value = self.response + self.net.session = mock.MagicMock() + self.net.session.request.return_value = self.response self.net.verify_ssl = verify # pylint: disable=protected-access self.assertEqual( - self.response, self.net._send_request('GET', 'url')) - mock_requests.request.assert_called_once_with( - 'GET', 'url', verify=verify, headers=mock.ANY) + self.response, + self.net._send_request('GET', 'http://example.com/')) + self.net.session.request.assert_called_once_with( + 'GET', 'http://example.com/', verify=verify, headers=mock.ANY) - @mock.patch('acme.client.requests') - def test_send_request_user_agent(self, mock_requests): - mock_requests.request.return_value = self.response + def test_send_request_user_agent(self): + self.net.session = mock.MagicMock() # pylint: disable=protected-access - self.net._send_request('GET', 'url', headers={'bar': 'baz'}) - mock_requests.request.assert_called_once_with( - 'GET', 'url', verify=mock.ANY, + self.net._send_request('GET', 'http://example.com/', + headers={'bar': 'baz'}) + self.net.session.request.assert_called_once_with( + 'GET', 'http://example.com/', verify=mock.ANY, headers={'User-Agent': 'acme-python-test', 'bar': 'baz'}) - self.net._send_request('GET', 'url', headers={'User-Agent': 'foo2'}) - mock_requests.request.assert_called_with( - 'GET', 'url', verify=mock.ANY, headers={'User-Agent': 'foo2'}) + self.net._send_request('GET', 'http://example.com/', + headers={'User-Agent': 'foo2'}) + self.net.session.request.assert_called_with( + 'GET', 'http://example.com/', + verify=mock.ANY, headers={'User-Agent': 'foo2'}) + + def test_del(self): + sess = mock.MagicMock() + self.net.session = sess + del self.net + sess.close.assert_called_once() @mock.patch('acme.client.requests') def test_requests_error_passthrough(self, mock_requests): @@ -616,14 +625,16 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase): return self.checked_response def test_head(self): - self.assertEqual(self.response, self.net.head('url', 'foo', bar='baz')) + self.assertEqual(self.response, self.net.head( + 'http://example.com/', 'foo', bar='baz')) self.send_request.assert_called_once_with( - 'HEAD', 'url', 'foo', bar='baz') + 'HEAD', 'http://example.com/', 'foo', bar='baz') def test_get(self): self.assertEqual(self.checked_response, self.net.get( - 'url', content_type=self.content_type, bar='baz')) - self.send_request.assert_called_once_with('GET', 'url', bar='baz') + 'http://example.com/', content_type=self.content_type, bar='baz')) + self.send_request.assert_called_once_with( + 'GET', 'http://example.com/', bar='baz') def test_post(self): # pylint: disable=protected-access From f092669347291463047707551a736b21c8200de9 Mon Sep 17 00:00:00 2001 From: sagi Date: Mon, 16 May 2016 21:19:07 +0000 Subject: [PATCH 109/186] If cert_path provided - do not randomize it --- certbot/client.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/certbot/client.py b/certbot/client.py index 6f41a3a0b..fda7707f6 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -317,7 +317,13 @@ class Client(object): cert_pem = OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped) - cert_file, act_cert_path = le_util.unique_file(cert_path, 0o644) + + if cert_path != constants.CLI_DEFAULTS['auth_cert_path']: + cert_file = le_util.safe_open(cert_path, chmod=0o644) + act_cert_path = cert_path + else: + cert_file, act_cert_path = le_util.unique_file(cert_path, 0o644) + try: cert_file.write(cert_pem) finally: From d39dee20ad9c0c4ddde31bdaeeb35b49135e902d Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 16 May 2016 15:06:51 -0700 Subject: [PATCH 110/186] fix auto arg parsing --- letsencrypt-auto-source/letsencrypt-auto | 25 ++++++++++--------- .../letsencrypt-auto.template | 22 ++++++++-------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index b255a99a7..bbb2cda54 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -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,6 +54,17 @@ 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 @@ -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 diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 33b140bca..f24746b46 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -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,6 +54,17 @@ 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 From c0228ef1aa505a84a87529f76177f7dc6aa51214 Mon Sep 17 00:00:00 2001 From: sagi Date: Mon, 16 May 2016 22:11:15 +0000 Subject: [PATCH 111/186] Boulder integration scripts provides a cert_path --- tests/boulder-integration.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/boulder-integration.sh b/tests/boulder-integration.sh index 201343525..a1245e1c9 100755 --- a/tests/boulder-integration.sh +++ b/tests/boulder-integration.sh @@ -43,7 +43,7 @@ export CSR_PATH="${root}/csr.der" KEY_PATH="${root}/key.pem" \ common auth --csr "$CSR_PATH" \ --cert-path "${root}/csr/cert.pem" \ --chain-path "${root}/csr/chain.pem" -openssl x509 -in "${root}/csr/0000_cert.pem" -text +openssl x509 -in "${root}/csr/cert.pem" -text openssl x509 -in "${root}/csr/0000_chain.pem" -text common --domains le3.wtf install \ From 9efdd3b38fa0de68cd01930c9adec7728a372916 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 16 May 2016 17:34:30 -0700 Subject: [PATCH 112/186] Fixes 2977 --- certbot/renewal.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/certbot/renewal.py b/certbot/renewal.py index 3682c50d5..7e0da6afa 100644 --- a/certbot/renewal.py +++ b/certbot/renewal.py @@ -301,7 +301,8 @@ 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 != []: + if (config.domains != [] and + set(config.domains) != six.viewkeys(config.webroot_map)): 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 " From 323bb34144df2b77739dd29b475acac553d32d36 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 16 May 2016 17:45:52 -0700 Subject: [PATCH 113/186] Add test to prevent regressions --- certbot/tests/cli_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 31056cafe..d7965a24e 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -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: From b9c97954eeaabb51d36260a236eb7f562bad8729 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 16 May 2016 17:48:26 -0700 Subject: [PATCH 114/186] Add comment about removing the exception in the future --- certbot/renewal.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certbot/renewal.py b/certbot/renewal.py index 7e0da6afa..24cd67c78 100644 --- a/certbot/renewal.py +++ b/certbot/renewal.py @@ -301,6 +301,8 @@ def _renew_describe_results(config, renew_successes, renew_failures, def renew_all_lineages(config): """Examine each lineage; renew if due and report results""" + # If more plugins start using cli.add_domains, + # we may want to only log a warning here if (config.domains != [] and set(config.domains) != six.viewkeys(config.webroot_map)): raise errors.Error("Currently, the renew verb is only capable of " From accc83a1ca9dd7dcf8c815a8f5b24788ba94bb73 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 16 May 2016 18:03:17 -0700 Subject: [PATCH 115/186] add py2.6 compatibility --- certbot/renewal.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/certbot/renewal.py b/certbot/renewal.py index 24cd67c78..b5b982972 100644 --- a/certbot/renewal.py +++ b/certbot/renewal.py @@ -301,10 +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 more plugins start using cli.add_domains, - # we may want to only log a warning here - if (config.domains != [] and - set(config.domains) != six.viewkeys(config.webroot_map)): + # 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 " From 3cf3e5b685753b353c2afa42fd2472a61790b44a Mon Sep 17 00:00:00 2001 From: sagi Date: Tue, 17 May 2016 17:52:29 +0000 Subject: [PATCH 116/186] Detect RewriteEngine directives that originate in VirtualHosts --- certbot-apache/certbot_apache/configurator.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 26c3185be..cc269ff62 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -1177,10 +1177,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): From 886776d7415ec9fd2e33cfa57a9047f99da74bfc Mon Sep 17 00:00:00 2001 From: sagi Date: Tue, 17 May 2016 18:29:39 +0000 Subject: [PATCH 117/186] Make lint happy --- certbot-apache/certbot_apache/configurator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index cc269ff62..12125d522 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -1177,7 +1177,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): :type vhost: :class:`~certbot_apache.obj.VirtualHost` """ - rewrite_engine_path_list= self.parser.find_dir("RewriteEngine", "on", + rewrite_engine_path_list = self.parser.find_dir("RewriteEngine", "on", start=vhost.path) if rewrite_engine_path_list: for re_path in rewrite_engine_path_list: From 85e962455559e25933cdf4ef7ecf8d37c8a03bde Mon Sep 17 00:00:00 2001 From: chrismarget Date: Tue, 17 May 2016 19:50:57 +0000 Subject: [PATCH 118/186] Added test for random certificate serial numbers from gen_ss_cert. --- acme/acme/crypto_util_test.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/acme/acme/crypto_util_test.py b/acme/acme/crypto_util_test.py index 147cd5a2a..b41243b8f 100644 --- a/acme/acme/crypto_util_test.py +++ b/acme/acme/crypto_util_test.py @@ -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.certCount = 5 + self.serialNum = [] + 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.certCount): + cert = gen_ss_cert(self.key, ['dummy'], force_san=True) + self.serialNum.append(cert.get_serial_number()) + self.assertTrue(len(set(self.serialNum)) > 1) + + if __name__ == '__main__': unittest.main() # pragma: no cover From 6dd99913719df02d5fbee28952774cdbf16a596e Mon Sep 17 00:00:00 2001 From: chrismarget Date: Tue, 17 May 2016 20:10:20 +0000 Subject: [PATCH 119/186] Fix invalid attribute for pylint --- acme/acme/crypto_util_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/acme/acme/crypto_util_test.py b/acme/acme/crypto_util_test.py index b41243b8f..75a908d4f 100644 --- a/acme/acme/crypto_util_test.py +++ b/acme/acme/crypto_util_test.py @@ -132,18 +132,18 @@ class RandomSnTest(unittest.TestCase): """Test for random certificate serial numbers.""" def setUp(self): - self.certCount = 5 - self.serialNum = [] + 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.certCount): + for _ in range(self.cert_count): cert = gen_ss_cert(self.key, ['dummy'], force_san=True) - self.serialNum.append(cert.get_serial_number()) - self.assertTrue(len(set(self.serialNum)) > 1) + self.serial_num.append(cert.get_serial_number()) + self.assertTrue(len(set(self.serial_num)) > 1) if __name__ == '__main__': From 7e3c9399e54f2fb4960296e6211595707ff2dcf5 Mon Sep 17 00:00:00 2001 From: sagi Date: Tue, 17 May 2016 22:12:11 +0000 Subject: [PATCH 120/186] Use cli.set_by_cli to detect if the user explicitly set cert_path --- certbot/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/certbot/client.py b/certbot/client.py index fda7707f6..dd38e47b0 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -24,6 +24,7 @@ from certbot import interfaces from certbot import le_util from certbot import reverter from certbot import storage +from certbot import cli from certbot.display import ops as display_ops from certbot.display import enhancements @@ -318,7 +319,7 @@ class Client(object): cert_pem = OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped) - if cert_path != constants.CLI_DEFAULTS['auth_cert_path']: + if cli.set_by_cli('cert_path'): cert_file = le_util.safe_open(cert_path, chmod=0o644) act_cert_path = cert_path else: From 14778c15cef825e94255fd8b6913186eb977dbd0 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 17 May 2016 20:05:47 -0700 Subject: [PATCH 121/186] Run build to make le-auto up to date --- letsencrypt-auto-source/letsencrypt-auto | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index bbb2cda54..0f309243b 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -452,6 +452,11 @@ BootstrapMac() { fi } +BootstrapSmartOS() { + pkgin update + pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv' +} + # Install required OS packages: Bootstrap() { @@ -484,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 From af41345967ec5a9a00caf10d76b7537bef359f4f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 17 May 2016 20:06:35 -0700 Subject: [PATCH 122/186] Put arg parsing in one place --- letsencrypt-auto-source/letsencrypt-auto | 12 ++++++------ letsencrypt-auto-source/letsencrypt-auto.template | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 0f309243b..a85ca7695 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -68,6 +68,12 @@ for arg in "$@" ; do 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 diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 5a4ddee7d..62624a5a8 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -68,6 +68,12 @@ for arg in "$@" ; do 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 From 45b7c407c17bed5403f1245fd549f2ca0ebafb89 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 17 May 2016 20:07:06 -0700 Subject: [PATCH 123/186] Don't tell people you check for updates on every run --- letsencrypt-auto-source/letsencrypt-auto | 1 - letsencrypt-auto-source/letsencrypt-auto.template | 1 - 2 files changed, 2 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index a85ca7695..a6f15b552 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -931,7 +931,6 @@ else fi if [ "$NO_SELF_UPGRADE" != 1 ]; then - echo "Checking for new version..." TEMP_DIR=$(TempDir) # --------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py" diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 62624a5a8..ca9dfc289 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -288,7 +288,6 @@ else fi if [ "$NO_SELF_UPGRADE" != 1 ]; then - echo "Checking for new version..." TEMP_DIR=$(TempDir) # --------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py" From 502eba1cc41e10dc196ff936b3d8f0c639e4a41d Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 17 May 2016 20:07:45 -0700 Subject: [PATCH 124/186] Simplify SUDO certbot prompt --- letsencrypt-auto-source/letsencrypt-auto | 3 +-- letsencrypt-auto-source/letsencrypt-auto.template | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index a6f15b552..306dacdf2 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -899,13 +899,12 @@ UNLIKELY_EOF echo "Installation succeeded." fi echo "Requesting root privileges to run certbot..." + echo " $VENV_BIN/letsencrypt" "$@" 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 diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index ca9dfc289..bbba45f21 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -256,13 +256,12 @@ UNLIKELY_EOF echo "Installation succeeded." fi echo "Requesting root privileges to run certbot..." + echo " $VENV_BIN/letsencrypt" "$@" 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 From 507b1542760ca17443fb86363f51e83238f23e36 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 17 May 2016 20:11:02 -0700 Subject: [PATCH 125/186] Don't saying you're requesting root unless you really are --- letsencrypt-auto-source/letsencrypt-auto | 7 +++++-- letsencrypt-auto-source/letsencrypt-auto.template | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 306dacdf2..659600cdd 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -898,8 +898,11 @@ UNLIKELY_EOF fi echo "Installation succeeded." fi - echo "Requesting root privileges to run certbot..." - echo " $VENV_BIN/letsencrypt" "$@" + 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 $SUDO "$VENV_BIN/letsencrypt" "$@" diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index bbba45f21..f1ed82c4c 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -255,8 +255,11 @@ UNLIKELY_EOF fi echo "Installation succeeded." fi - echo "Requesting root privileges to run certbot..." - echo " $VENV_BIN/letsencrypt" "$@" + 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 $SUDO "$VENV_BIN/letsencrypt" "$@" From f55ef8e286b52165717b3879f33d3cd3596d193f Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Wed, 18 May 2016 11:03:18 +0300 Subject: [PATCH 126/186] Renewal hooks mean this note is outdated --- docs/using.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 12ea3ea11..12f6c7375 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -337,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: From 279cb352568a600ea79df47065be3967890ee109 Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Wed, 18 May 2016 11:05:23 +0300 Subject: [PATCH 127/186] Oops, ReST syntax is weird --- docs/using.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index 12f6c7375..b10532259 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -338,7 +338,7 @@ 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``. You can automate that with - `--renew-hook` if you're using automatic renewal_. + ``--renew-hook`` if you're using automatic renewal_. .. _config-file: From 321a806b9186572a9e9d735693bf9cd7c97bced3 Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Wed, 18 May 2016 11:57:50 +0300 Subject: [PATCH 128/186] Hook validation: skip leading spaces/newlines Improves the situation with #3020 a bit. Does nothing about other valid shell commands that the current validation would reject: - shell builtins like --post-hook 'if [ -x /my/script ]; then /my/script; fi' - variable assignments like --post-hook 'ENV_VAR=value command' - comments - redirections like --post-hook ' Date: Wed, 18 May 2016 09:56:34 -0700 Subject: [PATCH 129/186] Factor loading cert/req into its own function --- certbot/crypto_util.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/certbot/crypto_util.py b/certbot/crypto_util.py index 3f2267af2..41e675471 100644 --- a/certbot/crypto_util.py +++ b/certbot/crypto_util.py @@ -228,15 +228,20 @@ def pyopenssl_load_certificate(data): str(error) for error in openssl_errors))) -def _get_sans_from_cert_or_req(cert_or_req_str, load_func, - typ=OpenSSL.crypto.FILETYPE_PEM): +def _load_cert_or_req(cert_or_req_str, load_func, + typ=OpenSSL.crypto.FILETYPE_PEM): try: - cert_or_req = load_func(typ, cert_or_req_str) + return load_func(typ, cert_or_req_str) except OpenSSL.crypto.Error as error: logger.exception(error) raise + + +def _get_sans_from_cert_or_req(cert_or_req_str, load_func, + typ=OpenSSL.crypto.FILETYPE_PEM): # pylint: disable=protected-access - return acme_crypto_util._pyopenssl_cert_or_req_san(cert_or_req) + return acme_crypto_util._pyopenssl_cert_or_req_san(_load_cert_or_req( + cert_or_req_str, load_func, typ)) def get_sans_from_cert(cert, typ=OpenSSL.crypto.FILETYPE_PEM): From 8e17d7498de484857daead51b56f50b186341233 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 18 May 2016 10:14:15 -0700 Subject: [PATCH 130/186] Add get_names_from_csr --- certbot/crypto_util.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/certbot/crypto_util.py b/certbot/crypto_util.py index 41e675471..b273cf59f 100644 --- a/certbot/crypto_util.py +++ b/certbot/crypto_util.py @@ -272,6 +272,27 @@ def get_sans_from_csr(csr, typ=OpenSSL.crypto.FILETYPE_PEM): csr, OpenSSL.crypto.load_certificate_request, typ) +def get_names_from_csr(csr, typ=OpenSSL.crypto.FILETYPE_PEM): + """Get a list of domains from a CSR, including the CN if it is set. + + :param str csr: CSR (encoded). + :param typ: `OpenSSL.crypto.FILETYPE_PEM` or `OpenSSL.crypto.FILETYPE_ASN1` + + :returns: A list of domain names. + :rtype: list + + """ + loaded_csr = _load_cert_or_req( + csr, OpenSSL.crypto.load_certificate_request, typ) + common_name = loaded_csr.get_subject().CN + + # Use a set to avoid duplication with CN and Subject Alt Names + domains = set() if common_name is None else set((common_name,)) + # pylint: disable=protected-access + domains.update(acme_crypto_util._pyopenssl_cert_or_req_san(loaded_csr)) + return list(domains) + + def dump_pyopenssl_chain(chain, filetype=OpenSSL.crypto.FILETYPE_PEM): """Dump certificate chain into a bundle. From c4fc7b30e397b187dc20d45d20cc6254a359826b Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Wed, 18 May 2016 13:44:29 -0700 Subject: [PATCH 131/186] change github URL --- letsencrypt-auto-source/letsencrypt-auto | 11 +++++++++-- letsencrypt-auto-source/pieces/fetch.py | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index bbb2cda54..83e915e26 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -452,6 +452,11 @@ BootstrapMac() { fi } +BootstrapSmartOS() { + pkgin update + pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv' +} + # Install required OS packages: Bootstrap() { @@ -484,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 @@ -1017,7 +1024,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') diff --git a/letsencrypt-auto-source/pieces/fetch.py b/letsencrypt-auto-source/pieces/fetch.py index 38f4aa255..ca3e94b80 100644 --- a/letsencrypt-auto-source/pieces/fetch.py +++ b/letsencrypt-auto-source/pieces/fetch.py @@ -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') From 77e4be933cbfffaadda97d45e2dfb17672de56b5 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 18 May 2016 13:59:17 -0700 Subject: [PATCH 132/186] Simplify get_names_from_csr --- certbot/crypto_util.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/certbot/crypto_util.py b/certbot/crypto_util.py index b273cf59f..1f87dc816 100644 --- a/certbot/crypto_util.py +++ b/certbot/crypto_util.py @@ -284,10 +284,8 @@ def get_names_from_csr(csr, typ=OpenSSL.crypto.FILETYPE_PEM): """ loaded_csr = _load_cert_or_req( csr, OpenSSL.crypto.load_certificate_request, typ) - common_name = loaded_csr.get_subject().CN - # Use a set to avoid duplication with CN and Subject Alt Names - domains = set() if common_name is None else set((common_name,)) + domains = set(d for d in (loaded_csr.get_subject().CN,) if d is not None) # pylint: disable=protected-access domains.update(acme_crypto_util._pyopenssl_cert_or_req_san(loaded_csr)) return list(domains) From 94549219c593dfc687b01f65ee89dc2287dae06e Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 18 May 2016 14:06:32 -0700 Subject: [PATCH 133/186] Add get_names_from_csr tests --- certbot/tests/crypto_util_test.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/certbot/tests/crypto_util_test.py b/certbot/tests/crypto_util_test.py index ff8d8142e..eade4861f 100644 --- a/certbot/tests/crypto_util_test.py +++ b/certbot/tests/crypto_util_test.py @@ -234,6 +234,36 @@ class GetSANsFromCSRTest(unittest.TestCase): [], self._call(test_util.load_vector('csr-nosans.pem'))) +class GetNamesFromCSRTest(unittest.TestCase): + """Tests for certbot.crypto_util.get_names_from_csr.""" + @classmethod + def _call(cls, *args, **kwargs): + from certbot.crypto_util import get_names_from_csr + return get_names_from_csr(*args, **kwargs) + + def test_extract_one_san(self): + self.assertEqual(['example.com'], self._call( + test_util.load_vector('csr.pem'))) + + def test_extract_two_sans(self): + self.assertEqual(set(('example.com', 'www.example.com',)), set( + self._call(test_util.load_vector('csr-san.pem')))) + + def test_extract_six_sans(self): + self.assertEqual( + set(self._call(test_util.load_vector('csr-6sans.pem'))), + set(("example.com", "example.org", "example.net", + "example.info", "subdomain.example.com", + "other.subdomain.example.com",))) + + def test_parse_non_csr(self): + self.assertRaises(OpenSSL.crypto.Error, self._call, "hello there") + + def test_parse_no_sans(self): + self.assertEqual(["example.org"], + self._call(test_util.load_vector('csr-nosans.pem'))) + + class CertLoaderTest(unittest.TestCase): """Tests for certbot.crypto_util.pyopenssl_load_certificate""" From 01ebab26bfa0eee521e8767411419007efa50814 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Wed, 18 May 2016 14:21:57 -0700 Subject: [PATCH 134/186] update pypi for auto --- letsencrypt-auto-source/letsencrypt-auto | 11 +++++++++-- letsencrypt-auto-source/pieces/fetch.py | 2 +- letsencrypt-auto-source/tests/auto_test.py | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index bbb2cda54..dd7dc06ec 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -452,6 +452,11 @@ BootstrapMac() { fi } +BootstrapSmartOS() { + pkgin update + pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv' +} + # Install required OS packages: Bootstrap() { @@ -484,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 @@ -998,7 +1005,7 @@ def latest_stable_version(get): """Return the latest stable release of letsencrypt.""" metadata = loads(get( environ.get('LE_AUTO_JSON_URL', - 'https://pypi.python.org/pypi/letsencrypt/json'))) + 'https://pypi.python.org/pypi/certbot/json'))) # metadata['info']['version'] actually returns the latest of any kind of # release release, contrary to https://wiki.python.org/moin/PyPIJSON. # The regex is a sufficient regex for picking out prereleases for most diff --git a/letsencrypt-auto-source/pieces/fetch.py b/letsencrypt-auto-source/pieces/fetch.py index 38f4aa255..4a2287fff 100644 --- a/letsencrypt-auto-source/pieces/fetch.py +++ b/letsencrypt-auto-source/pieces/fetch.py @@ -68,7 +68,7 @@ def latest_stable_version(get): """Return the latest stable release of letsencrypt.""" metadata = loads(get( environ.get('LE_AUTO_JSON_URL', - 'https://pypi.python.org/pypi/letsencrypt/json'))) + 'https://pypi.python.org/pypi/certbot/json'))) # metadata['info']['version'] actually returns the latest of any kind of # release release, contrary to https://wiki.python.org/moin/PyPIJSON. # The regex is a sufficient regex for picking out prereleases for most diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index 3b7e8731b..2c733f858 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -183,7 +183,7 @@ def run_le_auto(venv_dir, base_url, **kwargs): d = dict(XDG_DATA_HOME=venv_dir, # URL to PyPI-style JSON that tell us the latest released version # of LE: - LE_AUTO_JSON_URL=base_url + 'letsencrypt/json', + LE_AUTO_JSON_URL=base_url + 'certbot/json', # URL to dir containing letsencrypt-auto and letsencrypt-auto.sig: LE_AUTO_DIR_TEMPLATE=base_url + '%s/', # The public key corresponding to signing.key: From df9174b81f18328fd5b85a57cf21f4247268cb04 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 18 May 2016 14:36:07 -0700 Subject: [PATCH 135/186] Fix whitespace --- certbot/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/cli.py b/certbot/cli.py index 41d31fa35..4585446bd 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -760,7 +760,7 @@ 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. This is only run if " + " 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", From 55755d818af57809cd23ec6ccff855ae8a30c50a Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Wed, 18 May 2016 15:42:55 -0700 Subject: [PATCH 136/186] update secret pypi? --- letsencrypt-auto-source/tests/auto_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index 2c733f858..8018bab0f 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -301,8 +301,8 @@ class AutoTests(TestCase): with ephemeral_dir() as venv_dir: # Serve an unrelated hash signed with the good key (easier than # making a bad key, and a mismatch is a mismatch): - resources = {'': 'letsencrypt/', - 'letsencrypt/json': dumps({'releases': {'99.9.9': None}}), + resources = {'': 'certbot/', + 'certbot/json': dumps({'releases': {'99.9.9': None}}), 'v99.9.9/letsencrypt-auto': build_le_auto(version='99.9.9'), 'v99.9.9/letsencrypt-auto.sig': signed('something else')} with serving(resources) as base_url: From e385274cca6814b3e910e82a09574fae349d68e2 Mon Sep 17 00:00:00 2001 From: Telepenin Nikolay Date: Thu, 19 May 2016 02:35:17 +0300 Subject: [PATCH 137/186] Error/Warning with build docker container from Dockerfile (#3004) When I try to build container I see in logs ``` debconf: unable to initialize frontend: Dialog debconf: (TERM is not set, so the dialog frontend is not usable.) debconf: falling back to frontend: Readline debconf: unable to initialize frontend: Readline debconf: (This frontend requires a controlling tty.) debconf: falling back to frontend: Teletype ``` `DEBIAN_FRONTEND=noninteractive` fixed this warning --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 3e4c9430e..d42b632d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,7 @@ WORKDIR /opt/certbot # If 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 && \ From e8e009cc854246e9b059783f77506328c417191c Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Wed, 18 May 2016 17:00:42 -0700 Subject: [PATCH 138/186] Revert "update secret pypi?" This reverts commit 55755d818af57809cd23ec6ccff855ae8a30c50a. --- letsencrypt-auto-source/tests/auto_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index 8018bab0f..2c733f858 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -301,8 +301,8 @@ class AutoTests(TestCase): with ephemeral_dir() as venv_dir: # Serve an unrelated hash signed with the good key (easier than # making a bad key, and a mismatch is a mismatch): - resources = {'': 'certbot/', - 'certbot/json': dumps({'releases': {'99.9.9': None}}), + resources = {'': 'letsencrypt/', + 'letsencrypt/json': dumps({'releases': {'99.9.9': None}}), 'v99.9.9/letsencrypt-auto': build_le_auto(version='99.9.9'), 'v99.9.9/letsencrypt-auto.sig': signed('something else')} with serving(resources) as base_url: From 574d20ecc46c989d4b8b7e808c668302f6e4d4ff Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 19 May 2016 09:28:26 -0700 Subject: [PATCH 139/186] Record enhancements applied to vhosts --- certbot-apache/certbot_apache/configurator.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 12125d522..bf9a388ee 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -124,6 +124,8 @@ 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 @@ -1058,9 +1060,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 +1082,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 +1121,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) @@ -1206,6 +1210,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 " From 66a13999208ed89a3664a009b589499338287bd0 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 19 May 2016 09:40:17 -0700 Subject: [PATCH 140/186] Add tests for multidomain vhost redirects --- .../certbot_apache/tests/configurator_test.py | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index f2f78c8f9..978d9f5c7 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -938,15 +938,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") From e7374811294be55b45d8de30a36883f836da6590 Mon Sep 17 00:00:00 2001 From: sagi Date: Thu, 19 May 2016 18:20:27 +0000 Subject: [PATCH 141/186] WIP --- certbot/client.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/certbot/client.py b/certbot/client.py index dd38e47b0..6dd0420eb 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -292,6 +292,7 @@ class Client(object): key.pem, crypto_util.dump_pyopenssl_chain(chain), configuration.RenewerConfiguration(self.config.namespace)) + def save_certificate(self, certr, chain_cert, cert_path, chain_path, fullchain_path): """Saves the certificate received from the ACME server. @@ -318,12 +319,15 @@ class Client(object): cert_pem = OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped) - + """ if cli.set_by_cli('cert_path'): cert_file = le_util.safe_open(cert_path, chmod=0o644) act_cert_path = cert_path else: cert_file, act_cert_path = le_util.unique_file(cert_path, 0o644) + """ + cert_file, act_cert_path = _open_pem_file('cert_path', cert_path) + #import ipdb; ipdb.set_trace try: cert_file.write(cert_pem) @@ -331,7 +335,14 @@ class Client(object): cert_file.close() logger.info("Server issued certificate; certificate written to %s", act_cert_path) - + + if cli.set_by_cli('chain_path'): + #import ipdb; ipdb.set_trace() + pass + if cli.set_by_cli('fullchain_path'): + #import ipdb; ipdb.set_trace() + pass + cert_chain_abspath = None fullchain_abspath = None if chain_cert: @@ -569,6 +580,11 @@ def view_config_changes(config, num=None): rev.recovery_routine() rev.view_config_changes(num) +def _open_pem_file(cli_arg_path, pem_path): + if cli.set_by_cli(cli_arg_path): + return le_util.safe_open(pem_path, chmod=0o644), pem_path + else: + return le_util.unique_file(pem_path, 0o644) def _save_chain(chain_pem, chain_path): """Saves chain_pem at a unique path based on chain_path. From 409640fb87a89487e46be0427c072a05074958a0 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 19 May 2016 12:05:42 -0700 Subject: [PATCH 142/186] le to cb for test package --- letsencrypt-auto-source/tests/auto_test.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index 2c733f858..357e8302c 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -258,9 +258,9 @@ class AutoTests(TestCase): with ephemeral_dir() as venv_dir: # This serves a PyPI page with a higher version, a GitHub-alike # with a corresponding le-auto script, and a matching signature. - resources = {'letsencrypt/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/letsencrypt-auto': NEW_LE_AUTO, - 'v99.9.9/letsencrypt-auto.sig': NEW_LE_AUTO_SIG} + resources = {'certbot/json': dumps({'releases': {'99.9.9': None}}), + 'v99.9.9/certbot-auto': NEW_LE_AUTO, + 'v99.9.9/certbot-auto.sig': NEW_LE_AUTO_SIG} with serving(resources) as base_url: run_letsencrypt_auto = partial( run_le_auto, @@ -301,10 +301,10 @@ class AutoTests(TestCase): with ephemeral_dir() as venv_dir: # Serve an unrelated hash signed with the good key (easier than # making a bad key, and a mismatch is a mismatch): - resources = {'': 'letsencrypt/', - 'letsencrypt/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/letsencrypt-auto': build_le_auto(version='99.9.9'), - 'v99.9.9/letsencrypt-auto.sig': signed('something else')} + resources = {'': 'certbot/', + 'certbot/json': dumps({'releases': {'99.9.9': None}}), + 'v99.9.9/certbot-auto': build_le_auto(version='99.9.9'), + 'v99.9.9/certbot-auto.sig': signed('something else')} with serving(resources) as base_url: copy(LE_AUTO_PATH, venv_dir) try: @@ -320,8 +320,8 @@ class AutoTests(TestCase): def test_pip_failure(self): """Make sure pip stops us if there is a hash mismatch.""" with ephemeral_dir() as venv_dir: - resources = {'': 'letsencrypt/', - 'letsencrypt/json': dumps({'releases': {'99.9.9': None}})} + resources = {'': 'certbot/', + 'certbot/json': dumps({'releases': {'99.9.9': None}})} with serving(resources) as base_url: # Build a le-auto script embedding a bad requirements file: install_le_auto( From fde151848d4b1a29ada511db77308979ba247989 Mon Sep 17 00:00:00 2001 From: sagi Date: Thu, 19 May 2016 19:11:25 +0000 Subject: [PATCH 143/186] Use set_by_cli for fullchain_path and chain_path --- certbot/client.py | 40 ++++++++++++++++------------------------ certbot/le_util.py | 3 ++- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/certbot/client.py b/certbot/client.py index 6dd0420eb..3475312f0 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -319,15 +319,8 @@ class Client(object): cert_pem = OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped) - """ - if cli.set_by_cli('cert_path'): - cert_file = le_util.safe_open(cert_path, chmod=0o644) - act_cert_path = cert_path - else: - cert_file, act_cert_path = le_util.unique_file(cert_path, 0o644) - """ + cert_file, act_cert_path = _open_pem_file('cert_path', cert_path) - #import ipdb; ipdb.set_trace try: cert_file.write(cert_pem) @@ -335,21 +328,20 @@ class Client(object): cert_file.close() logger.info("Server issued certificate; certificate written to %s", act_cert_path) - - if cli.set_by_cli('chain_path'): - #import ipdb; ipdb.set_trace() - pass - if cli.set_by_cli('fullchain_path'): - #import ipdb; ipdb.set_trace() - pass - + cert_chain_abspath = None fullchain_abspath = None if chain_cert: chain_pem = crypto_util.dump_pyopenssl_chain(chain_cert) - cert_chain_abspath = _save_chain(chain_pem, chain_path) + + chain_file, act_chain_path =\ + _open_pem_file('chain_path', chain_path) + fullchain_file, act_fullchain_path =\ + _open_pem_file('fullchain_path', fullchain_path) + + cert_chain_abspath = _save_chain(chain_pem, chain_file) fullchain_abspath = _save_chain(cert_pem + chain_pem, - fullchain_path) + fullchain_file) return os.path.abspath(act_cert_path), cert_chain_abspath, fullchain_abspath @@ -582,27 +574,27 @@ def view_config_changes(config, num=None): def _open_pem_file(cli_arg_path, pem_path): if cli.set_by_cli(cli_arg_path): - return le_util.safe_open(pem_path, chmod=0o644), pem_path + return le_util.safe_open(pem_path, chmod=0o644),\ + os.path.abspath(pem_path) else: return le_util.unique_file(pem_path, 0o644) -def _save_chain(chain_pem, chain_path): +def _save_chain(chain_pem, chain_file): """Saves chain_pem at a unique path based on chain_path. :param str chain_pem: certificate chain in PEM format - :param str chain_path: candidate path for the cert chain + :param str chain_file: chain file object :returns: absolute path to saved cert chain :rtype: str """ - chain_file, act_chain_path = le_util.unique_file(chain_path, 0o644) try: chain_file.write(chain_pem) finally: chain_file.close() - logger.info("Cert chain written to %s", act_chain_path) + logger.info("Cert chain written to %s", chain_file.name) # This expects a valid chain file - return os.path.abspath(act_chain_path) + return os.path.abspath(chain_file.name) diff --git a/certbot/le_util.py b/certbot/le_util.py index f5148b949..fe2577a4c 100644 --- a/certbot/le_util.py +++ b/certbot/le_util.py @@ -151,7 +151,8 @@ def _unique_file(path, filename_pat, count, mode): while True: current_path = os.path.join(path, filename_pat(count)) try: - return safe_open(current_path, chmod=mode), current_path + return safe_open(current_path, chmod=mode),\ + os.path.abspath(current_path) except OSError as err: # "File exists," is okay, try a different name. if err.errno != errno.EEXIST: From 0bb8b0bcd5231c896ee9449bac22d30204381dac Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 19 May 2016 12:27:17 -0700 Subject: [PATCH 144/186] change invocation --- letsencrypt-auto-source/tests/auto_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index 357e8302c..6fccdb56e 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -199,7 +199,7 @@ iQIDAQAB **kwargs) env.update(d) return out_and_err( - join(venv_dir, 'letsencrypt-auto') + ' --version', + join(venv_dir, 'certbot-auto') + ' --version', shell=True, env=env) From e1eb3eff164610b7359582478d02c3fbf4b8c6b9 Mon Sep 17 00:00:00 2001 From: sagi Date: Thu, 19 May 2016 19:27:18 +0000 Subject: [PATCH 145/186] Improve code reuse --- certbot/client.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/certbot/client.py b/certbot/client.py index 3475312f0..ee1ab8bb8 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -320,30 +320,27 @@ class Client(object): cert_pem = OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped) - cert_file, act_cert_path = _open_pem_file('cert_path', cert_path) + cert_file, abs_cert_path = _open_pem_file('cert_path', cert_path) try: cert_file.write(cert_pem) finally: cert_file.close() logger.info("Server issued certificate; certificate written to %s", - act_cert_path) + abs_cert_path) - cert_chain_abspath = None - fullchain_abspath = None if chain_cert: chain_pem = crypto_util.dump_pyopenssl_chain(chain_cert) - chain_file, act_chain_path =\ + chain_file, abs_chain_path =\ _open_pem_file('chain_path', chain_path) - fullchain_file, act_fullchain_path =\ + fullchain_file, abs_fullchain_path =\ _open_pem_file('fullchain_path', fullchain_path) - cert_chain_abspath = _save_chain(chain_pem, chain_file) - fullchain_abspath = _save_chain(cert_pem + chain_pem, - fullchain_file) + _save_chain(chain_pem, chain_file) + _save_chain(cert_pem + chain_pem, fullchain_file - return os.path.abspath(act_cert_path), cert_chain_abspath, fullchain_abspath + return abs_cert_path, abs_chain_path, abs_fullchain_path def deploy_certificate(self, domains, privkey_path, cert_path, chain_path, fullchain_path): @@ -577,7 +574,8 @@ def _open_pem_file(cli_arg_path, pem_path): return le_util.safe_open(pem_path, chmod=0o644),\ os.path.abspath(pem_path) else: - return le_util.unique_file(pem_path, 0o644) + uniq = le_util.unique_file(pem_path, 0o644) + return uniq[0], os.path.abspath(uniq) def _save_chain(chain_pem, chain_file): """Saves chain_pem at a unique path based on chain_path. @@ -585,9 +583,6 @@ def _save_chain(chain_pem, chain_file): :param str chain_pem: certificate chain in PEM format :param str chain_file: chain file object - :returns: absolute path to saved cert chain - :rtype: str - """ try: chain_file.write(chain_pem) @@ -595,6 +590,3 @@ def _save_chain(chain_pem, chain_file): chain_file.close() logger.info("Cert chain written to %s", chain_file.name) - - # This expects a valid chain file - return os.path.abspath(chain_file.name) From 501c19ef2a254e44b768eb4cd57e5832f5afb792 Mon Sep 17 00:00:00 2001 From: sagi Date: Thu, 19 May 2016 19:33:04 +0000 Subject: [PATCH 146/186] Syntax --- certbot/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/client.py b/certbot/client.py index ee1ab8bb8..8964686e6 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -338,7 +338,7 @@ class Client(object): _open_pem_file('fullchain_path', fullchain_path) _save_chain(chain_pem, chain_file) - _save_chain(cert_pem + chain_pem, fullchain_file + _save_chain(cert_pem + chain_pem, fullchain_file) return abs_cert_path, abs_chain_path, abs_fullchain_path From 3589b25dc3a7d4c0fb2477b21d6039a327bd1b52 Mon Sep 17 00:00:00 2001 From: sagi Date: Thu, 19 May 2016 19:35:38 +0000 Subject: [PATCH 147/186] Make lint happy --- certbot/client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/certbot/client.py b/certbot/client.py index 8964686e6..4fc662948 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -292,7 +292,6 @@ class Client(object): key.pem, crypto_util.dump_pyopenssl_chain(chain), configuration.RenewerConfiguration(self.config.namespace)) - def save_certificate(self, certr, chain_cert, cert_path, chain_path, fullchain_path): """Saves the certificate received from the ACME server. From ad76de2502596a9ed76b9785108964f79882c21b Mon Sep 17 00:00:00 2001 From: Sagi Kedmi Date: Thu, 19 May 2016 16:04:18 -0700 Subject: [PATCH 148/186] OCSP Stapling Enhancement for Apache (#2723) Currently supports only Apache >=2.3.3. letsencrypt --staple-ocsp -d dumpbits.com [no problem to set it on for apache => 2.3.3] To check OCSP Stapling: [~]$ echo QUIT | openssl s_client -connect dumpbits.com:443 -status 2>/dev/null | grep -A 31 'OCSP Resp' OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 Produced At: Mar 26 17:54:00 2016 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 7EE66AE7729AB3FCF8A220646C16A12D6071085D Issuer Key Hash: A84A6A63047DDDBAE6D139B7A64565EFF3A8ECA1 Serial Number: 032A2108AAA650E6EE2E6B041C03C2612A19 Cert Status: good This Update: Mar 26 17:00:00 2016 GMT Next Update: Apr 2 17:00:00 2016 GMT Signature Algorithm: sha256WithRSAEncryption 64:f2:71:02:6a:97:d9:eb:13:c1:5c:7a:f5:eb:26:89:3b:40: e3:08:82:f7:71:d4:fa:61:4a:8e:4a:7d:e9:53:84:e9:3a:89: 67:66:08:d9:0e:79:65:9a:8d:dc:fb:07:cc:93:4f:eb:4e:3c: cc:7f:cd:fd:db:8f:c3:25:c3:54:87:a9:9c:35:6f:c1:39:31: e0:b1:f6:b1:3d:52:5d:db:bb:69:0f:23:05:fe:33:29:1f:ff: c6:af:17:a5:98:58:50:3a:48:93:5c:09:4b:f3:91:36:48:31: ed:ee:47:4d:66:c3:25:cf:56:b7:f4:48:80:eb:b8:f0:27:b1: 97:18:b4:88:71:c6:55:5d:bb:25:16:48:98:85:8a:12:8d:64: bf:51:df:39:b1:44:91:e1:f2:c6:c3:7d:23:2b:d2:0f:4c:7f: 57:b1:c9:ae:ec:32:b5:6a:87:bd:83:43:f1:f7:3c:8c:11:5c: 9d:a5:12:fa:e6:79:87:45:c6:1d:46:c8:14:1e:8d:d1:de:7a: 0d:e4:53:f2:c9:b6:e5:6e:cb:91:14:bb:04:38:36:4f:71:55: e1:ff:71:c7:a6:31:ed:db:6c:0f:d7:f5:ef:0c:6e:08:6b:e0: 37:cf:ca:a5:67:89:c2:de:8e:36:6d:2f:41:7f:9f:10:c6:de: 4d:b1:2d:09 ====================================== --- certbot-apache/certbot_apache/configurator.py | 69 ++++++++- .../certbot_apache/tests/configurator_test.py | 141 +++++++++++++++--- .../apache2/sites-available/ocsp-ssl.conf | 36 +++++ .../apache2/sites-enabled/ocsp-ssl.conf | 1 + .../debian_apache_2_4/multiple_vhosts/sites | 1 + certbot-apache/certbot_apache/tests/util.py | 8 +- certbot/cli.py | 13 +- certbot/client.py | 7 +- 8 files changed, 246 insertions(+), 30 deletions(-) create mode 100644 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/ocsp-ssl.conf create mode 120000 certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-enabled/ocsp-ssl.conf diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 12125d522..cacd54d5b 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -130,7 +130,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): 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 +594,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 +945,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 +972,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. diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index f2f78c8f9..4d07d1fb1 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -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( @@ -957,7 +1054,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 +1065,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 diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/ocsp-ssl.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/ocsp-ssl.conf new file mode 100644 index 000000000..631cf16c8 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-available/ocsp-ssl.conf @@ -0,0 +1,36 @@ + +SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000) + + # The ServerName directive sets the request scheme, hostname and port that + # the server uses to identify itself. This is used when creating + # redirection URLs. In the context of virtual hosts, the ServerName + # specifies what hostname must appear in the request's Host: header to + # match this virtual host. For the default virtual host (this file) this + # value is not decisive as it is used as a last resort host regardless. + # However, you must set it for any further virtual host explicitly. + ServerName ocspvhost.com + + ServerAdmin webmaster@dumpbits.com + DocumentRoot /var/www/html + + # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, + # error, crit, alert, emerg. + # It is also possible to configure the loglevel for particular + # modules, e.g. + #LogLevel info ssl:warn + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + # For most configuration files from conf-available/, which are + # enabled or disabled at a global level, it is possible to + # include a line for only one particular virtual host. For example the + # following line enables the CGI configuration for this host only + # after it has been globally disabled with "a2disconf". + #Include conf-available/serve-cgi-bin.conf +SSLCertificateFile /etc/apache2/certs/certbot-cert_5.pem +SSLCertificateKeyFile /etc/apache2/ssl/key-certbot_15.pem +SSLUseStapling on + +# vim: syntax=apache ts=4 sw=4 sts=4 sr noet + diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-enabled/ocsp-ssl.conf b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-enabled/ocsp-ssl.conf new file mode 120000 index 000000000..b25ee0482 --- /dev/null +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/apache2/sites-enabled/ocsp-ssl.conf @@ -0,0 +1 @@ +../sites-available/ocsp-ssl.conf \ No newline at end of file diff --git a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/sites b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/sites index 06bf6a2ae..ab518ee5b 100644 --- a/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/sites +++ b/certbot-apache/certbot_apache/tests/testdata/debian_apache_2_4/multiple_vhosts/sites @@ -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 diff --git a/certbot-apache/certbot_apache/tests/util.py b/certbot-apache/certbot_apache/tests/util.py index 9fb5dcdfa..8935ee908 100644 --- a/certbot-apache/certbot_apache/tests/util.py +++ b/certbot-apache/certbot_apache/tests/util.py @@ -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 diff --git a/certbot/cli.py b/certbot/cli.py index e15725ece..5dbad3ed4 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -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 " diff --git a/certbot/client.py b/certbot/client.py index 6f41a3a0b..0159d3946 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -396,7 +396,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") @@ -410,9 +411,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() From 22badb2380bc405032d47e9f90212a0f1a507fad Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Thu, 19 May 2016 17:29:39 -0700 Subject: [PATCH 149/186] tests pass? --- letsencrypt-auto-source/tests/auto_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py index 6fccdb56e..7e131f4cf 100644 --- a/letsencrypt-auto-source/tests/auto_test.py +++ b/letsencrypt-auto-source/tests/auto_test.py @@ -199,7 +199,7 @@ iQIDAQAB **kwargs) env.update(d) return out_and_err( - join(venv_dir, 'certbot-auto') + ' --version', + join(venv_dir, 'letsencrypt-auto') + ' --version', shell=True, env=env) @@ -259,8 +259,8 @@ class AutoTests(TestCase): # This serves a PyPI page with a higher version, a GitHub-alike # with a corresponding le-auto script, and a matching signature. resources = {'certbot/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/certbot-auto': NEW_LE_AUTO, - 'v99.9.9/certbot-auto.sig': NEW_LE_AUTO_SIG} + 'v99.9.9/letsencrypt-auto': NEW_LE_AUTO, + 'v99.9.9/letsencrypt-auto.sig': NEW_LE_AUTO_SIG} with serving(resources) as base_url: run_letsencrypt_auto = partial( run_le_auto, @@ -303,8 +303,8 @@ class AutoTests(TestCase): # making a bad key, and a mismatch is a mismatch): resources = {'': 'certbot/', 'certbot/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/certbot-auto': build_le_auto(version='99.9.9'), - 'v99.9.9/certbot-auto.sig': signed('something else')} + 'v99.9.9/letsencrypt-auto': build_le_auto(version='99.9.9'), + 'v99.9.9/letsencrypt-auto.sig': signed('something else')} with serving(resources) as base_url: copy(LE_AUTO_PATH, venv_dir) try: From 7689de2ad8da074015df2150b455115f3b5816b5 Mon Sep 17 00:00:00 2001 From: sagi Date: Fri, 20 May 2016 01:18:50 +0000 Subject: [PATCH 150/186] Fix tests --- certbot/client.py | 12 +++++++++++- certbot/tests/client_test.py | 8 +++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/certbot/client.py b/certbot/client.py index 4fc662948..818701f08 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -569,12 +569,22 @@ def view_config_changes(config, num=None): rev.view_config_changes(num) def _open_pem_file(cli_arg_path, pem_path): + """Open a pem file. + + If cli_arg_path was set by the client, open that. + Otherwise, uniquify the file path. + + :param str cli_arg_path: the cli arg name, e.g. cert_path + :param str pem_path: the pem file path to open + + :returns a file object + """ if cli.set_by_cli(cli_arg_path): return le_util.safe_open(pem_path, chmod=0o644),\ os.path.abspath(pem_path) else: uniq = le_util.unique_file(pem_path, 0o644) - return uniq[0], os.path.abspath(uniq) + return uniq[0], os.path.abspath(uniq[1]) def _save_chain(chain_pem, chain_file): """Saves chain_pem at a unique path based on chain_path. diff --git a/certbot/tests/client_test.py b/certbot/tests/client_test.py index 8ceefe8ae..49596fdee 100644 --- a/certbot/tests/client_test.py +++ b/certbot/tests/client_test.py @@ -221,7 +221,9 @@ class ClientTest(unittest.TestCase): mock.sentinel.key, domains, self.config.csr_dir) self._check_obtain_certificate() - def test_save_certificate(self): + @mock.patch("certbot.cli.helpful_parser") + def test_save_certificate(self, mock_parser): + # pylint: disable=too-many-locals certs = ["matching_cert.pem", "cert.pem", "cert-san.pem"] tmp_path = tempfile.mkdtemp() os.chmod(tmp_path, 0o755) # TODO: really?? @@ -232,6 +234,10 @@ class ClientTest(unittest.TestCase): candidate_cert_path = os.path.join(tmp_path, "certs", "cert.pem") candidate_chain_path = os.path.join(tmp_path, "chains", "chain.pem") candidate_fullchain_path = os.path.join(tmp_path, "chains", "fullchain.pem") + mock_parser.verb = "certonly" + mock_parser.args = ["--cert-path", candidate_cert_path, + "--chain-path", candidate_chain_path, + "--fullchain-path", candidate_fullchain_path] cert_path, chain_path, fullchain_path = self.client.save_certificate( certr, chain_cert, candidate_cert_path, candidate_chain_path, From 46be2df1999e65e49e6194484f7bee5fea894fcb Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Fri, 20 May 2016 13:25:34 -0700 Subject: [PATCH 151/186] fix syntax error --- certbot/reverter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/reverter.py b/certbot/reverter.py index fe6d9f24f..b023d18a7 100644 --- a/certbot/reverter.py +++ b/certbot/reverter.py @@ -489,7 +489,7 @@ class Reverter(object): if not os.path.exists(changes_since_path): logger.info("Rollback checkpoint is empty (no changes made?)") - with open(self.config.changes_since_path) as f: + with open(changes_since_path, 'w') as f: f.write("No changes\n") # Add title to self.config.in_progress_dir CHANGES_SINCE From 32d32dbc1279603a8cdc0cef7e0a0c42563f71ba Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 20 May 2016 15:20:28 -0700 Subject: [PATCH 152/186] cli.py PEP8 fixes --- certbot/cli.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/certbot/cli.py b/certbot/cli.py index af4cd3013..3bd565496 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -347,7 +347,6 @@ class HelpfulArgumentParser(object): return parsed_args - def set_test_server(self, parsed_args): """We have --staging/--dry-run; perform sanity check and set config.server""" @@ -370,7 +369,6 @@ class HelpfulArgumentParser(object): parsed_args.tos = True parsed_args.register_unsafely_without_email = True - def handle_csr(self, parsed_args): """Process a --csr flag.""" if parsed_args.verb != "certonly": From 73c4e8f7a40b34e8dfed12d0e784e1aef0d25523 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 20 May 2016 16:24:49 -0700 Subject: [PATCH 153/186] Cleanup test_obtain_certificate_from_csr --- certbot/tests/client_test.py | 74 +++++++++++++----------------------- 1 file changed, 27 insertions(+), 47 deletions(-) diff --git a/certbot/tests/client_test.py b/certbot/tests/client_test.py index 148857be7..b7195a777 100644 --- a/certbot/tests/client_test.py +++ b/certbot/tests/client_test.py @@ -134,59 +134,39 @@ class ClientTest(unittest.TestCase): self.acme.fetch_chain.assert_called_once_with(mock.sentinel.certr) - # FIXME move parts of this to crypto_util tests... @mock.patch("certbot.client.logger") def test_obtain_certificate_from_csr(self, mock_logger): self._mock_obtain_certificate() - from certbot import cli test_csr = le_util.CSR(form="der", file=None, data=CSR_SAN) - mock_parsed_args = mock.MagicMock() - # The CLI should believe that this is a certonly request, because - # a CSR would not be allowed with other kinds of requests! - mock_parsed_args.verb = "certonly" - with mock.patch("certbot.cli.crypto_util.le_util.CSR") as mock_CSR: - mock_CSR.return_value = test_csr - mock_parsed_args.domains = self.eg_domains[:] - mock_parsed_args.allow_subset_of_names = False - mock_parsed_args.csr = (mock.MagicMock(), mock.MagicMock()) - mock_parser = mock.MagicMock(cli.HelpfulArgumentParser) - cli.HelpfulArgumentParser.handle_csr(mock_parser, mock_parsed_args) + auth_handler = self.client.auth_handler - # Now provoke an inconsistent domains error... - mock_parsed_args.domains.append("hippopotamus.io") - self.assertRaises(errors.ConfigurationError, - cli.HelpfulArgumentParser.handle_csr, mock_parser, mock_parsed_args) - - authzr = self.client.auth_handler.get_authorizations(self.eg_domains, False) - - self.assertEqual( - (mock.sentinel.certr, mock.sentinel.chain), - self.client.obtain_certificate_from_csr( - self.eg_domains, - test_csr, - authzr=authzr)) - # and that the cert was obtained correctly - self._check_obtain_certificate() - - # Test for authzr=None - self.assertEqual( - (mock.sentinel.certr, mock.sentinel.chain), - self.client.obtain_certificate_from_csr( - self.eg_domains, - test_csr, - authzr=None)) - - self.client.auth_handler.get_authorizations.assert_called_with( - self.eg_domains) - - # Test for no auth_handler - self.client.auth_handler = None - self.assertRaises( - errors.Error, - self.client.obtain_certificate_from_csr, + authzr = auth_handler.get_authorizations(self.eg_domains, False) + self.assertEqual( + (mock.sentinel.certr, mock.sentinel.chain), + self.client.obtain_certificate_from_csr( self.eg_domains, - test_csr) - mock_logger.warning.assert_called_once_with(mock.ANY) + test_csr, + authzr=authzr)) + # and that the cert was obtained correctly + self._check_obtain_certificate() + + # Test for authzr=None + self.assertEqual( + (mock.sentinel.certr, mock.sentinel.chain), + self.client.obtain_certificate_from_csr( + self.eg_domains, + test_csr, + authzr=None)) + auth_handler.get_authorizations.assert_called_with(self.eg_domains) + + # Test for no auth_handler + self.client.auth_handler = None + self.assertRaises( + errors.Error, + self.client.obtain_certificate_from_csr, + self.eg_domains, + test_csr) + mock_logger.warning.assert_called_once_with(mock.ANY) @mock.patch("certbot.client.crypto_util") def test_obtain_certificate(self, mock_crypto_util): From 53286863fefa47b7464340b8b46bbd93b5358932 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 20 May 2016 16:26:09 -0700 Subject: [PATCH 154/186] Simplify import_csr_file --- certbot/crypto_util.py | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/certbot/crypto_util.py b/certbot/crypto_util.py index ba368b15b..68e07e059 100644 --- a/certbot/crypto_util.py +++ b/certbot/crypto_util.py @@ -180,33 +180,28 @@ def csr_matches_pubkey(csr, privkey): return False -def import_csr_file(csrfile, contents): +def import_csr_file(csrfile, data): """Import a CSR file, which can be either PEM or DER. :param str csrfile: CSR filename - :param str contents: contens of the CSR file + :param str data: contents of the CSR file - :returns: (le_util.CSR object representing the CSR, - `OpenSSL.crypto.FILETYPE_PEM` or `OpenSSL.crypto.FILETYPE_ASN1`, + :returns: (`OpenSSL.crypto.FILETYPE_PEM` or `OpenSSL.crypto.FILETYPE_ASN1`, + le_util.CSR object representing the CSR, list of domains requested in the CSR) - :rtype: tuple + """ - try: - csr = le_util.CSR(file=csrfile, data=contents, form="der") - typ = OpenSSL.crypto.FILETYPE_ASN1 - domains = get_sans_from_csr(csr.data, OpenSSL.crypto.FILETYPE_ASN1) - except OpenSSL.crypto.Error: + for form, typ in (("der", OpenSSL.crypto.FILETYPE_ASN1,), + ("pem", OpenSSL.crypto.FILETYPE_PEM,),): try: - e1 = traceback.format_exc() - typ = OpenSSL.crypto.FILETYPE_PEM - csr = le_util.CSR(file=csrfile, data=contents, form="pem") - domains = get_sans_from_csr(csr.data, typ) + domains = get_names_from_csr(data, typ) except OpenSSL.crypto.Error: - logger.debug("DER CSR parse error %s", e1) - logger.debug("PEM CSR parse error %s", traceback.format_exc()) - raise errors.Error("Failed to parse CSR file: {0}".format(csrfile)) - return typ, csr, domains + logger.debug("CSR parse error (form=%s, typ=%s):", form, typ) + logger.debug(traceback.format_exc()) + continue + return typ, le_util.CSR(file=csrfile, data=data, form=form), domains + raise errors.Error("Failed to parse CSR file: {0}".format(csrfile)) def make_key(bits): From 271316a41343593e598f721f3aee3e1621b987e9 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Fri, 20 May 2016 16:32:39 -0700 Subject: [PATCH 155/186] cover test --- certbot/reverter.py | 1 + certbot/tests/reverter_test.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/certbot/reverter.py b/certbot/reverter.py index b023d18a7..16ee5d8a4 100644 --- a/certbot/reverter.py +++ b/certbot/reverter.py @@ -7,6 +7,7 @@ import shutil import time import traceback + import zope.component from certbot import constants diff --git a/certbot/tests/reverter_test.py b/certbot/tests/reverter_test.py index eda5ffb36..c79c72a48 100644 --- a/certbot/tests/reverter_test.py +++ b/certbot/tests/reverter_test.py @@ -34,6 +34,20 @@ class ReverterCheckpointLocalTest(unittest.TestCase): logging.disable(logging.NOTSET) + @mock.patch("certbot.reverter.Reverter._read_and_append") + def test_no_change(self, mock_read): + mock_read.side_effect = OSError("cannot even") + try: + self.reverter.add_to_checkpoint(self.sets[0], "save1") + except: + pass + self.reverter.finalize_checkpoint("blah") + path = os.listdir(self.reverter.config.backup_dir)[0] + no_change = os.path.join(self.reverter.config.backup_dir, path, "CHANGES_SINCE") + with open(no_change, "r") as f: + x = f.read() + self.assertTrue("No changes" in x) + def test_basic_add_to_temp_checkpoint(self): # These shouldn't conflict even though they are both named config.txt self.reverter.add_to_temp_checkpoint(self.sets[0], "save1") From a48afd498c9c7a022eff72d8f903879f824cbe14 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 20 May 2016 16:52:35 -0700 Subject: [PATCH 156/186] Start import_csr_file tests --- certbot/tests/crypto_util_test.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/certbot/tests/crypto_util_test.py b/certbot/tests/crypto_util_test.py index eade4861f..af8308fd8 100644 --- a/certbot/tests/crypto_util_test.py +++ b/certbot/tests/crypto_util_test.py @@ -10,6 +10,7 @@ import zope.component from certbot import errors from certbot import interfaces +from certbot import le_util from certbot.tests import test_util @@ -159,6 +160,27 @@ class CSRMatchesPubkeyTest(unittest.TestCase): test_util.load_vector('csr.pem'), RSA256_KEY)) +class ImportCSRFileTest(unittest.TestCase): + """Tests for certbot.certbot_util.import_csr_file.""" + + @classmethod + def _call(cls, *args, **kwargs): + from certbot.crypto_util import import_csr_file + return import_csr_file(*args, **kwargs) + + def test_der_csr(self): + csrfile = test_util.vector_path('csr.der') + data = test_util.load_vector('csr.der') + + self.assertEqual( + (OpenSSL.crypto.FILETYPE_ASN1, + le_util.CSR(file=csrfile, + data=data, + form="der"), + ["example.com"],), + self._call(csrfile, data)) + + class MakeKeyTest(unittest.TestCase): # pylint: disable=too-few-public-methods """Tests for certbot.crypto_util.make_key.""" From 953d4957b8e32a74d894c2d3eeab56e0105ebf94 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 20 May 2016 16:57:13 -0700 Subject: [PATCH 157/186] Add csr test --- certbot/tests/crypto_util_test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/certbot/tests/crypto_util_test.py b/certbot/tests/crypto_util_test.py index af8308fd8..d5a016320 100644 --- a/certbot/tests/crypto_util_test.py +++ b/certbot/tests/crypto_util_test.py @@ -180,6 +180,18 @@ class ImportCSRFileTest(unittest.TestCase): ["example.com"],), self._call(csrfile, data)) + def test_pem_csr(self): + csrfile = test_util.vector_path('csr.pem') + data = test_util.load_vector('csr.pem') + + self.assertEqual( + (OpenSSL.crypto.FILETYPE_PEM, + le_util.CSR(file=csrfile, + data=data, + form="pem"), + ["example.com"],), + self._call(csrfile, data)) + class MakeKeyTest(unittest.TestCase): # pylint: disable=too-few-public-methods """Tests for certbot.crypto_util.make_key.""" From 2c4c8c081c80d00be04149afd7da2396f52a0a93 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 20 May 2016 17:00:06 -0700 Subject: [PATCH 158/186] Test bad csr --- certbot/tests/crypto_util_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certbot/tests/crypto_util_test.py b/certbot/tests/crypto_util_test.py index d5a016320..eeea0f4ab 100644 --- a/certbot/tests/crypto_util_test.py +++ b/certbot/tests/crypto_util_test.py @@ -192,6 +192,11 @@ class ImportCSRFileTest(unittest.TestCase): ["example.com"],), self._call(csrfile, data)) + def test_bad_csr(self): + self.assertRaises(errors.Error, self._call, + test_util.vector_path('cert.pem'), + test_util.load_vector('cert.pem')) + class MakeKeyTest(unittest.TestCase): # pylint: disable=too-few-public-methods """Tests for certbot.crypto_util.make_key.""" From 3c11733006b03da942d0ee43a8d16c1c6bd40d77 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 20 May 2016 17:32:37 -0700 Subject: [PATCH 159/186] fix --csr and --allow-subset-of-names test --- certbot/tests/cli_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index d7965a24e..62ec36d2a 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -349,8 +349,9 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods ['-d', '204.11.231.35']) def test_csr_with_besteffort(self): - args = ["--csr", CSR, "--allow-subset-of-names"] - self.assertRaises(errors.Error, self._call, args) + self.assertRaises( + errors.Error, self._call, + 'certonly --csr {0} --allow-subset-of-names'.format(CSR).split()) def test_run_with_csr(self): # This is an error because you can only use --csr with certonly From 0b85a8f1c8d26accccd148701f2e7ddd6065a6e2 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 20 May 2016 17:37:48 -0700 Subject: [PATCH 160/186] Add a test for a CSR with no domains --- certbot/tests/cli_test.py | 6 ++++++ certbot/tests/testdata/csr-nonames.pem | 8 ++++++++ 2 files changed, 14 insertions(+) create mode 100644 certbot/tests/testdata/csr-nonames.pem diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 62ec36d2a..c24da4989 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -362,6 +362,12 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods return assert False, "Expected supplying --csr to fail with default verb" + def test_csr_with_no_domains(self): + self.assertRaises( + errors.Error, self._call, + 'certonly --csr {0}'.format( + test_util.vector_path('csr-nonames.pem')).split()) + def _get_argument_parser(self): plugins = disco.PluginsRegistry.find_all() return functools.partial(cli.prepare_and_parse_args, plugins) diff --git a/certbot/tests/testdata/csr-nonames.pem b/certbot/tests/testdata/csr-nonames.pem new file mode 100644 index 000000000..abe1029ca --- /dev/null +++ b/certbot/tests/testdata/csr-nonames.pem @@ -0,0 +1,8 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIH/MIGqAgEAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwXDANBgkqhkiG9w0BAQEF +AANLADBIAkEArHVztFHtH92ucFJD/N/HW9AsdRsUuHUBBBDlHwNlRd3fp580rv2+ +6QWE30cWgdmJS86ObRz6lUTor4R0T+3C5QIDAQABoAAwDQYJKoZIhvcNAQELBQAD +QQBt9XLSZ9DGfWcGGaBUTCiSY7lWBegpNlCeo8pK3ydWmKpjcza+j7lF5paph2LH +lKWVQ8+xwYMscGWK0NApHGco +-----END CERTIFICATE REQUEST----- From 5cb0e0f264ef94187b774561329d2ab432e2634e Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 20 May 2016 17:41:58 -0700 Subject: [PATCH 161/186] Add test for csr with inconsistent domains --- certbot/tests/cli_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index c24da4989..4ae69e69d 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -368,6 +368,11 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods 'certonly --csr {0}'.format( test_util.vector_path('csr-nonames.pem')).split()) + def test_csr_with_inconsistent_domains(self): + self.assertRaises( + errors.Error, self._call, + 'certonly -d example.org --csr {0}'.format(CSR).split()) + def _get_argument_parser(self): plugins = disco.PluginsRegistry.find_all() return functools.partial(cli.prepare_and_parse_args, plugins) From fd899d21252b8bebd2729fbbebec216496c57902 Mon Sep 17 00:00:00 2001 From: Nick Le Mouton Date: Mon, 23 May 2016 09:44:06 +1200 Subject: [PATCH 162/186] Fixing package names for Debian Jessie --- docs/using.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index b10532259..f9af07613 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -460,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** From d4de026372780f079af3e6b811da991bad824ffe Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 13:37:47 -0700 Subject: [PATCH 163/186] Add get_strict_version --- certbot/le_util.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/certbot/le_util.py b/certbot/le_util.py index f5148b949..1e5997d92 100644 --- a/certbot/le_util.py +++ b/certbot/le_util.py @@ -1,6 +1,9 @@ """Utilities for all Certbot.""" import argparse import collections +# distutils.version under virtualenv confuses pylint +# For more info, see: https://github.com/PyCQA/pylint/issues/73 +import distutils.version # pylint: disable=import-error,no-name-in-module import errno import logging import os @@ -342,3 +345,17 @@ def enforce_domain_sanity(domain): if not fqdn.match(domain): raise errors.ConfigurationError("Requested domain {0} is not a FQDN".format(domain)) return domain + + +def get_strict_version(normalized): + """Converts a normalized version to a strict version. + + :param str normalized: normalized version string + + :returns: An equivalent strict version + :rtype: distutils.version.StrictVersion + + """ + # strict version ending with "a" and a number designates a pre-release + # pylint: disable=no-member + return distutils.version.StrictVersion(normalized.replace(".dev", "a")) From 40a0354b360214485fbd19d90e24c9c9d040856c Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 13:50:14 -0700 Subject: [PATCH 164/186] Start get_strict_version tests --- certbot/tests/le_util_test.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/certbot/tests/le_util_test.py b/certbot/tests/le_util_test.py index b6da4525f..db76615ee 100644 --- a/certbot/tests/le_util_test.py +++ b/certbot/tests/le_util_test.py @@ -339,5 +339,18 @@ class EnforceDomainSanityTest(unittest.TestCase): u"eichh\u00f6rnchen.example.com") +class GetStrictVersionTest(unittest.TestCase): + """Tests for certbot.le_util.get_strict_version.""" + + @classmethod + def _call(cls, *args, **kwargs): + from certbot.le_util import get_strict_version + return get_strict_version(*args, **kwargs) + + def test_two_dev_versions(self): + self.assertTrue( + self._call("0.0.0.dev20151006") < self._call("0.0.0.dev20151008")) + + if __name__ == "__main__": unittest.main() # pragma: no cover From 4caba1fc75749eb6c4f45dd61e314f62e26b962b Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 13:53:09 -0700 Subject: [PATCH 165/186] Test mixed versions --- certbot/tests/le_util_test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/certbot/tests/le_util_test.py b/certbot/tests/le_util_test.py index db76615ee..2dcecae2c 100644 --- a/certbot/tests/le_util_test.py +++ b/certbot/tests/le_util_test.py @@ -351,6 +351,10 @@ class GetStrictVersionTest(unittest.TestCase): self.assertTrue( self._call("0.0.0.dev20151006") < self._call("0.0.0.dev20151008")) + def test_one_dev_one_release_version(self): + self.assertTrue(self._call("1.0.0.dev0") < self._call("1.0.0")) + self.assertTrue(self._call("1.0.0") < self._call("1.0.1.dev0")) + if __name__ == "__main__": unittest.main() # pragma: no cover From ac37b9de6fdd5f935df4a5f83e0840f88df24d29 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 13:55:17 -0700 Subject: [PATCH 166/186] test release version comparison --- certbot/tests/le_util_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certbot/tests/le_util_test.py b/certbot/tests/le_util_test.py index 2dcecae2c..5bf93a406 100644 --- a/certbot/tests/le_util_test.py +++ b/certbot/tests/le_util_test.py @@ -355,6 +355,11 @@ class GetStrictVersionTest(unittest.TestCase): self.assertTrue(self._call("1.0.0.dev0") < self._call("1.0.0")) self.assertTrue(self._call("1.0.0") < self._call("1.0.1.dev0")) + def test_two_release_versions(self): + self.assertTrue(self._call("0.0.0") < self._call("0.0.1")) + self.assertTrue(self._call("0.0.0") < self._call("0.1.0")) + self.assertTrue(self._call("0.0.0") < self._call("1.0.0")) + if __name__ == "__main__": unittest.main() # pragma: no cover From 536234c5595347a472060beccdd9fd2e83791483 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 13:59:16 -0700 Subject: [PATCH 167/186] try and catch problems if we do something silly with our version in the future --- certbot/tests/le_util_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/certbot/tests/le_util_test.py b/certbot/tests/le_util_test.py index 5bf93a406..6e4eef0f1 100644 --- a/certbot/tests/le_util_test.py +++ b/certbot/tests/le_util_test.py @@ -10,6 +10,7 @@ import unittest import mock import six +import certbot from certbot import errors @@ -360,6 +361,11 @@ class GetStrictVersionTest(unittest.TestCase): self.assertTrue(self._call("0.0.0") < self._call("0.1.0")) self.assertTrue(self._call("0.0.0") < self._call("1.0.0")) + def test_current_version(self): + current_version = self._call(certbot.__version__) + self.assertTrue(self._call("0.6.0") < current_version) + self.assertTrue(current_version < self._call("99.99.99")) + if __name__ == "__main__": unittest.main() # pragma: no cover From 0e9aec20a76d06895173ef815962447d75bb87d8 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 14:04:13 -0700 Subject: [PATCH 168/186] Add CURRENT_VERSION constant --- certbot/storage.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certbot/storage.py b/certbot/storage.py index c4bfb3e28..e2b26d322 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -8,6 +8,7 @@ import configobj import parsedatetime import pytz +import certbot from certbot import constants from certbot import crypto_util from certbot import errors @@ -17,6 +18,7 @@ from certbot import le_util logger = logging.getLogger(__name__) ALL_FOUR = ("cert", "privkey", "chain", "fullchain") +CURRENT_VERSION = le_util.get_strict_version(certbot.__version__) def config_with_defaults(config=None): From c3c9441a599226efe261d140d547977eb6ac8d71 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 14:09:31 -0700 Subject: [PATCH 169/186] Save version in renewal config file --- certbot/storage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/certbot/storage.py b/certbot/storage.py index e2b26d322..d4a469ca1 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -65,6 +65,7 @@ def write_renewal_config(o_filename, n_filename, target, relevant_data): """ config = configobj.ConfigObj(o_filename) + config["version"] = certbot.__version__ for kind in ALL_FOUR: config[kind] = target[kind] From 3576d372a67882a584c207b7bf720c10fc8d69c6 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 14:32:43 -0700 Subject: [PATCH 170/186] Add warning about parsing old configuration file --- certbot/storage.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/certbot/storage.py b/certbot/storage.py index d4a469ca1..6c13eb844 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -262,6 +262,14 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes "renewal config file {0} is missing a required " "file reference".format(self.configfile)) + conf_version = self.configuration.get("version") + if (conf_version is not None and + le_util.get_strict_version(conf_version) > CURRENT_VERSION): + logger.warning( + "Attempting to parse the version %s renewal configuration " + "file found at %s with version %s of Certbot. This might not " + "work.", conf_version, config_filename, certbot.__version__) + self.cert = self.configuration["cert"] self.privkey = self.configuration["privkey"] self.chain = self.configuration["chain"] From ea53a14b57910bf9749d9304a3e93e02bea36d02 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 14:58:14 -0700 Subject: [PATCH 171/186] test version is stored --- certbot/tests/storage_test.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index be626edc5..aeba5c3ae 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -10,6 +10,7 @@ import configobj import mock import pytz +import certbot from certbot import configuration from certbot import errors from certbot.storage import ALL_FOUR @@ -760,11 +761,14 @@ class RenewableCertTests(BaseRenewableCertTest): with open(temp2, "r") as f: content = f.read() # useful value was updated - assert "useful = new_value" in content + self.assertTrue("useful = new_value" in content) # associated comment was preserved - assert "A useful value" in content + self.assertTrue("A useful value" in content) # useless value was deleted - assert "useless" not in content + self.assertTrue("useless" not in content) + # check version was stored + self.assertTrue("version = {0}".format(certbot.__version__) in content) + if __name__ == "__main__": unittest.main() # pragma: no cover From 15ddf2ea32a4f020b655c7ac4ca6d62cb0cafd50 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 15:16:43 -0700 Subject: [PATCH 172/186] Test init with newer conf file --- certbot/tests/storage_test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index aeba5c3ae..b1444f311 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -138,6 +138,18 @@ class RenewableCertTests(BaseRenewableCertTest): self.assertRaises(errors.CertStorageError, storage.RenewableCert, config.filename, self.cli_config) + def test_renewal_newer_version(self): + from certbot import storage + + self._write_out_ex_kinds() + self.config["version"] = "99.99.99" + self.config.write() + + with mock.patch("certbot.storage.logger") as mock_logger: + storage.RenewableCert(self.config.filename, self.cli_config) + self.assertTrue(mock_logger.warning.called) + self.assertTrue("version" in mock_logger.warning.call_args[0][0]) + def test_consistent(self): # pylint: disable=too-many-statements,protected-access oldcert = self.test_rc.cert From 4919814dd17bdb8a7b0100ac89a5196cb4766310 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 23 May 2016 15:39:00 -0700 Subject: [PATCH 173/186] Pin old pkginfo version --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 4ee56576b..59da23de4 100644 --- a/setup.py +++ b/setup.py @@ -71,6 +71,7 @@ dev_extras = [ 'nose', 'nosexcover', 'pep8', + 'pkginfo<=1.2.1', 'pylint==1.4.2', # upstream #248 'tox', 'twine', From 2cfcfd6988dc84cf118004f860d926eb024cf1d6 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Mon, 23 May 2016 13:18:02 -0700 Subject: [PATCH 174/186] Run Boulder via docker-compose in tests. This removes a lot of setup code we used to need in order to get Boulder to run, and should reduce brittleness of tests based on Boulder changes. This also unblocks Boulder from upgrading to MariaDB 10.1 in integration tests, since changing to 10.1 syntax for user creation would break the current certbot integration tests (which run 10.0). --- .travis.yml | 25 ++++---------- tests/boulder-fetch.sh | 40 +++-------------------- tests/letstest/scripts/boulder_install.sh | 29 +++------------- tests/travis-integration.sh | 15 +++------ 4 files changed, 22 insertions(+), 87 deletions(-) diff --git a/.travis.yml b/.travis.yml index 16b5700e5..172f4c659 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,26 +4,18 @@ cache: directories: - $HOME/.cache/pip -services: - - rabbitmq - - mariadb - # apacheconftest - #- apache2 +# This makes sure we get a host with docker-compose present. +dist: trusty -# http://docs.travis-ci.com/user/ci-environment/#CI-environment-OS -# gimme has to be kept in sync with Boulder's Go version setting in .travis.yml before_install: - 'dpkg -s libaugeas0' - - '[ "xxx$BOULDER_INTEGRATION" = "xxx" ] || eval "$(gimme 1.5.1)"' # using separate envs with different TOXENVs creates 4x1 Travis build # matrix, which allows us to clearly distinguish which component under # test has failed env: global: - - GOPATH=/tmp/go - - PATH=$GOPATH/bin:$PATH - - GO15VENDOREXPERIMENT=1 # Fixes problems with vendor directories + - BOULDERPATH=$GOPATH/src/github.com/letsencrypt/boulder/ matrix: include: @@ -93,7 +85,6 @@ addons: - boulder - boulder-mysql - boulder-rabbitmq - mariadb: "10.0" apt: sources: - augeas @@ -109,13 +100,11 @@ addons: # For certbot-nginx integration testing - nginx-light - openssl - # For Boulder integration testing - - rsyslog # for apacheconftest - #- apache2 - #- libapache2-mod-wsgi - #- libapache2-mod-macro - #- sudo + - apache2 + - libapache2-mod-wsgi + - libapache2-mod-macro + - sudo install: "travis_retry pip install tox coveralls" script: 'travis_retry tox && ([ "xxx$BOULDER_INTEGRATION" = "xxx" ] || ./tests/travis-integration.sh)' diff --git a/tests/boulder-fetch.sh b/tests/boulder-fetch.sh index 0d8a3de38..11e36835a 100755 --- a/tests/boulder-fetch.sh +++ b/tests/boulder-fetch.sh @@ -1,40 +1,10 @@ #!/bin/bash # Download and run Boulder instance for integration testing - -# ugh, go version output is like: -# go version go1.4.2 linux/amd64 -GOVER=`go version | cut -d" " -f3 | cut -do -f2` - -# version comparison -function verlte { - #OS X doesn't support version sorting; emulate with sed - if [ `uname` == 'Darwin' ]; then - [ "$1" = "`echo -e \"$1\n$2\" | sed 's/\b\([0-9]\)\b/0\1/g' \ - | sort | sed 's/\b0\([0-9]\)/\1/g' | head -n1`" ] - else - [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ] - fi -} - -if ! verlte 1.5 "$GOVER" ; then - echo "We require go version 1.5 or later; you have... $GOVER" - exit 1 -fi - set -xe -# `/...` avoids `no buildable Go source files` errors, for more info -# see `go help packages` -go get -d github.com/letsencrypt/boulder/... -cd $GOPATH/src/github.com/letsencrypt/boulder -# goose is needed for ./test/create_db.sh -wget https://github.com/jsha/boulder-tools/raw/master/goose.gz && \ - mkdir $GOPATH/bin && \ - zcat goose.gz > $GOPATH/bin/goose && \ - chmod +x $GOPATH/bin/goose -./test/create_db.sh -go run cmd/rabbitmq-setup/main.go -server amqp://localhost -# listenbuddy is needed for ./start.py -go get github.com/jsha/listenbuddy -cd - +# Check out special branch until latest docker changes land in Boulder master. +git clone -b rev-rev https://github.com/letsencrypt/boulder $BOULDERPATH +cd $BOULDERPATH +sed -i 's/FAKE_DNS: .*/FAKE_DNS: 172.17.42.1/' docker-compose.yml +docker-compose up -d diff --git a/tests/letstest/scripts/boulder_install.sh b/tests/letstest/scripts/boulder_install.sh index b5ddf2c5b..936a64802 100755 --- a/tests/letstest/scripts/boulder_install.sh +++ b/tests/letstest/scripts/boulder_install.sh @@ -2,27 +2,8 @@ # >>>> only tested on Ubuntu 14.04LTS <<<< -# non-interactive install of mariadb and other dependencies -export DEBIAN_FRONTEND=noninteractive -sudo debconf-set-selections <<< 'mariadb-server mysql-server/root_password password PASS' -sudo debconf-set-selections <<< 'mariadb-server mysql-server/root_password_again password PASS' -apt-get -y --no-upgrade install git make libltdl3-dev mariadb-server rabbitmq-server -sudo mysql -uroot -pPASS -e "SET PASSWORD = PASSWORD(\'\');" - -# install go -wget https://storage.googleapis.com/golang/go1.5.1.linux-amd64.tar.gz -tar xzvf go1.5.1.linux-amd64.tar.gz -mkdir gocode -echo "export GOROOT=/home/ubuntu/go \n\ - export GOPATH=/home/ubuntu/gocode\n\ - export PATH=/home/ubuntu/go/bin:/home/ubuntu/gocode/bin:$PATH" >> .bashrc - -# install boulder and its go dependencies -go get -d github.com/letsencrypt/boulder/... -cd $GOPATH/src/github.com/letsencrypt/boulder -wget https://github.com/jsha/boulder-tools/raw/master/goose.gz -mkdir $GOPATH/bin -zcat goose.gz > $GOPATH/bin/goose -chmod +x $GOPATH/bin/goose -./test/create_db.sh -go get github.com/jsha/listenbuddy +# Check out special branch until latest docker changes land in Boulder master. +git clone -b rev-rev https://github.com/letsencrypt/boulder $BOULDERPATH +cd $BOULDERPATH +sed -i 's/FAKE_DNS: .*/FAKE_DNS: 172.17.42.1/' docker-compose.yml +docker-compose up -d diff --git a/tests/travis-integration.sh b/tests/travis-integration.sh index 159a2ef80..b42617400 100755 --- a/tests/travis-integration.sh +++ b/tests/travis-integration.sh @@ -6,14 +6,9 @@ set -o errexit source .tox/$TOXENV/bin/activate -export CERTBOT_PATH=`pwd` +until curl http://boulder:4000/directory 2>/dev/null; do + echo waiting for boulder + sleep 1 +done -cd $GOPATH/src/github.com/letsencrypt/boulder/ - -# boulder's integration-test.py has code that knows to start and wait for the -# boulder processes to start reliably and then will run the certbot -# boulder-interation.sh on its own. The --certbot flag says to run only the -# certbot tests (instead of any other client tests it might run). We're -# going to want to define a more robust interaction point between the boulder -# and certbot tests, but that will be better built off of this. -python test/integration-test.py --certbot +./tests/boulder-integration.sh From ed802a664813ff12d4da4874b1591a90c8391df4 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Mon, 23 May 2016 18:47:52 -0700 Subject: [PATCH 175/186] Fix BOULDERPATH --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 172f4c659..6f964dbec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ before_install: # test has failed env: global: - - BOULDERPATH=$GOPATH/src/github.com/letsencrypt/boulder/ + - BOULDERPATH=$PWD/boulder/ matrix: include: From b54497d8145e0999ac3f163ae38e3bc70a7a5549 Mon Sep 17 00:00:00 2001 From: sagi Date: Tue, 24 May 2016 19:33:13 +0000 Subject: [PATCH 176/186] Fix chain filename --- tests/boulder-integration.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/boulder-integration.sh b/tests/boulder-integration.sh index a1245e1c9..323ea004b 100755 --- a/tests/boulder-integration.sh +++ b/tests/boulder-integration.sh @@ -44,7 +44,7 @@ common auth --csr "$CSR_PATH" \ --cert-path "${root}/csr/cert.pem" \ --chain-path "${root}/csr/chain.pem" openssl x509 -in "${root}/csr/cert.pem" -text -openssl x509 -in "${root}/csr/0000_chain.pem" -text +openssl x509 -in "${root}/csr/chain.pem" -text common --domains le3.wtf install \ --cert-path "${root}/csr/cert.pem" \ From b1eff0fe3528f0cef2a077b6dcee777d1dbebb8c Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 24 May 2016 13:03:53 -0700 Subject: [PATCH 177/186] Build le-auto to bring it up to date --- letsencrypt-auto-source/letsencrypt-auto | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index eb5561070..ea085454c 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -425,7 +425,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..." From 70bb7ff68f2a9eb5fac7b6cc494a50dce99ade20 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 24 May 2016 13:08:10 -0700 Subject: [PATCH 178/186] fixes #3060 --- letsencrypt-auto-source/letsencrypt-auto | 3 +-- letsencrypt-auto-source/letsencrypt-auto.template | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index ea085454c..2de4b053e 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -935,6 +935,7 @@ else if [ "$NO_SELF_UPGRADE" != 1 ]; then TEMP_DIR=$(TempDir) + trap 'rm -rf "$TEMP_DIR"' EXIT # --------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py" """Do downloading and JSON parsing without additional dependencies. :: @@ -1089,8 +1090,6 @@ UNLIKELY_EOF # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the # cp is unlikely to fail (esp. under sudo) if the rm doesn't. $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" - # TODO: Clean up temp dir safely, even if it has quotes in its path. - rm -rf "$TEMP_DIR" fi # A newer version is available. fi # Self-upgrading is allowed. diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index f1ed82c4c..116894a93 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -291,6 +291,7 @@ else if [ "$NO_SELF_UPGRADE" != 1 ]; then TEMP_DIR=$(TempDir) + trap 'rm -rf "$TEMP_DIR"' EXIT # --------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py" {{ fetch.py }} @@ -319,8 +320,6 @@ UNLIKELY_EOF # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the # cp is unlikely to fail (esp. under sudo) if the rm doesn't. $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0" - # TODO: Clean up temp dir safely, even if it has quotes in its path. - rm -rf "$TEMP_DIR" fi # A newer version is available. fi # Self-upgrading is allowed. From c606273d1489a27c50376fca6244968a4ccde06a Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 24 May 2016 13:16:21 -0700 Subject: [PATCH 179/186] use TEMP_DIR trap consistently --- letsencrypt-auto-source/letsencrypt-auto | 2 +- letsencrypt-auto-source/letsencrypt-auto.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 2de4b053e..b65c29a44 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -532,6 +532,7 @@ if [ "$1" = "--le-auto-phase2" ]; then echo "Installing Python packages..." TEMP_DIR=$(TempDir) + trap 'rm -rf "$TEMP_DIR"' EXIT # There is no $ interpolation due to quotes on starting heredoc delimiter. # ------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt" @@ -889,7 +890,6 @@ UNLIKELY_EOF PIP_OUT=`"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1` PIP_STATUS=$? set -e - rm -rf "$TEMP_DIR" if [ "$PIP_STATUS" != 0 ]; then # Report error. (Otherwise, be quiet.) echo "Had a problem while installing Python packages:" diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 116894a93..43d8bc7e1 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -229,6 +229,7 @@ if [ "$1" = "--le-auto-phase2" ]; then echo "Installing Python packages..." TEMP_DIR=$(TempDir) + trap 'rm -rf "$TEMP_DIR"' EXIT # There is no $ interpolation due to quotes on starting heredoc delimiter. # ------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt" @@ -245,7 +246,6 @@ UNLIKELY_EOF PIP_OUT=`"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1` PIP_STATUS=$? set -e - rm -rf "$TEMP_DIR" if [ "$PIP_STATUS" != 0 ]; then # Report error. (Otherwise, be quiet.) echo "Had a problem while installing Python packages:" From 420e64f03951bbce7737d0b0ce05fad9070763db Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 24 May 2016 13:43:45 -0700 Subject: [PATCH 180/186] Simplify webroot chown and rm errors --- certbot/plugins/webroot.py | 22 +++++---------------- certbot/plugins/webroot_test.py | 35 ++------------------------------- 2 files changed, 7 insertions(+), 50 deletions(-) diff --git a/certbot/plugins/webroot.py b/certbot/plugins/webroot.py index c344954ae..508000d77 100644 --- a/certbot/plugins/webroot.py +++ b/certbot/plugins/webroot.py @@ -181,12 +181,8 @@ to serve all files under specified web root ({0}).""" os.chown(self.full_roots[name], stat_path.st_uid, stat_path.st_gid) except OSError as exception: - if exception.errno == errno.EACCES: - logger.debug("Insufficient permissions to change owner and uid - ignoring") - else: - raise errors.PluginError( - "Couldn't create root for {0} http-01 " - "challenge responses: {1}", name, exception) + logger.debug("Unable to change owner and uid of webroot directory") + logger.debug("Error was: %s", exception) except OSError as exception: if exception.errno != errno.EEXIST: @@ -235,17 +231,9 @@ to serve all files under specified web root ({0}).""" logger.debug("All challenges cleaned up, removing %s", root_path) except OSError as exc: - if exc.errno == errno.ENOTEMPTY: - logger.debug("Challenges cleaned up but %s not empty", - root_path) - elif exc.errno == errno.EACCES: - logger.debug("Challenges cleaned up but no permissions for %s", - root_path) - elif exc.errno == errno.ENOENT: - logger.debug("Challenges cleaned up, %s does not exists", - root_path) - else: - raise + logger.debug( + "Unable to clean up challenge directory %s", root_path) + logger.debug("Error was: %s", exc) class _WebrootMapAction(argparse.Action): diff --git a/certbot/plugins/webroot_test.py b/certbot/plugins/webroot_test.py index ab2a9e9a4..5d784a75c 100644 --- a/certbot/plugins/webroot_test.py +++ b/certbot/plugins/webroot_test.py @@ -138,15 +138,10 @@ class AuthenticatorTest(unittest.TestCase): os.chmod(self.path, 0o700) @mock.patch("certbot.plugins.webroot.os.chown") - def test_failed_chown_eacces(self, mock_chown): + def test_failed_chown(self, mock_chown): mock_chown.side_effect = OSError(errno.EACCES, "msg") self.auth.perform([self.achall]) # exception caught and logged - @mock.patch("certbot.plugins.webroot.os.chown") - def test_failed_chown_not_eacces(self, mock_chown): - mock_chown.side_effect = OSError() - self.assertRaises(errors.PluginError, self.auth.perform, []) - def test_perform_permissions(self): self.auth.prepare() @@ -200,7 +195,7 @@ class AuthenticatorTest(unittest.TestCase): os.rmdir(leftover_path) @mock.patch('os.rmdir') - def test_cleanup_permission_denied(self, mock_rmdir): + def test_cleanup_failure(self, mock_rmdir): self.auth.prepare() self.auth.perform([self.achall]) @@ -212,32 +207,6 @@ class AuthenticatorTest(unittest.TestCase): self.assertFalse(os.path.exists(self.validation_path)) self.assertTrue(os.path.exists(self.root_challenge_path)) - @mock.patch('os.rmdir') - def test_cleanup_oserror(self, mock_rmdir): - self.auth.prepare() - self.auth.perform([self.achall]) - - os_error = OSError() - os_error.errno = errno.EPERM - mock_rmdir.side_effect = os_error - - self.assertRaises(OSError, self.auth.cleanup, [self.achall]) - self.assertFalse(os.path.exists(self.validation_path)) - self.assertTrue(os.path.exists(self.root_challenge_path)) - - @mock.patch('os.rmdir') - def test_cleanup_file_not_exists(self, mock_rmdir): - self.auth.prepare() - self.auth.perform([self.achall]) - - os_error = OSError() - os_error.errno = errno.ENOENT - mock_rmdir.side_effect = os_error - - self.auth.cleanup([self.achall]) - self.assertFalse(os.path.exists(self.validation_path)) - self.assertTrue(os.path.exists(self.root_challenge_path)) - class WebrootActionTest(unittest.TestCase): """Tests for webroot argparse actions.""" From c01e2c259af0e200222e66bdf27434f3dba47613 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Tue, 24 May 2016 15:38:03 -0700 Subject: [PATCH 181/186] Check out Boulder master instead of branch. --- tests/boulder-fetch.sh | 2 +- tests/letstest/scripts/boulder_install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/boulder-fetch.sh b/tests/boulder-fetch.sh index 11e36835a..a09d0adf9 100755 --- a/tests/boulder-fetch.sh +++ b/tests/boulder-fetch.sh @@ -3,7 +3,7 @@ set -xe # Check out special branch until latest docker changes land in Boulder master. -git clone -b rev-rev https://github.com/letsencrypt/boulder $BOULDERPATH +git clone https://github.com/letsencrypt/boulder $BOULDERPATH cd $BOULDERPATH sed -i 's/FAKE_DNS: .*/FAKE_DNS: 172.17.42.1/' docker-compose.yml docker-compose up -d diff --git a/tests/letstest/scripts/boulder_install.sh b/tests/letstest/scripts/boulder_install.sh index 936a64802..426642880 100755 --- a/tests/letstest/scripts/boulder_install.sh +++ b/tests/letstest/scripts/boulder_install.sh @@ -3,7 +3,7 @@ # >>>> only tested on Ubuntu 14.04LTS <<<< # Check out special branch until latest docker changes land in Boulder master. -git clone -b rev-rev https://github.com/letsencrypt/boulder $BOULDERPATH +git clone https://github.com/letsencrypt/boulder $BOULDERPATH cd $BOULDERPATH sed -i 's/FAKE_DNS: .*/FAKE_DNS: 172.17.42.1/' docker-compose.yml docker-compose up -d From 57e6d1995bebf2a700f83e1dfaff2c626d6d8d18 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 24 May 2016 16:32:03 -0700 Subject: [PATCH 182/186] log louder --- certbot/plugins/webroot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot/plugins/webroot.py b/certbot/plugins/webroot.py index 508000d77..624ee2ff4 100644 --- a/certbot/plugins/webroot.py +++ b/certbot/plugins/webroot.py @@ -181,7 +181,7 @@ to serve all files under specified web root ({0}).""" os.chown(self.full_roots[name], stat_path.st_uid, stat_path.st_gid) except OSError as exception: - logger.debug("Unable to change owner and uid of webroot directory") + logger.info("Unable to change owner and uid of webroot directory") logger.debug("Error was: %s", exception) except OSError as exception: @@ -231,7 +231,7 @@ to serve all files under specified web root ({0}).""" logger.debug("All challenges cleaned up, removing %s", root_path) except OSError as exc: - logger.debug( + logger.info( "Unable to clean up challenge directory %s", root_path) logger.debug("Error was: %s", exc) From e93aeb88dd4da8e26fd6a4c257234ba990aae403 Mon Sep 17 00:00:00 2001 From: sagi Date: Wed, 25 May 2016 04:19:18 +0000 Subject: [PATCH 183/186] Fix docs --- certbot/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/certbot/client.py b/certbot/client.py index 514da879e..9ce326822 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -580,7 +580,8 @@ def _open_pem_file(cli_arg_path, pem_path): :param str cli_arg_path: the cli arg name, e.g. cert_path :param str pem_path: the pem file path to open - :returns a file object + :returns: a tuple of file object and its absolute file path + """ if cli.set_by_cli(cli_arg_path): return le_util.safe_open(pem_path, chmod=0o644),\ From 13e165e2f9ef3af630d6dbe74082aa689f35be31 Mon Sep 17 00:00:00 2001 From: Noah Swartz Date: Tue, 24 May 2016 21:30:45 -0700 Subject: [PATCH 184/186] add exception type --- certbot/tests/reverter_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/tests/reverter_test.py b/certbot/tests/reverter_test.py index c79c72a48..85234b76a 100644 --- a/certbot/tests/reverter_test.py +++ b/certbot/tests/reverter_test.py @@ -39,7 +39,7 @@ class ReverterCheckpointLocalTest(unittest.TestCase): mock_read.side_effect = OSError("cannot even") try: self.reverter.add_to_checkpoint(self.sets[0], "save1") - except: + except OSError: pass self.reverter.finalize_checkpoint("blah") path = os.listdir(self.reverter.config.backup_dir)[0] From 4a85d59d9353e7a0567c0bc56c9729d75b96d209 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 24 May 2016 22:03:30 -0700 Subject: [PATCH 185/186] Add test for missing renewal conf version --- certbot/tests/storage_test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index b1444f311..f19b7d89d 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -138,6 +138,16 @@ class RenewableCertTests(BaseRenewableCertTest): self.assertRaises(errors.CertStorageError, storage.RenewableCert, config.filename, self.cli_config) + def test_no_renewal_version(self): + from certbot import storage + + self._write_out_ex_kinds() + self.assertTrue("version" not in self.config) + + with mock.patch("certbot.storage.logger") as mock_logger: + storage.RenewableCert(self.config.filename, self.cli_config) + self.assertFalse(mock_logger.warning.called) + def test_renewal_newer_version(self): from certbot import storage From d1df72d63c7eb9e590d05651f0f1a41caf234a1d Mon Sep 17 00:00:00 2001 From: sagi Date: Wed, 25 May 2016 19:06:25 +0000 Subject: [PATCH 186/186] Add the chain_cert is None case --- certbot/client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/certbot/client.py b/certbot/client.py index 9ce326822..ba31f8760 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -328,7 +328,9 @@ class Client(object): logger.info("Server issued certificate; certificate written to %s", abs_cert_path) - if chain_cert: + if not chain_cert: + return abs_cert_path, None, None + else: chain_pem = crypto_util.dump_pyopenssl_chain(chain_cert) chain_file, abs_chain_path =\ @@ -339,7 +341,7 @@ class Client(object): _save_chain(chain_pem, chain_file) _save_chain(cert_pem + chain_pem, fullchain_file) - return abs_cert_path, abs_chain_path, abs_fullchain_path + return abs_cert_path, abs_chain_path, abs_fullchain_path def deploy_certificate(self, domains, privkey_path, cert_path, chain_path, fullchain_path):