mirror of
https://github.com/certbot/certbot.git
synced 2026-06-08 16:22:18 -04:00
Merge branch 'config_sanity'
This commit is contained in:
commit
6c3ea0d2a1
5 changed files with 87 additions and 21 deletions
|
|
@ -28,6 +28,7 @@ from letsencrypt import configuration
|
|||
from letsencrypt import constants
|
||||
from letsencrypt import client
|
||||
from letsencrypt import crypto_util
|
||||
from letsencrypt import errors
|
||||
from letsencrypt import interfaces
|
||||
from letsencrypt import le_util
|
||||
from letsencrypt import log
|
||||
|
|
@ -36,7 +37,6 @@ from letsencrypt import storage
|
|||
|
||||
from letsencrypt.display import util as display_util
|
||||
from letsencrypt.display import ops as display_ops
|
||||
from letsencrypt.errors import Error, PluginSelectionError, CertStorageError
|
||||
from letsencrypt.plugins import disco as plugins_disco
|
||||
|
||||
|
||||
|
|
@ -106,8 +106,8 @@ def _find_domains(args, installer):
|
|||
domains = args.domains
|
||||
|
||||
if not domains:
|
||||
raise Error("Please specify --domains, or --installer that "
|
||||
"will help in domain names autodiscovery")
|
||||
raise errors.Error("Please specify --domains, or --installer that "
|
||||
"will help in domain names autodiscovery")
|
||||
|
||||
return domains
|
||||
|
||||
|
|
@ -159,9 +159,9 @@ def _determine_account(args, config):
|
|||
try:
|
||||
acc, acme = client.register(
|
||||
config, account_storage, tos_cb=_tos_cb)
|
||||
except Error as error:
|
||||
except errors.Error as error:
|
||||
logger.debug(error, exc_info=True)
|
||||
raise Error(
|
||||
raise errors.Error(
|
||||
"Unable to register an account with ACME server")
|
||||
|
||||
args.account = acc.id
|
||||
|
|
@ -195,7 +195,7 @@ def _find_duplicative_certs(config, domains):
|
|||
try:
|
||||
full_path = os.path.join(configs_dir, renewal_file)
|
||||
candidate_lineage = storage.RenewableCert(full_path, cli_config)
|
||||
except (CertStorageError, IOError):
|
||||
except (errors.CertStorageError, IOError):
|
||||
logger.warning("Renewal configuration file %s is broken. "
|
||||
"Skipping.", full_path)
|
||||
continue
|
||||
|
|
@ -267,7 +267,7 @@ def _treat_as_renewal(config, domains):
|
|||
br=os.linesep
|
||||
),
|
||||
reporter_util.HIGH_PRIORITY)
|
||||
raise Error(
|
||||
raise errors.Error(
|
||||
"User did not use proper CLI and would like "
|
||||
"to reinvoke the client.")
|
||||
|
||||
|
|
@ -327,7 +327,7 @@ def _auth_from_domains(le_client, config, domains, plugins):
|
|||
# TREAT AS NEW REQUEST
|
||||
lineage = le_client.obtain_and_enroll_certificate(domains, plugins)
|
||||
if not lineage:
|
||||
raise Error("Certificate could not be obtained")
|
||||
raise errors.Error("Certificate could not be obtained")
|
||||
|
||||
_report_new_cert(lineage.cert, lineage.fullchain)
|
||||
|
||||
|
|
@ -346,7 +346,7 @@ def set_configurator(previously, now):
|
|||
if previously:
|
||||
if previously != now:
|
||||
msg = "Too many flags setting configurators/installers/authenticators {0} -> {1}"
|
||||
raise PluginSelectionError(msg.format(repr(previously), repr(now)))
|
||||
raise errors.PluginSelectionError(msg.format(repr(previously), repr(now)))
|
||||
return now
|
||||
|
||||
|
||||
|
|
@ -379,7 +379,7 @@ def diagnose_configurator_problem(cfg_type, requested, plugins):
|
|||
'"letsencrypt-auto certonly" to get a cert you can install manually')
|
||||
else:
|
||||
msg = "{0} could not be determined or is not installed".format(cfg_type)
|
||||
raise PluginSelectionError(msg)
|
||||
raise errors.PluginSelectionError(msg)
|
||||
|
||||
|
||||
def choose_configurator_plugins(args, config, plugins, verb):
|
||||
|
|
@ -439,7 +439,7 @@ def run(args, config, plugins): # pylint: disable=too-many-branches,too-many-lo
|
|||
"""Obtain a certificate and install."""
|
||||
try:
|
||||
installer, authenticator = choose_configurator_plugins(args, config, plugins, "run")
|
||||
except PluginSelectionError, e:
|
||||
except errors.PluginSelectionError, e:
|
||||
return e.message
|
||||
|
||||
domains = _find_domains(args, installer)
|
||||
|
|
@ -472,7 +472,7 @@ def obtaincert(args, config, plugins):
|
|||
try:
|
||||
# installers are used in auth mode to determine domain names
|
||||
installer, authenticator = choose_configurator_plugins(args, config, plugins, "certonly")
|
||||
except PluginSelectionError, e:
|
||||
except errors.PluginSelectionError, e:
|
||||
return e.message
|
||||
|
||||
# TODO: Handle errors from _init_le_client?
|
||||
|
|
@ -497,7 +497,7 @@ def install(args, config, plugins):
|
|||
try:
|
||||
installer, _ = choose_configurator_plugins(args, config,
|
||||
plugins, "install")
|
||||
except PluginSelectionError, e:
|
||||
except errors.PluginSelectionError, e:
|
||||
return e.message
|
||||
|
||||
domains = _find_domains(args, installer)
|
||||
|
|
@ -1060,7 +1060,7 @@ def _handle_exception(exc_type, exc_value, trace, args):
|
|||
sys.exit("".join(
|
||||
traceback.format_exception(exc_type, exc_value, trace)))
|
||||
|
||||
if issubclass(exc_type, Error):
|
||||
if issubclass(exc_type, errors.Error):
|
||||
sys.exit(exc_value)
|
||||
else:
|
||||
# Tell the user a bit about what happened, without overwhelming
|
||||
|
|
@ -1124,7 +1124,7 @@ def main(cli_args=sys.argv[1:]):
|
|||
disclaimer = pkg_resources.resource_string("letsencrypt", "DISCLAIMER")
|
||||
if not zope.component.getUtility(interfaces.IDisplay).yesno(
|
||||
disclaimer, "Agree", "Cancel"):
|
||||
raise Error("Must agree to TOS")
|
||||
raise errors.Error("Must agree to TOS")
|
||||
|
||||
if not os.geteuid() == 0:
|
||||
logger.warning(
|
||||
|
|
@ -1139,7 +1139,6 @@ def main(cli_args=sys.argv[1:]):
|
|||
|
||||
return args.func(args, config, plugins)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
err_string = main()
|
||||
if err_string:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""Let's Encrypt user-supplied configuration."""
|
||||
import os
|
||||
import urlparse
|
||||
import re
|
||||
|
||||
import zope.interface
|
||||
|
||||
|
|
@ -36,11 +37,8 @@ class NamespaceConfig(object):
|
|||
|
||||
def __init__(self, namespace):
|
||||
self.namespace = namespace
|
||||
|
||||
if self.http01_port == self.tls_sni_01_port:
|
||||
raise errors.Error(
|
||||
"Trying to run http-01 and tls-sni-01 "
|
||||
"on the same port ({0})".format(self.tls_sni_01_port))
|
||||
# Check command line parameters sanity, and error out in case of problem.
|
||||
check_config_sanity(self)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.namespace, name)
|
||||
|
|
@ -111,3 +109,49 @@ class RenewerConfiguration(object):
|
|||
def renewer_config_file(self): # pylint: disable=missing-docstring
|
||||
return os.path.join(
|
||||
self.namespace.config_dir, constants.RENEWER_CONFIG_FILENAME)
|
||||
|
||||
|
||||
def check_config_sanity(config):
|
||||
"""Validate command line options and display error message if
|
||||
requirements are not met.
|
||||
|
||||
:param config: IConfig instance holding user configuration
|
||||
:type args: :class:`letsencrypt.interfaces.IConfig`
|
||||
|
||||
"""
|
||||
# Port check
|
||||
if config.http01_port == config.tls_sni_01_port:
|
||||
raise errors.ConfigurationError(
|
||||
"Trying to run http-01 and tls-sni-01 "
|
||||
"on the same port ({0})".format(config.tls_sni_01_port))
|
||||
|
||||
# Domain checks
|
||||
if config.namespace.domains is not None:
|
||||
_check_config_domain_sanity(config.namespace.domains)
|
||||
|
||||
|
||||
def _check_config_domain_sanity(domains):
|
||||
"""Helper method for check_config_sanity which validates
|
||||
domain flag values and errors out if the requirements are not met.
|
||||
|
||||
:param domains: List of domains
|
||||
:type domains: `list` of `string`
|
||||
:raises ConfigurationError: for invalid domains and cases where Let's
|
||||
Encrypt currently will not issue certificates
|
||||
|
||||
"""
|
||||
# Check if there's a wildcard domain
|
||||
if any(d.startswith("*.") for d in domains):
|
||||
raise errors.ConfigurationError(
|
||||
"Wildcard domains are not supported")
|
||||
# Punycode
|
||||
if any("xn--" in d for d in domains):
|
||||
raise errors.ConfigurationError(
|
||||
"Punycode domains are not supported")
|
||||
# FQDN checks from
|
||||
# http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/
|
||||
# Characters used, domain parts < 63 chars, tld > 1 < 7 chars
|
||||
# first and last char is not "-"
|
||||
fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}$")
|
||||
if any(True for d in domains if not fqdn.match(d)):
|
||||
raise errors.ConfigurationError("Requested domain is not a FQDN")
|
||||
|
|
|
|||
|
|
@ -94,3 +94,7 @@ class StandaloneBindError(Error):
|
|||
"Problem binding to port {0}: {1}".format(port, socket_error))
|
||||
self.socket_error = socket_error
|
||||
self.port = port
|
||||
|
||||
|
||||
class ConfigurationError(Error):
|
||||
"""Configuration sanity error."""
|
||||
|
|
|
|||
|
|
@ -175,6 +175,24 @@ class CLITest(unittest.TestCase):
|
|||
ret, _, _, _ = self._call(['-a', 'bad_auth', 'certonly'])
|
||||
self.assertEqual(ret, 'The requested bad_auth plugin does not appear to be installed')
|
||||
|
||||
def test_check_config_sanity_domain(self):
|
||||
# Punycode
|
||||
self.assertRaises(errors.ConfigurationError,
|
||||
self._call,
|
||||
['-d', 'this.is.xn--ls8h.tld'])
|
||||
# FQDN
|
||||
self.assertRaises(errors.ConfigurationError,
|
||||
self._call,
|
||||
['-d', 'comma,gotwrong.tld'])
|
||||
# FQDN 2
|
||||
self.assertRaises(errors.ConfigurationError,
|
||||
self._call,
|
||||
['-d', 'illegal.character=.tld'])
|
||||
# Wildcard
|
||||
self.assertRaises(errors.ConfigurationError,
|
||||
self._call,
|
||||
['-d', '*.wildcard.tld'])
|
||||
|
||||
@mock.patch('letsencrypt.crypto_util.notAfter')
|
||||
@mock.patch('letsencrypt.cli.zope.component.getUtility')
|
||||
def test_certonly_new_request_success(self, mock_get_utility, mock_notAfter):
|
||||
|
|
|
|||
|
|
@ -691,6 +691,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
self.test_rc.configfile["renewalparams"]["tls_sni_01_port"] = "4430"
|
||||
self.test_rc.configfile["renewalparams"]["http01_port"] = "1234"
|
||||
self.test_rc.configfile["renewalparams"]["account"] = "abcde"
|
||||
self.test_rc.configfile["renewalparams"]["domains"] = ["example.com"]
|
||||
mock_auth = mock.MagicMock()
|
||||
mock_pd.PluginsRegistry.find_all.return_value = {"apache": mock_auth}
|
||||
# Fails because "fake" != "apache"
|
||||
|
|
|
|||
Loading…
Reference in a new issue