Browse Source

added optional contact details

Daniel Roesler 7 years ago
parent
commit
aaf1091838
2 changed files with 39 additions and 10 deletions
  1. 7 3
      acme_tiny.py
  2. 32 7
      tests/test_module.py

+ 7 - 3
acme_tiny.py

@@ -12,7 +12,7 @@ LOGGER = logging.getLogger(__name__)
 LOGGER.addHandler(logging.StreamHandler())
 LOGGER.setLevel(logging.INFO)
 
-def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA, disable_check=False, directory_url=DEFAULT_DIRECTORY_URL):
+def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA, disable_check=False, directory_url=DEFAULT_DIRECTORY_URL, contact=None):
     directory, acct_headers, alg, jwk = None, None, None, None # global variables
 
     # helper functions - base64 encode for jose spec
@@ -104,11 +104,14 @@ def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA, disable_check
     directory, _, _ = _do_request(directory_url, err_msg="Error getting directory")
     log.info("Directory found!")
 
-    # create account and set the global key identifier
+    # create account, update contact details (if any), and set the global key identifier
     log.info("Registering account...")
     reg_payload = {"termsOfServiceAgreed": True}
     account, code, acct_headers = _send_signed_request(directory['newAccount'], reg_payload, "Error registering")
     log.info("Registered!" if code == 201 else "Already registered!")
+    if contact is not None:
+        account, _, _ = _send_signed_request(acct_headers['Location'], {"contact": contact}, "Error updating contact details")
+        log.info("Updated contact details:\n{}".format("\n".join(account['contact'])))
 
     # create a new order
     log.info("Creating new order...")
@@ -185,10 +188,11 @@ def main(argv=None):
     parser.add_argument("--disable-check", default=False, action="store_true", help="disable checking if the challenge file is hosted correctly before telling the CA")
     parser.add_argument("--directory-url", default=DEFAULT_DIRECTORY_URL, help="certificate authority directory url, default is Let's Encrypt")
     parser.add_argument("--ca", default=DEFAULT_CA, help="DEPRECATED! USE --directory-url INSTEAD!")
+    parser.add_argument("--contact", metavar="CONTACT", default=None, nargs="*", help="Contact details (e.g. mailto:aaa@bbb.com) for your account-key")
 
     args = parser.parse_args(argv)
     LOGGER.setLevel(args.quiet or LOGGER.level)
-    signed_crt = get_crt(args.account_key, args.csr, args.acme_dir, log=LOGGER, CA=args.ca, disable_check=args.disable_check, directory_url=args.directory_url)
+    signed_crt = get_crt(args.account_key, args.csr, args.acme_dir, log=LOGGER, CA=args.ca, disable_check=args.disable_check, directory_url=args.directory_url, contact=args.contact)
     sys.stdout.write(signed_crt)
 
 if __name__ == "__main__": # pragma: no cover

+ 32 - 7
tests/test_module.py

@@ -1,4 +1,4 @@
-import unittest, os, sys, tempfile
+import unittest, os, sys, tempfile, logging
 from subprocess import Popen, PIPE
 try:
     from StringIO import StringIO # Python 2
@@ -36,8 +36,7 @@ class TestModule(unittest.TestCase):
         sys.stdout.seek(0)
         crt = sys.stdout.read().encode("utf8")
         sys.stdout = old_stdout
-        out, err = Popen(["openssl", "x509", "-text", "-noout"], stdin=PIPE,
-            stdout=PIPE, stderr=PIPE).communicate(crt)
+        out, err = Popen(["openssl", "x509", "-text", "-noout"], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(crt)
         self.assertIn("Issuer: CN=Fake LE Intermediate", out.decode("utf8"))
 
     def test_success_san(self):
@@ -53,8 +52,7 @@ class TestModule(unittest.TestCase):
         sys.stdout.seek(0)
         crt = sys.stdout.read().encode("utf8")
         sys.stdout = old_stdout
-        out, err = Popen(["openssl", "x509", "-text", "-noout"], stdin=PIPE,
-            stdout=PIPE, stderr=PIPE).communicate(crt)
+        out, err = Popen(["openssl", "x509", "-text", "-noout"], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(crt)
         self.assertIn("Issuer: CN=Fake LE Intermediate", out.decode("utf8"))
 
     def test_success_cli(self):
@@ -66,8 +64,7 @@ class TestModule(unittest.TestCase):
             "--acme-dir", self.tempdir,
             "--directory-url", self.DIR_URL,
         ], stdout=PIPE, stderr=PIPE).communicate()
-        out, err = Popen(["openssl", "x509", "-text", "-noout"], stdin=PIPE,
-            stdout=PIPE, stderr=PIPE).communicate(crt)
+        out, err = Popen(["openssl", "x509", "-text", "-noout"], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(crt)
         self.assertIn("Issuer: CN=Fake LE Intermediate", out.decode("utf8"))
 
     def test_missing_account_key(self):
@@ -154,3 +151,31 @@ class TestModule(unittest.TestCase):
         self.assertIsInstance(result, ValueError)
         self.assertIn("certificate public key must be different than account key", result.args[0])
 
+    def test_contact(self):
+        """ Make sure optional contact details can be set """
+        # add a logging handler that captures the info log output
+        log_output = StringIO()
+        debug_handler = logging.StreamHandler(log_output)
+        acme_tiny.LOGGER.addHandler(debug_handler)
+        # call acme_tiny with new contact details
+        old_stdout = sys.stdout
+        sys.stdout = StringIO()
+        result = acme_tiny.main([
+            "--account-key", KEYS['account_key'].name,
+            "--csr", KEYS['domain_csr'].name,
+            "--acme-dir", self.tempdir,
+            "--directory-url", self.DIR_URL,
+            "--contact", "mailto:devteam@example.com", "mailto:boss@example.com",
+        ])
+        sys.stdout.seek(0)
+        crt = sys.stdout.read().encode("utf8")
+        sys.stdout = old_stdout
+        log_output.seek(0)
+        log_string = log_output.read().encode("utf8")
+        # make sure the certificate was issued and the contact details were updated
+        out, err = Popen(["openssl", "x509", "-text", "-noout"], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(crt)
+        self.assertIn("Issuer: CN=Fake LE Intermediate", out.decode("utf8"))
+        self.assertIn("Updated contact details:\nmailto:devteam@example.com\nmailto:boss@example.com", log_string)
+        # remove logging capture
+        acme_tiny.LOGGER.removeHandler(debug_handler)
+