diff --git a/certbot/cli.py b/certbot/cli.py index eaafce762..7135f7600 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -1145,6 +1145,11 @@ def _create_subparsers(helpful): '(default: {0}). The flags encoded in the user agent are: ' '--duplicate, --force-renew, --allow-subset-of-names, -n, and ' 'whether any hooks are set.'.format(sample_user_agent())) + helpful.add( + None, "--user-agent-comment", default=None, type=_user_agent_comment_type, + help="Add a comment to the default user agent string. May be used when repackaging Certbot " + "or calling it from another tool to allow additional statistical data to be collected." + " Ignored if --user-agent is set. (Example: Foo-Wrapper/1.0)") helpful.add("certonly", "--csr", type=read_file, help="Path to a Certificate Signing Request (CSR) in DER or PEM format." @@ -1360,6 +1365,10 @@ def parse_preferred_challenges(pref_challs): "Unrecognized challenges: {0}".format(unrecognized)) return challs +def _user_agent_comment_type(value): + if "(" in value or ")" in value: + raise argparse.ArgumentTypeError("may not contain parentheses") + return value class _DeployHookAction(argparse.Action): """Action class for parsing deploy hooks.""" diff --git a/certbot/client.py b/certbot/client.py index 6010dd0a0..ed70fda71 100644 --- a/certbot/client.py +++ b/certbot/client.py @@ -58,11 +58,12 @@ def determine_user_agent(config): # policy, talk to a core Certbot team member before making any # changes here. if config.user_agent is None: - ua = ("CertbotACMEClient/{0} ({1}; {2}) Authenticator/{3} Installer/{4} " + ua = ("CertbotACMEClient/{0} ({1}; {2}{8}) Authenticator/{3} Installer/{4} " "({5}; flags: {6}) Py/{7}") ua = ua.format(certbot.__version__, cli.cli_command, util.get_os_info_ua(), config.authenticator, config.installer, config.verb, - ua_flags(config), platform.python_version()) + ua_flags(config), platform.python_version(), + "; " + config.user_agent_comment if config.user_agent_comment else "") else: ua = config.user_agent return ua