From 0e3eae153e9f8fcc98a295065a87fcf851ba175b Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 17 Sep 2015 12:29:42 -0700 Subject: [PATCH 01/13] Hide tracebacks, but not the ultimate error itself --- letsencrypt/cli.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index ab03a576f..a413cdf8e 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -845,14 +845,17 @@ def _handle_exception(exc_type, exc_value, trace, args): if issubclass(exc_type, errors.Error): sys.exit(exc_value) - elif args is None: - sys.exit( - "An unexpected error occurred. Please see the logfile '{0}' " - "for more details.".format(logfile)) else: - sys.exit( - "An unexpected error occurred. Please see the logfiles in {0} " - "for more details.".format(args.logs_dir)) + # Tell the user a bit about what happened, without overwhelming + # them with a full traceback + msg = "An unexpected error occurred.\n" + msg += traceback.format_exception_only(exc_type,exc_value)[0] + msg += "\nPlease see the " + if args is None: + msg += "logfile '{0}' for more details.".format(logfile) + else: + msg += "logfiles in {0} for more details.".format(args.logs_dir) + sys.exit(msg) else: sys.exit("".join( traceback.format_exception(exc_type, exc_value, trace))) From 7c67df107636a6058a975b4a1392987bfdc5fa90 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 17 Sep 2015 12:48:07 -0700 Subject: [PATCH 02/13] traceback actually provides that \n --- letsencrypt/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index a413cdf8e..739385206 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -850,7 +850,7 @@ def _handle_exception(exc_type, exc_value, trace, args): # them with a full traceback msg = "An unexpected error occurred.\n" msg += traceback.format_exception_only(exc_type,exc_value)[0] - msg += "\nPlease see the " + msg += "Please see the " if args is None: msg += "logfile '{0}' for more details.".format(logfile) else: From 6c4d9e932407f0932d04f757694b54ad9da50ab2 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Thu, 17 Sep 2015 13:00:03 -0700 Subject: [PATCH 03/13] Satisfy the lintmonster --- letsencrypt/cli.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 739385206..dcd1e55b1 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -848,13 +848,13 @@ def _handle_exception(exc_type, exc_value, trace, args): else: # Tell the user a bit about what happened, without overwhelming # them with a full traceback - msg = "An unexpected error occurred.\n" - msg += traceback.format_exception_only(exc_type,exc_value)[0] - msg += "Please see the " + msg = ("An unexpected error occurred.\n" + + traceback.format_exception_only(exc_type, exc_value)[0] + + "Please see the ") if args is None: - msg += "logfile '{0}' for more details.".format(logfile) + msg += "logfile '{0}' for more details.".format(logfile) else: - msg += "logfiles in {0} for more details.".format(args.logs_dir) + msg += "logfiles in {0} for more details.".format(args.logs_dir) sys.exit(msg) else: sys.exit("".join( From 31af7b3a02c00be3bc0b15f0a629e3322756ebfd Mon Sep 17 00:00:00 2001 From: kevinlondon Date: Sun, 20 Sep 2015 14:53:45 -0700 Subject: [PATCH 04/13] Replace mktemp with mkstemp --- letsencrypt/revoker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/revoker.py b/letsencrypt/revoker.py index 239879542..036309b21 100644 --- a/letsencrypt/revoker.py +++ b/letsencrypt/revoker.py @@ -288,7 +288,7 @@ class Revoker(object): :class:`letsencrypt.revoker.Cert` """ - list_path2 = tempfile.mktemp(".tmp", "LIST") + _, list_path2 = tempfile.mkstemp(".tmp", "LIST") idx = 0 with open(self.list_path, "rb") as orgfile: From 4ffb74d7df3b612ad49625e8b65423afd2ed95c8 Mon Sep 17 00:00:00 2001 From: Brandon Kreisel Date: Sun, 20 Sep 2015 19:07:55 -0400 Subject: [PATCH 05/13] Add dialog dependency and homebrew installation --- bootstrap/mac.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bootstrap/mac.sh b/bootstrap/mac.sh index a48afe11e..47450cd9e 100755 --- a/bootstrap/mac.sh +++ b/bootstrap/mac.sh @@ -1,2 +1,10 @@ #!/bin/sh +if hash brew 2>/dev/null; then + echo "Homebrew Installed" +else + echo "Homebrew Not Installed\nDownloading..." + ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +fi + brew install augeas +brew install dialog From 7f42beda95c189ffaf457bbba0d3585f27b25a6b Mon Sep 17 00:00:00 2001 From: Brandon Kreisel Date: Sun, 20 Sep 2015 19:07:55 -0400 Subject: [PATCH 06/13] Add homebrew and add dialog dependency per #413 --- bootstrap/mac.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bootstrap/mac.sh b/bootstrap/mac.sh index a48afe11e..47450cd9e 100755 --- a/bootstrap/mac.sh +++ b/bootstrap/mac.sh @@ -1,2 +1,10 @@ #!/bin/sh +if hash brew 2>/dev/null; then + echo "Homebrew Installed" +else + echo "Homebrew Not Installed\nDownloading..." + ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +fi + brew install augeas +brew install dialog From fd53b09ab53073361d1287671243d0cae4315020 Mon Sep 17 00:00:00 2001 From: Brandon Kreisel Date: Mon, 21 Sep 2015 06:58:35 -0400 Subject: [PATCH 07/13] Remove homebrew existing message --- bootstrap/mac.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bootstrap/mac.sh b/bootstrap/mac.sh index 47450cd9e..6779188a7 100755 --- a/bootstrap/mac.sh +++ b/bootstrap/mac.sh @@ -1,7 +1,5 @@ #!/bin/sh -if hash brew 2>/dev/null; then - echo "Homebrew Installed" -else +if ! hash brew 2>/dev/null; then echo "Homebrew Not Installed\nDownloading..." ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" fi From ff9f12aea606448a5705486c4630cca3a299defc Mon Sep 17 00:00:00 2001 From: kevinlondon Date: Mon, 21 Sep 2015 08:05:55 -0700 Subject: [PATCH 08/13] Use the file handle provided by mkstemp for opening the file. --- letsencrypt/revoker.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/letsencrypt/revoker.py b/letsencrypt/revoker.py index 036309b21..7fe1bd106 100644 --- a/letsencrypt/revoker.py +++ b/letsencrypt/revoker.py @@ -288,12 +288,12 @@ class Revoker(object): :class:`letsencrypt.revoker.Cert` """ - _, list_path2 = tempfile.mkstemp(".tmp", "LIST") + newfile_handle, list_path2 = tempfile.mkstemp(".tmp", "LIST") idx = 0 with open(self.list_path, "rb") as orgfile: csvreader = csv.reader(orgfile) - with open(list_path2, "wb") as newfile: + with os.fdopen(newfile_handle, "wb") as newfile: csvwriter = csv.writer(newfile) for row in csvreader: @@ -308,7 +308,7 @@ class Revoker(object): "Did not find all cert_list items to remove from LIST") shutil.copy2(list_path2, self.list_path) - os.remove(list_path2) + newfile.close() def _row_to_backup(self, row): """Convenience function From d4fa0363e320d7e68350eef20d952ef0074b5b88 Mon Sep 17 00:00:00 2001 From: kevinlondon Date: Mon, 21 Sep 2015 09:25:27 -0700 Subject: [PATCH 09/13] Removed the temp file again, not closing a closed file. --- letsencrypt/revoker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/revoker.py b/letsencrypt/revoker.py index 7fe1bd106..32c6f003d 100644 --- a/letsencrypt/revoker.py +++ b/letsencrypt/revoker.py @@ -308,7 +308,7 @@ class Revoker(object): "Did not find all cert_list items to remove from LIST") shutil.copy2(list_path2, self.list_path) - newfile.close() + os.remove(list_path2) def _row_to_backup(self, row): """Convenience function From 8009993b52b9c13a8bb1fd42b84894e478f94e53 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 21 Sep 2015 14:50:00 -0700 Subject: [PATCH 10/13] Removed hardcoded signature --- letsencrypt/plugins/manual_test.py | 33 +++--------------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/letsencrypt/plugins/manual_test.py b/letsencrypt/plugins/manual_test.py index 2d7c3e1e4..ce4ec22f9 100644 --- a/letsencrypt/plugins/manual_test.py +++ b/letsencrypt/plugins/manual_test.py @@ -46,12 +46,9 @@ class ManualAuthenticatorTest(unittest.TestCase): self.assertEqual([], self.auth.perform([])) @mock.patch("letsencrypt.plugins.manual.sys.stdout") - @mock.patch("letsencrypt.plugins.manual.os.urandom") @mock.patch("acme.challenges.SimpleHTTPResponse.simple_verify") @mock.patch("__builtin__.raw_input") - def test_perform(self, mock_raw_input, mock_verify, mock_urandom, - mock_stdout): - mock_urandom.side_effect = nonrandom_urandom + def test_perform(self, mock_raw_input, mock_verify, mock_stdout): mock_verify.return_value = True resp = challenges.SimpleHTTPResponse(tls=False) @@ -61,27 +58,8 @@ class ManualAuthenticatorTest(unittest.TestCase): self.achalls[0].challb.chall, "foo.com", KEY.public_key(), 4430) message = mock_stdout.write.mock_calls[0][1][0] - self.assertEqual(message, """\ -Make sure your web server displays the following content at -http://foo.com/.well-known/acme-challenge/ZXZhR3hmQURzNnBTUmIyTEF2OUlaZjE3RHQzanV4R0orUEN0OTJ3citvQQ before continuing: - -{"header": {"alg": "RS256", "jwk": {"e": "AQAB", "kty": "RSA", "n": "rHVztFHtH92ucFJD_N_HW9AsdRsUuHUBBBDlHwNlRd3fp580rv2-6QWE30cWgdmJS86ObRz6lUTor4R0T-3C5Q"}}, "payload": "eyJ0bHMiOiBmYWxzZSwgInRva2VuIjogIlpYWmhSM2htUVVSek5uQlRVbUl5VEVGMk9VbGFaakUzUkhRemFuVjRSMG9yVUVOME9USjNjaXR2UVEiLCAidHlwZSI6ICJzaW1wbGVIdHRwIn0", "signature": "jFPJFC-2eRyBw7Sl0wyEBhsdvRZtKk8hc6HykEPAiofZlIwdIu76u2xHqMVZWSZdpxwMNUnnawTEAqgMWFydMA"} - -Content-Type header MUST be set to application/jose+json. - -If you don\'t have HTTP server configured, you can run the following -command on the target server (as root): - -mkdir -p /tmp/letsencrypt/public_html/.well-known/acme-challenge -cd /tmp/letsencrypt/public_html -echo -n \'{"header": {"alg": "RS256", "jwk": {"e": "AQAB", "kty": "RSA", "n": "rHVztFHtH92ucFJD_N_HW9AsdRsUuHUBBBDlHwNlRd3fp580rv2-6QWE30cWgdmJS86ObRz6lUTor4R0T-3C5Q"}}, "payload": "eyJ0bHMiOiBmYWxzZSwgInRva2VuIjogIlpYWmhSM2htUVVSek5uQlRVbUl5VEVGMk9VbGFaakUzUkhRemFuVjRSMG9yVUVOME9USjNjaXR2UVEiLCAidHlwZSI6ICJzaW1wbGVIdHRwIn0", "signature": "jFPJFC-2eRyBw7Sl0wyEBhsdvRZtKk8hc6HykEPAiofZlIwdIu76u2xHqMVZWSZdpxwMNUnnawTEAqgMWFydMA"}\' > .well-known/acme-challenge/ZXZhR3hmQURzNnBTUmIyTEF2OUlaZjE3RHQzanV4R0orUEN0OTJ3citvQQ -# run only once per server: -$(command -v python2 || command -v python2.7 || command -v python2.6) -c \\ -"import BaseHTTPServer, SimpleHTTPServer; \\ -SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {\'\': \'application/jose+json\'}; \\ -s = BaseHTTPServer.HTTPServer((\'\', 4430), SimpleHTTPServer.SimpleHTTPRequestHandler); \\ -s.serve_forever()" \n""") - #self.assertTrue(validation in message) + token = self.achalls[0].challb.chall.encode("token") + self.assertTrue(token in message) mock_verify.return_value = False self.assertEqual([None], self.auth.perform(self.achalls)) @@ -130,10 +108,5 @@ s.serve_forever()" \n""") mock_killpg.assert_called_once_with(1234, signal.SIGTERM) -def nonrandom_urandom(num_bytes): - """Returns a string of length num_bytes""" - return "x" * num_bytes - - if __name__ == "__main__": unittest.main() # pragma: no cover From 65dd4c668c31cc9cdb6d82c05d24798254f2de8d Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 21 Sep 2015 14:55:12 -0700 Subject: [PATCH 11/13] Increased letsencrypt and letsencrypt-nginx cover minimums --- tox.cover.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.cover.sh b/tox.cover.sh index 6f8a5697b..edfd9b81a 100755 --- a/tox.cover.sh +++ b/tox.cover.sh @@ -16,13 +16,13 @@ fi cover () { if [ "$1" = "letsencrypt" ]; then - min=96 + min=97 elif [ "$1" = "acme" ]; then min=100 elif [ "$1" = "letsencrypt_apache" ]; then min=100 elif [ "$1" = "letsencrypt_nginx" ]; then - min=96 + min=97 elif [ "$1" = "letshelp_letsencrypt" ]; then min=100 else From f482b5bd5373f0bb2d0db7afb05a5069f09d53c4 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 21 Sep 2015 15:08:11 -0700 Subject: [PATCH 12/13] Removed unnecessary .challb --- letsencrypt/plugins/manual_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/letsencrypt/plugins/manual_test.py b/letsencrypt/plugins/manual_test.py index ce4ec22f9..6b9359db1 100644 --- a/letsencrypt/plugins/manual_test.py +++ b/letsencrypt/plugins/manual_test.py @@ -58,8 +58,7 @@ class ManualAuthenticatorTest(unittest.TestCase): self.achalls[0].challb.chall, "foo.com", KEY.public_key(), 4430) message = mock_stdout.write.mock_calls[0][1][0] - token = self.achalls[0].challb.chall.encode("token") - self.assertTrue(token in message) + self.assertTrue(self.achalls[0].chall.encode("token") in message) mock_verify.return_value = False self.assertEqual([None], self.auth.perform(self.achalls)) From 5b080b6056856db15121d1db4ce84e5be2f704b4 Mon Sep 17 00:00:00 2001 From: yan Date: Mon, 21 Sep 2015 15:33:40 -0700 Subject: [PATCH 13/13] Update Dockerfile-dev and instructions. --- Dockerfile-dev | 6 +++++- docs/contributing.rst | 5 ++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Dockerfile-dev b/Dockerfile-dev index 835b3a7cc..2fe1a818d 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -32,7 +32,7 @@ RUN /opt/letsencrypt/src/ubuntu.sh && \ # the above is not likely to change, so by putting it further up the # Dockerfile we make sure we cache as much as possible -COPY setup.py README.rst CHANGES.rst MANIFEST.in requirements.txt EULA linter_plugin.py tox.cover.sh tox.ini /opt/letsencrypt/src/ +COPY setup.py README.rst CHANGES.rst MANIFEST.in requirements.txt EULA linter_plugin.py tox.cover.sh tox.ini pep8.travis.sh .pep8 .pylintrc /opt/letsencrypt/src/ # all above files are necessary for setup.py, however, package source # code directory has to be copied separately to a subdirectory... @@ -46,6 +46,8 @@ COPY letsencrypt /opt/letsencrypt/src/letsencrypt/ COPY acme /opt/letsencrypt/src/acme/ COPY letsencrypt-apache /opt/letsencrypt/src/letsencrypt-apache/ COPY letsencrypt-nginx /opt/letsencrypt/src/letsencrypt-nginx/ +COPY letshelp-letsencrypt /opt/letsencrypt/src/letshelp-letsencrypt/ +COPY letsencrypt-compatibility-test /opt/letsencrypt/src/letsencrypt-compatibility-test/ COPY tests /opt/letsencrypt/src/tests/ RUN virtualenv --no-site-packages -p python2 /opt/letsencrypt/venv && \ @@ -55,6 +57,8 @@ RUN virtualenv --no-site-packages -p python2 /opt/letsencrypt/venv && \ -e /opt/letsencrypt/src \ -e /opt/letsencrypt/src/letsencrypt-apache \ -e /opt/letsencrypt/src/letsencrypt-nginx \ + -e /opt/letsencrypt/src/letshelp-letsencrypt \ + -e /opt/letsencrypt/src/letsencrypt-compatibility-test \ -e /opt/letsencrypt/src[dev,docs,testing] # install in editable mode (-e) to save space: it's not possible to diff --git a/docs/contributing.rst b/docs/contributing.rst index f85e37c39..c6443e3b2 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -129,9 +129,8 @@ 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``) -for doing so. To use Docker on OSX, install boot2docker using the -instructions at https://docs.docker.com/installation/mac/ and start it -from the command line (``boot2docker init``). +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::