diff --git a/acme/acme/client.py b/acme/acme/client.py index 0e9319f9c..082dcb5cd 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -37,6 +37,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes :ivar key: `.JWK` (private) :ivar alg: `.JWASignature` :ivar bool verify_ssl: Verify SSL certificates? + :ivar str ua: User agent string to send to the server. :ivar .ClientNetwork net: Client network. Useful for testing. If not supplied, it will be initialized using `key`, `alg` and `verify_ssl`. @@ -45,7 +46,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes DER_CONTENT_TYPE = 'application/pkix-cert' def __init__(self, directory, key, alg=jose.RS256, verify_ssl=True, - net=None): + net=None, ua="acme-python"): """Initialize. :param directory: Directory Resource (`.messages.Directory`) or @@ -53,7 +54,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes """ self.key = key - self.net = ClientNetwork(key, alg, verify_ssl) if net is None else net + self.net = ClientNetwork(key, alg, verify_ssl, user_agent) if net is None else net if isinstance(directory, six.string_types): self.directory = messages.Directory.from_json( diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index c37533115..6f4facc3e 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -169,6 +169,7 @@ def _determine_account(args, config): def _init_le_client(args, config, authenticator, installer): + config.deterimine_user_agent(authenticator, installer) if authenticator is not None: # if authenticator was given, then we will need account... acc, acme = _determine_account(args, config) @@ -521,6 +522,7 @@ def revoke(args, config, unused_plugins): # TODO: coop with renewal config logger.debug("Revoking %s using Account Key", args.cert_path[0]) acc, _ = _determine_account(args, config) # pylint: disable=protected-access + config.determine_user_agent(None, None) acme = client._acme_from_config_key(config, acc.key) acme.revoke(jose.ComparableX509(crypto_util.pyopenssl_load_certificate( args.cert_path[1])[0])) diff --git a/letsencrypt/client.py b/letsencrypt/client.py index 8a0ad6af4..0b4297791 100644 --- a/letsencrypt/client.py +++ b/letsencrypt/client.py @@ -32,7 +32,8 @@ logger = logging.getLogger(__name__) def _acme_from_config_key(config, key): # TODO: Allow for other alg types besides RS256 return acme_client.Client(directory=config.server, key=key, - verify_ssl=(not config.no_verify_ssl)) + verify_ssl=(not config.no_verify_ssl), + ua=config.user_agent) def register(config, account_storage, tos_cb=None): diff --git a/letsencrypt/configuration.py b/letsencrypt/configuration.py index e70171675..a3fd33d69 100644 --- a/letsencrypt/configuration.py +++ b/letsencrypt/configuration.py @@ -3,6 +3,7 @@ import os import urlparse import re +import letsencrypt import zope.interface from acme import challenges @@ -82,6 +83,19 @@ class NamespaceConfig(object): else: return challenges.HTTP01Response.PORT + def determine_user_agent(self, authenticator, installer): + # The user agent string isn't knowable until the authenticator and + # installer have been chosen. + + if self.user_agent is None: + ua = "LetsEncryptPythonClient/{0} ({1}) Authenticator/{2} Installer/{3}" + ua = ua.format(letsencrypt.__version__, le_util.get_os_info(), + authenticator.name if authenticator else "none", + installer.name if installer else "none") + self.user_agent=ua + else: + assert isinstance(self.user_agent, str), "User Agent not a string?" + class RenewerConfiguration(object): """Configuration wrapper for renewer.""" diff --git a/letsencrypt/le_util.py b/letsencrypt/le_util.py index 413cec43d..4a780e36b 100644 --- a/letsencrypt/le_util.py +++ b/letsencrypt/le_util.py @@ -3,6 +3,7 @@ import collections import errno import logging import os +import platform import re import subprocess import stat @@ -226,7 +227,7 @@ def get_os_info(): os_ver = os_ver.parititon("-")[0] os_ver = os_ver.parititon(".")[0] elif platform.win32_ver()[1]: - os_ver = win32_ver()[1] + os_ver = platform.win32_ver()[1] else: # Cases known to fall here: Cygwin python os_ver = ''