We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Race condition in recent Travis builds
#726, #752 and #754 are affected by annoying race condition that causes Travis build to fail randomly (see https://travis-ci.org/letsencrypt/letsencrypt/builds/77715204, https://travis-ci.org/letsencrypt/letsencrypt/builds/78978888, https://travis-ci.org/letsencrypt/letsencrypt/builds/78990354, resp.).

It seems that manual authenticator doesn't manage to bootstrap on time before we proceed to `simple_verify`.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `letsencrypt/plugins/manual.py`
Content:
```
1 """Manual plugin."""
2 import os
3 import logging
4 import pipes
5 import shutil
6 import signal
7 import subprocess
8 import sys
9 import tempfile
10 import time
11 
12 import zope.component
13 import zope.interface
14 
15 from acme import challenges
16 
17 from letsencrypt import errors
18 from letsencrypt import interfaces
19 from letsencrypt.plugins import common
20 
21 
22 logger = logging.getLogger(__name__)
23 
24 
25 class ManualAuthenticator(common.Plugin):
26     """Manual Authenticator.
27 
28     .. todo:: Support for `~.challenges.DVSNI`.
29 
30     """
31     zope.interface.implements(interfaces.IAuthenticator)
32     zope.interface.classProvides(interfaces.IPluginFactory)
33 
34     description = "Manual Authenticator"
35 
36     MESSAGE_TEMPLATE = """\
37 Make sure your web server displays the following content at
38 {uri} before continuing:
39 
40 {achall.token}
41 
42 Content-Type header MUST be set to {ct}.
43 
44 If you don't have HTTP server configured, you can run the following
45 command on the target server (as root):
46 
47 {command}
48 """
49 
50     # "cd /tmp/letsencrypt" makes sure user doesn't serve /root,
51     # separate "public_html" ensures that cert.pem/key.pem are not
52     # served and makes it more obvious that Python command will serve
53     # anything recursively under the cwd
54 
55     HTTP_TEMPLATE = """\
56 mkdir -p {root}/public_html/{response.URI_ROOT_PATH}
57 cd {root}/public_html
58 echo -n {validation} > {response.URI_ROOT_PATH}/{encoded_token}
59 # run only once per server:
60 $(command -v python2 || command -v python2.7 || command -v python2.6) -c \\
61 "import BaseHTTPServer, SimpleHTTPServer; \\
62 SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {{'': '{ct}'}}; \\
63 s = BaseHTTPServer.HTTPServer(('', {port}), SimpleHTTPServer.SimpleHTTPRequestHandler); \\
64 s.serve_forever()" """
65     """Non-TLS command template."""
66 
67     # https://www.piware.de/2011/01/creating-an-https-server-in-python/
68     HTTPS_TEMPLATE = """\
69 mkdir -p {root}/public_html/{response.URI_ROOT_PATH}
70 cd {root}/public_html
71 echo -n {validation} > {response.URI_ROOT_PATH}/{encoded_token}
72 # run only once per server:
73 openssl req -new -newkey rsa:4096 -subj "/" -days 1 -nodes -x509 -keyout ../key.pem -out ../cert.pem
74 $(command -v python2 || command -v python2.7 || command -v python2.6) -c \\
75 "import BaseHTTPServer, SimpleHTTPServer, ssl; \\
76 SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {{'': '{ct}'}}; \\
77 s = BaseHTTPServer.HTTPServer(('', {port}), SimpleHTTPServer.SimpleHTTPRequestHandler); \\
78 s.socket = ssl.wrap_socket(s.socket, keyfile='../key.pem', certfile='../cert.pem'); \\
79 s.serve_forever()" """
80     """TLS command template.
81 
82     According to the ACME specification, "the ACME server MUST ignore
83     the certificate provided by the HTTPS server", so the first command
84     generates temporary self-signed certificate.
85 
86     """
87 
88     def __init__(self, *args, **kwargs):
89         super(ManualAuthenticator, self).__init__(*args, **kwargs)
90         self.template = (self.HTTP_TEMPLATE if self.config.no_simple_http_tls
91                          else self.HTTPS_TEMPLATE)
92         self._root = (tempfile.mkdtemp() if self.conf("test-mode")
93                       else "/tmp/letsencrypt")
94         self._httpd = None
95 
96     @classmethod
97     def add_parser_arguments(cls, add):
98         add("test-mode", action="store_true",
99             help="Test mode. Executes the manual command in subprocess. "
100             "Requires openssl to be installed unless --no-simple-http-tls.")
101 
102     def prepare(self):  # pylint: disable=missing-docstring,no-self-use
103         pass  # pragma: no cover
104 
105     def more_info(self):  # pylint: disable=missing-docstring,no-self-use
106         return """\
107 This plugin requires user's manual intervention in setting up a HTTP
108 server for solving SimpleHTTP challenges and thus does not need to be
109 run as a privilidged process. Alternatively shows instructions on how
110 to use Python's built-in HTTP server and, in case of HTTPS, openssl
111 binary for temporary key/certificate generation.""".replace("\n", "")
112 
113     def get_chall_pref(self, domain):
114         # pylint: disable=missing-docstring,no-self-use,unused-argument
115         return [challenges.SimpleHTTP]
116 
117     def perform(self, achalls):  # pylint: disable=missing-docstring
118         responses = []
119         # TODO: group achalls by the same socket.gethostbyname(_ex)
120         # and prompt only once per server (one "echo -n" per domain)
121         for achall in achalls:
122             responses.append(self._perform_single(achall))
123         return responses
124 
125     def _perform_single(self, achall):
126         # same path for each challenge response would be easier for
127         # users, but will not work if multiple domains point at the
128         # same server: default command doesn't support virtual hosts
129         response, validation = achall.gen_response_and_validation(
130             tls=(not self.config.no_simple_http_tls))
131 
132         command = self.template.format(
133             root=self._root, achall=achall, response=response,
134             validation=pipes.quote(validation.json_dumps()),
135             encoded_token=achall.chall.encode("token"),
136             ct=response.CONTENT_TYPE, port=(
137                 response.port if self.config.simple_http_port is None
138                 else self.config.simple_http_port))
139         if self.conf("test-mode"):
140             logger.debug("Test mode. Executing the manual command: %s", command)
141             try:
142                 self._httpd = subprocess.Popen(
143                     command,
144                     # don't care about setting stdout and stderr,
145                     # we're in test mode anyway
146                     shell=True,
147                     # "preexec_fn" is UNIX specific, but so is "command"
148                     preexec_fn=os.setsid)
149             except OSError as error:  # ValueError should not happen!
150                 logger.debug(
151                     "Couldn't execute manual command: %s", error, exc_info=True)
152                 return False
153             logger.debug("Manual command running as PID %s.", self._httpd.pid)
154             # give it some time to bootstrap, before we try to verify
155             # (cert generation in case of simpleHttpS might take time)
156             time.sleep(4)  # XXX
157             if self._httpd.poll() is not None:
158                 raise errors.Error("Couldn't execute manual command")
159         else:
160             self._notify_and_wait(self.MESSAGE_TEMPLATE.format(
161                 achall=achall, response=response,
162                 uri=response.uri(achall.domain, achall.challb.chall),
163                 ct=response.CONTENT_TYPE, command=command))
164 
165         if response.simple_verify(
166                 achall.chall, achall.domain,
167                 achall.account_key.public_key(), self.config.simple_http_port):
168             return response
169         else:
170             if self.conf("test-mode") and self._httpd.poll() is not None:
171                 # simply verify cause command failure...
172                 return False
173             return None
174 
175     def _notify_and_wait(self, message):  # pylint: disable=no-self-use
176         # TODO: IDisplay wraps messages, breaking the command
177         #answer = zope.component.getUtility(interfaces.IDisplay).notification(
178         #    message=message, height=25, pause=True)
179         sys.stdout.write(message)
180         raw_input("Press ENTER to continue")
181 
182     def cleanup(self, achalls):
183         # pylint: disable=missing-docstring,no-self-use,unused-argument
184         if self.conf("test-mode"):
185             assert self._httpd is not None, (
186                 "cleanup() must be called after perform()")
187             if self._httpd.poll() is None:
188                 logger.debug("Terminating manual command process")
189                 os.killpg(self._httpd.pid, signal.SIGTERM)
190             else:
191                 logger.debug("Manual command process already terminated "
192                              "with %s code", self._httpd.returncode)
193             shutil.rmtree(self._root)
194
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/letsencrypt/plugins/manual.py b/letsencrypt/plugins/manual.py
--- a/letsencrypt/plugins/manual.py
+++ b/letsencrypt/plugins/manual.py
@@ -4,6 +4,7 @@
 import pipes
 import shutil
 import signal
+import socket
 import subprocess
 import sys
 import tempfile
@@ -122,6 +123,20 @@
             responses.append(self._perform_single(achall))
         return responses
 
+    @classmethod
+    def _test_mode_busy_wait(cls, port):
+        while True:
+            time.sleep(1)
+            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            try:
+                sock.connect(("localhost", port))
+            except socket.error:  # pragma: no cover
+                pass
+            else:
+                break
+            finally:
+                sock.close()
+
     def _perform_single(self, achall):
         # same path for each challenge response would be easier for
         # users, but will not work if multiple domains point at the
@@ -129,13 +144,13 @@
         response, validation = achall.gen_response_and_validation(
             tls=(not self.config.no_simple_http_tls))
 
+        port = (response.port if self.config.simple_http_port is None
+                else int(self.config.simple_http_port))
         command = self.template.format(
             root=self._root, achall=achall, response=response,
             validation=pipes.quote(validation.json_dumps()),
             encoded_token=achall.chall.encode("token"),
-            ct=response.CONTENT_TYPE, port=(
-                response.port if self.config.simple_http_port is None
-                else self.config.simple_http_port))
+            ct=response.CONTENT_TYPE, port=port)
         if self.conf("test-mode"):
             logger.debug("Test mode. Executing the manual command: %s", command)
             try:
@@ -153,7 +168,7 @@
             logger.debug("Manual command running as PID %s.", self._httpd.pid)
             # give it some time to bootstrap, before we try to verify
             # (cert generation in case of simpleHttpS might take time)
-            time.sleep(4)  # XXX
+            self._test_mode_busy_wait(port)
             if self._httpd.poll() is not None:
                 raise errors.Error("Couldn't execute manual command")
         else:

{"golden_diff": "diff --git a/letsencrypt/plugins/manual.py b/letsencrypt/plugins/manual.py\n--- a/letsencrypt/plugins/manual.py\n+++ b/letsencrypt/plugins/manual.py\n@@ -4,6 +4,7 @@\n import pipes\n import shutil\n import signal\n+import socket\n import subprocess\n import sys\n import tempfile\n@@ -122,6 +123,20 @@\n             responses.append(self._perform_single(achall))\n         return responses\n \n+    @classmethod\n+    def _test_mode_busy_wait(cls, port):\n+        while True:\n+            time.sleep(1)\n+            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n+            try:\n+                sock.connect((\"localhost\", port))\n+            except socket.error:  # pragma: no cover\n+                pass\n+            else:\n+                break\n+            finally:\n+                sock.close()\n+\n     def _perform_single(self, achall):\n         # same path for each challenge response would be easier for\n         # users, but will not work if multiple domains point at the\n@@ -129,13 +144,13 @@\n         response, validation = achall.gen_response_and_validation(\n             tls=(not self.config.no_simple_http_tls))\n \n+        port = (response.port if self.config.simple_http_port is None\n+                else int(self.config.simple_http_port))\n         command = self.template.format(\n             root=self._root, achall=achall, response=response,\n             validation=pipes.quote(validation.json_dumps()),\n             encoded_token=achall.chall.encode(\"token\"),\n-            ct=response.CONTENT_TYPE, port=(\n-                response.port if self.config.simple_http_port is None\n-                else self.config.simple_http_port))\n+            ct=response.CONTENT_TYPE, port=port)\n         if self.conf(\"test-mode\"):\n             logger.debug(\"Test mode. Executing the manual command: %s\", command)\n             try:\n@@ -153,7 +168,7 @@\n             logger.debug(\"Manual command running as PID %s.\", self._httpd.pid)\n             # give it some time to bootstrap, before we try to verify\n             # (cert generation in case of simpleHttpS might take time)\n-            time.sleep(4)  # XXX\n+            self._test_mode_busy_wait(port)\n             if self._httpd.poll() is not None:\n                 raise errors.Error(\"Couldn't execute manual command\")\n         else:\n", "issue": "Race condition in recent Travis builds\n#726, #752 and #754 are affected by annoying race condition that causes Travis build to fail randomly (see https://travis-ci.org/letsencrypt/letsencrypt/builds/77715204, https://travis-ci.org/letsencrypt/letsencrypt/builds/78978888, https://travis-ci.org/letsencrypt/letsencrypt/builds/78990354, resp.).\n\nIt seems that manual authenticator doesn't manage to bootstrap on time before we proceed to `simple_verify`.\n\n", "before_files": [{"content": "\"\"\"Manual plugin.\"\"\"\nimport os\nimport logging\nimport pipes\nimport shutil\nimport signal\nimport subprocess\nimport sys\nimport tempfile\nimport time\n\nimport zope.component\nimport zope.interface\n\nfrom acme import challenges\n\nfrom letsencrypt import errors\nfrom letsencrypt import interfaces\nfrom letsencrypt.plugins import common\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass ManualAuthenticator(common.Plugin):\n    \"\"\"Manual Authenticator.\n\n    .. todo:: Support for `~.challenges.DVSNI`.\n\n    \"\"\"\n    zope.interface.implements(interfaces.IAuthenticator)\n    zope.interface.classProvides(interfaces.IPluginFactory)\n\n    description = \"Manual Authenticator\"\n\n    MESSAGE_TEMPLATE = \"\"\"\\\nMake sure your web server displays the following content at\n{uri} before continuing:\n\n{achall.token}\n\nContent-Type header MUST be set to {ct}.\n\nIf you don't have HTTP server configured, you can run the following\ncommand on the target server (as root):\n\n{command}\n\"\"\"\n\n    # \"cd /tmp/letsencrypt\" makes sure user doesn't serve /root,\n    # separate \"public_html\" ensures that cert.pem/key.pem are not\n    # served and makes it more obvious that Python command will serve\n    # anything recursively under the cwd\n\n    HTTP_TEMPLATE = \"\"\"\\\nmkdir -p {root}/public_html/{response.URI_ROOT_PATH}\ncd {root}/public_html\necho -n {validation} > {response.URI_ROOT_PATH}/{encoded_token}\n# run only once per server:\n$(command -v python2 || command -v python2.7 || command -v python2.6) -c \\\\\n\"import BaseHTTPServer, SimpleHTTPServer; \\\\\nSimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {{'': '{ct}'}}; \\\\\ns = BaseHTTPServer.HTTPServer(('', {port}), SimpleHTTPServer.SimpleHTTPRequestHandler); \\\\\ns.serve_forever()\" \"\"\"\n    \"\"\"Non-TLS command template.\"\"\"\n\n    # https://www.piware.de/2011/01/creating-an-https-server-in-python/\n    HTTPS_TEMPLATE = \"\"\"\\\nmkdir -p {root}/public_html/{response.URI_ROOT_PATH}\ncd {root}/public_html\necho -n {validation} > {response.URI_ROOT_PATH}/{encoded_token}\n# run only once per server:\nopenssl req -new -newkey rsa:4096 -subj \"/\" -days 1 -nodes -x509 -keyout ../key.pem -out ../cert.pem\n$(command -v python2 || command -v python2.7 || command -v python2.6) -c \\\\\n\"import BaseHTTPServer, SimpleHTTPServer, ssl; \\\\\nSimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {{'': '{ct}'}}; \\\\\ns = BaseHTTPServer.HTTPServer(('', {port}), SimpleHTTPServer.SimpleHTTPRequestHandler); \\\\\ns.socket = ssl.wrap_socket(s.socket, keyfile='../key.pem', certfile='../cert.pem'); \\\\\ns.serve_forever()\" \"\"\"\n    \"\"\"TLS command template.\n\n    According to the ACME specification, \"the ACME server MUST ignore\n    the certificate provided by the HTTPS server\", so the first command\n    generates temporary self-signed certificate.\n\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        super(ManualAuthenticator, self).__init__(*args, **kwargs)\n        self.template = (self.HTTP_TEMPLATE if self.config.no_simple_http_tls\n                         else self.HTTPS_TEMPLATE)\n        self._root = (tempfile.mkdtemp() if self.conf(\"test-mode\")\n                      else \"/tmp/letsencrypt\")\n        self._httpd = None\n\n    @classmethod\n    def add_parser_arguments(cls, add):\n        add(\"test-mode\", action=\"store_true\",\n            help=\"Test mode. Executes the manual command in subprocess. \"\n            \"Requires openssl to be installed unless --no-simple-http-tls.\")\n\n    def prepare(self):  # pylint: disable=missing-docstring,no-self-use\n        pass  # pragma: no cover\n\n    def more_info(self):  # pylint: disable=missing-docstring,no-self-use\n        return \"\"\"\\\nThis plugin requires user's manual intervention in setting up a HTTP\nserver for solving SimpleHTTP challenges and thus does not need to be\nrun as a privilidged process. Alternatively shows instructions on how\nto use Python's built-in HTTP server and, in case of HTTPS, openssl\nbinary for temporary key/certificate generation.\"\"\".replace(\"\\n\", \"\")\n\n    def get_chall_pref(self, domain):\n        # pylint: disable=missing-docstring,no-self-use,unused-argument\n        return [challenges.SimpleHTTP]\n\n    def perform(self, achalls):  # pylint: disable=missing-docstring\n        responses = []\n        # TODO: group achalls by the same socket.gethostbyname(_ex)\n        # and prompt only once per server (one \"echo -n\" per domain)\n        for achall in achalls:\n            responses.append(self._perform_single(achall))\n        return responses\n\n    def _perform_single(self, achall):\n        # same path for each challenge response would be easier for\n        # users, but will not work if multiple domains point at the\n        # same server: default command doesn't support virtual hosts\n        response, validation = achall.gen_response_and_validation(\n            tls=(not self.config.no_simple_http_tls))\n\n        command = self.template.format(\n            root=self._root, achall=achall, response=response,\n            validation=pipes.quote(validation.json_dumps()),\n            encoded_token=achall.chall.encode(\"token\"),\n            ct=response.CONTENT_TYPE, port=(\n                response.port if self.config.simple_http_port is None\n                else self.config.simple_http_port))\n        if self.conf(\"test-mode\"):\n            logger.debug(\"Test mode. Executing the manual command: %s\", command)\n            try:\n                self._httpd = subprocess.Popen(\n                    command,\n                    # don't care about setting stdout and stderr,\n                    # we're in test mode anyway\n                    shell=True,\n                    # \"preexec_fn\" is UNIX specific, but so is \"command\"\n                    preexec_fn=os.setsid)\n            except OSError as error:  # ValueError should not happen!\n                logger.debug(\n                    \"Couldn't execute manual command: %s\", error, exc_info=True)\n                return False\n            logger.debug(\"Manual command running as PID %s.\", self._httpd.pid)\n            # give it some time to bootstrap, before we try to verify\n            # (cert generation in case of simpleHttpS might take time)\n            time.sleep(4)  # XXX\n            if self._httpd.poll() is not None:\n                raise errors.Error(\"Couldn't execute manual command\")\n        else:\n            self._notify_and_wait(self.MESSAGE_TEMPLATE.format(\n                achall=achall, response=response,\n                uri=response.uri(achall.domain, achall.challb.chall),\n                ct=response.CONTENT_TYPE, command=command))\n\n        if response.simple_verify(\n                achall.chall, achall.domain,\n                achall.account_key.public_key(), self.config.simple_http_port):\n            return response\n        else:\n            if self.conf(\"test-mode\") and self._httpd.poll() is not None:\n                # simply verify cause command failure...\n                return False\n            return None\n\n    def _notify_and_wait(self, message):  # pylint: disable=no-self-use\n        # TODO: IDisplay wraps messages, breaking the command\n        #answer = zope.component.getUtility(interfaces.IDisplay).notification(\n        #    message=message, height=25, pause=True)\n        sys.stdout.write(message)\n        raw_input(\"Press ENTER to continue\")\n\n    def cleanup(self, achalls):\n        # pylint: disable=missing-docstring,no-self-use,unused-argument\n        if self.conf(\"test-mode\"):\n            assert self._httpd is not None, (\n                \"cleanup() must be called after perform()\")\n            if self._httpd.poll() is None:\n                logger.debug(\"Terminating manual command process\")\n                os.killpg(self._httpd.pid, signal.SIGTERM)\n            else:\n                logger.debug(\"Manual command process already terminated \"\n                             \"with %s code\", self._httpd.returncode)\n            shutil.rmtree(self._root)\n", "path": "letsencrypt/plugins/manual.py"}], "after_files": [{"content": "\"\"\"Manual plugin.\"\"\"\nimport os\nimport logging\nimport pipes\nimport shutil\nimport signal\nimport socket\nimport subprocess\nimport sys\nimport tempfile\nimport time\n\nimport zope.component\nimport zope.interface\n\nfrom acme import challenges\n\nfrom letsencrypt import errors\nfrom letsencrypt import interfaces\nfrom letsencrypt.plugins import common\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass ManualAuthenticator(common.Plugin):\n    \"\"\"Manual Authenticator.\n\n    .. todo:: Support for `~.challenges.DVSNI`.\n\n    \"\"\"\n    zope.interface.implements(interfaces.IAuthenticator)\n    zope.interface.classProvides(interfaces.IPluginFactory)\n\n    description = \"Manual Authenticator\"\n\n    MESSAGE_TEMPLATE = \"\"\"\\\nMake sure your web server displays the following content at\n{uri} before continuing:\n\n{achall.token}\n\nContent-Type header MUST be set to {ct}.\n\nIf you don't have HTTP server configured, you can run the following\ncommand on the target server (as root):\n\n{command}\n\"\"\"\n\n    # \"cd /tmp/letsencrypt\" makes sure user doesn't serve /root,\n    # separate \"public_html\" ensures that cert.pem/key.pem are not\n    # served and makes it more obvious that Python command will serve\n    # anything recursively under the cwd\n\n    HTTP_TEMPLATE = \"\"\"\\\nmkdir -p {root}/public_html/{response.URI_ROOT_PATH}\ncd {root}/public_html\necho -n {validation} > {response.URI_ROOT_PATH}/{encoded_token}\n# run only once per server:\n$(command -v python2 || command -v python2.7 || command -v python2.6) -c \\\\\n\"import BaseHTTPServer, SimpleHTTPServer; \\\\\nSimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {{'': '{ct}'}}; \\\\\ns = BaseHTTPServer.HTTPServer(('', {port}), SimpleHTTPServer.SimpleHTTPRequestHandler); \\\\\ns.serve_forever()\" \"\"\"\n    \"\"\"Non-TLS command template.\"\"\"\n\n    # https://www.piware.de/2011/01/creating-an-https-server-in-python/\n    HTTPS_TEMPLATE = \"\"\"\\\nmkdir -p {root}/public_html/{response.URI_ROOT_PATH}\ncd {root}/public_html\necho -n {validation} > {response.URI_ROOT_PATH}/{encoded_token}\n# run only once per server:\nopenssl req -new -newkey rsa:4096 -subj \"/\" -days 1 -nodes -x509 -keyout ../key.pem -out ../cert.pem\n$(command -v python2 || command -v python2.7 || command -v python2.6) -c \\\\\n\"import BaseHTTPServer, SimpleHTTPServer, ssl; \\\\\nSimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {{'': '{ct}'}}; \\\\\ns = BaseHTTPServer.HTTPServer(('', {port}), SimpleHTTPServer.SimpleHTTPRequestHandler); \\\\\ns.socket = ssl.wrap_socket(s.socket, keyfile='../key.pem', certfile='../cert.pem'); \\\\\ns.serve_forever()\" \"\"\"\n    \"\"\"TLS command template.\n\n    According to the ACME specification, \"the ACME server MUST ignore\n    the certificate provided by the HTTPS server\", so the first command\n    generates temporary self-signed certificate.\n\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        super(ManualAuthenticator, self).__init__(*args, **kwargs)\n        self.template = (self.HTTP_TEMPLATE if self.config.no_simple_http_tls\n                         else self.HTTPS_TEMPLATE)\n        self._root = (tempfile.mkdtemp() if self.conf(\"test-mode\")\n                      else \"/tmp/letsencrypt\")\n        self._httpd = None\n\n    @classmethod\n    def add_parser_arguments(cls, add):\n        add(\"test-mode\", action=\"store_true\",\n            help=\"Test mode. Executes the manual command in subprocess. \"\n            \"Requires openssl to be installed unless --no-simple-http-tls.\")\n\n    def prepare(self):  # pylint: disable=missing-docstring,no-self-use\n        pass  # pragma: no cover\n\n    def more_info(self):  # pylint: disable=missing-docstring,no-self-use\n        return \"\"\"\\\nThis plugin requires user's manual intervention in setting up a HTTP\nserver for solving SimpleHTTP challenges and thus does not need to be\nrun as a privilidged process. Alternatively shows instructions on how\nto use Python's built-in HTTP server and, in case of HTTPS, openssl\nbinary for temporary key/certificate generation.\"\"\".replace(\"\\n\", \"\")\n\n    def get_chall_pref(self, domain):\n        # pylint: disable=missing-docstring,no-self-use,unused-argument\n        return [challenges.SimpleHTTP]\n\n    def perform(self, achalls):  # pylint: disable=missing-docstring\n        responses = []\n        # TODO: group achalls by the same socket.gethostbyname(_ex)\n        # and prompt only once per server (one \"echo -n\" per domain)\n        for achall in achalls:\n            responses.append(self._perform_single(achall))\n        return responses\n\n    @classmethod\n    def _test_mode_busy_wait(cls, port):\n        while True:\n            time.sleep(1)\n            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            try:\n                sock.connect((\"localhost\", port))\n            except socket.error:  # pragma: no cover\n                pass\n            else:\n                break\n            finally:\n                sock.close()\n\n    def _perform_single(self, achall):\n        # same path for each challenge response would be easier for\n        # users, but will not work if multiple domains point at the\n        # same server: default command doesn't support virtual hosts\n        response, validation = achall.gen_response_and_validation(\n            tls=(not self.config.no_simple_http_tls))\n\n        port = (response.port if self.config.simple_http_port is None\n                else int(self.config.simple_http_port))\n        command = self.template.format(\n            root=self._root, achall=achall, response=response,\n            validation=pipes.quote(validation.json_dumps()),\n            encoded_token=achall.chall.encode(\"token\"),\n            ct=response.CONTENT_TYPE, port=port)\n        if self.conf(\"test-mode\"):\n            logger.debug(\"Test mode. Executing the manual command: %s\", command)\n            try:\n                self._httpd = subprocess.Popen(\n                    command,\n                    # don't care about setting stdout and stderr,\n                    # we're in test mode anyway\n                    shell=True,\n                    # \"preexec_fn\" is UNIX specific, but so is \"command\"\n                    preexec_fn=os.setsid)\n            except OSError as error:  # ValueError should not happen!\n                logger.debug(\n                    \"Couldn't execute manual command: %s\", error, exc_info=True)\n                return False\n            logger.debug(\"Manual command running as PID %s.\", self._httpd.pid)\n            # give it some time to bootstrap, before we try to verify\n            # (cert generation in case of simpleHttpS might take time)\n            self._test_mode_busy_wait(port)\n            if self._httpd.poll() is not None:\n                raise errors.Error(\"Couldn't execute manual command\")\n        else:\n            self._notify_and_wait(self.MESSAGE_TEMPLATE.format(\n                achall=achall, response=response,\n                uri=response.uri(achall.domain, achall.challb.chall),\n                ct=response.CONTENT_TYPE, command=command))\n\n        if response.simple_verify(\n                achall.chall, achall.domain,\n                achall.account_key.public_key(), self.config.simple_http_port):\n            return response\n        else:\n            if self.conf(\"test-mode\") and self._httpd.poll() is not None:\n                # simply verify cause command failure...\n                return False\n            return None\n\n    def _notify_and_wait(self, message):  # pylint: disable=no-self-use\n        # TODO: IDisplay wraps messages, breaking the command\n        #answer = zope.component.getUtility(interfaces.IDisplay).notification(\n        #    message=message, height=25, pause=True)\n        sys.stdout.write(message)\n        raw_input(\"Press ENTER to continue\")\n\n    def cleanup(self, achalls):\n        # pylint: disable=missing-docstring,no-self-use,unused-argument\n        if self.conf(\"test-mode\"):\n            assert self._httpd is not None, (\n                \"cleanup() must be called after perform()\")\n            if self._httpd.poll() is None:\n                logger.debug(\"Terminating manual command process\")\n                os.killpg(self._httpd.pid, signal.SIGTERM)\n            else:\n                logger.debug(\"Manual command process already terminated \"\n                             \"with %s code\", self._httpd.returncode)\n            shutil.rmtree(self._root)\n", "path": "letsencrypt/plugins/manual.py"}]}