diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 04a06779b..0dfed928d 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -1306,7 +1306,9 @@ def _plugins_parsing(helpful, plugins): help="JSON dictionary mapping domains to webroot paths; this implies -d " "for each entry. You may need to escape this from your shell. " """Eg: --webroot-map '{"eg1.is,m.eg1.is":"/www/eg1/", "eg2.is":"/www/eg2"}' """ - "This option is merged with, but takes precedence over, -w / -d entries") + "This option is merged with, but takes precedence over, -w / -d entries." + " At present, if you put webroot-map in a config file, it needs to be " + ' on a single line, like: webroot-map = {"example.com":"/var/www"}.') class WebrootPathProcessor(argparse.Action): # pylint: disable=missing-docstring def __init__(self, *args, **kwargs): @@ -1337,21 +1339,26 @@ class WebrootPathProcessor(argparse.Action): # pylint: disable=missing-docstring _undot = lambda domain: domain[:-1] if domain.endswith('.') else domain -def _process_domain(args, domain_arg, webroot_path=None): +def _process_domain(args_or_config, domain_arg, webroot_path=None): """ Process a new -d flag, helping the webroot plugin construct a map of {domain : webrootpath} if -w / --webroot-path is in use + + :param args_or_config: may be an argparse args object, or a NamespaceConfig object + :param str domain_arg: a string representing 1+ domains, eg: "eg.is, example.com" + :param str webroot_path: (optional) the webroot_path for these domains + """ - webroot_path = webroot_path if webroot_path else args.webroot_path + webroot_path = webroot_path if webroot_path else args_or_config.webroot_path for domain in (d.strip() for d in domain_arg.split(",")): - if domain not in args.domains: + if domain not in args_or_config.domains: domain = _undot(domain) - args.domains.append(domain) + args_or_config.domains.append(domain) # Each domain has a webroot_path of the most recent -w flag # unless it was explicitly included in webroot_map if webroot_path: - args.webroot_map.setdefault(domain, webroot_path[-1]) + args_or_config.webroot_map.setdefault(domain, webroot_path[-1]) class WebrootMapProcessor(argparse.Action): # pylint: disable=missing-docstring diff --git a/letsencrypt/configuration.py b/letsencrypt/configuration.py index afd5edbe4..37eaba3bd 100644 --- a/letsencrypt/configuration.py +++ b/letsencrypt/configuration.py @@ -124,4 +124,5 @@ def check_config_sanity(config): # Domain checks if config.namespace.domains is not None: for domain in config.namespace.domains: - le_util.check_domain_sanity(domain) + # This may be redundant, but let's be paranoid + le_util.enforce_domain_sanity(domain) diff --git a/letsencrypt/display/ops.py b/letsencrypt/display/ops.py index b3c057301..f0dec8b06 100644 --- a/letsencrypt/display/ops.py +++ b/letsencrypt/display/ops.py @@ -239,8 +239,7 @@ def get_valid_domains(domains): valid_domains = [] for domain in domains: try: - le_util.check_domain_sanity(domain) - valid_domains.append(domain) + valid_domains.append(le_util.enforce_domain_sanity(domain)) except errors.ConfigurationError: continue return valid_domains @@ -282,9 +281,9 @@ def _choose_names_manually(): "supported.{0}{0}Would you like to re-enter the " "names?{0}").format(os.linesep) - for domain in domain_list: + for i, domain in enumerate(domain_list): try: - le_util.check_domain_sanity(domain) + domain_list[i] = le_util.enforce_domain_sanity(domain) except errors.ConfigurationError as e: invalid_domains[domain] = e.message diff --git a/letsencrypt/le_util.py b/letsencrypt/le_util.py index d97d43dc6..35793849e 100644 --- a/letsencrypt/le_util.py +++ b/letsencrypt/le_util.py @@ -285,15 +285,17 @@ def add_deprecated_argument(add_argument, argument_name, nargs): help=argparse.SUPPRESS, nargs=nargs) -def check_domain_sanity(domain): +def enforce_domain_sanity(domain): """Method which validates domain value and errors out if the requirements are not met. :param domain: Domain to check - :type domains: `string` + :type domains: `str` or `unicode` :raises ConfigurationError: for invalid domains and cases where Let's Encrypt currently will not issue certificates + :returns: The domain cast to `str`, with ASCII-only contents + :rtype: str """ # Check if there's a wildcard domain if domain.startswith("*."): @@ -306,12 +308,15 @@ def check_domain_sanity(domain): # Unicode try: - domain.encode('ascii') + domain = domain.encode('ascii') except UnicodeDecodeError: raise errors.ConfigurationError( "Internationalized domain names are not presently supported: {0}" .format(domain)) + # Remove trailing dot + domain = domain[:-1] if domain.endswith('.') else domain + # FQDN checks from # http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/ # Characters used, domain parts < 63 chars, tld > 1 < 64 chars @@ -319,3 +324,4 @@ def check_domain_sanity(domain): fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(?