mirror of
https://github.com/certbot/certbot.git
synced 2026-01-24 19:22:07 +03:00
@@ -378,13 +378,21 @@ def _report_new_cert(cert_path, fullchain_path):
|
||||
.format(and_chain, path, expiry))
|
||||
reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
|
||||
|
||||
def _suggest_donate():
|
||||
"Suggest a donation to support Let's Encrypt"
|
||||
|
||||
def _suggest_donation_if_appropriate(config):
|
||||
"""Potentially suggest a donation to support Let's Encrypt."""
|
||||
if not config.staging: # --dry-run implies --staging
|
||||
reporter_util = zope.component.getUtility(interfaces.IReporter)
|
||||
msg = ("If you like Let's Encrypt, please consider supporting our work by:\n\n"
|
||||
"Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n"
|
||||
"Donating to EFF: https://eff.org/donate-le\n\n")
|
||||
reporter_util.add_message(msg, reporter_util.LOW_PRIORITY)
|
||||
|
||||
|
||||
def _report_successful_dry_run():
|
||||
reporter_util = zope.component.getUtility(interfaces.IReporter)
|
||||
msg = ("If you like Let's Encrypt, please consider supporting our work by:\n\n"
|
||||
"Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n"
|
||||
"Donating to EFF: https://eff.org/donate-le\n\n")
|
||||
reporter_util.add_message(msg, reporter_util.LOW_PRIORITY)
|
||||
reporter_util.add_message("The dry run was successful.",
|
||||
reporter_util.HIGH_PRIORITY, on_crash=False)
|
||||
|
||||
|
||||
def _auth_from_domains(le_client, config, domains):
|
||||
@@ -397,6 +405,11 @@ def _auth_from_domains(le_client, config, domains):
|
||||
# (which results in treating the request as a new certificate request).
|
||||
|
||||
action, lineage = _treat_as_renewal(config, domains)
|
||||
if config.dry_run and action == "reinstall":
|
||||
logger.info(
|
||||
"Cert not due for renewal, but simulating renewal for dry run")
|
||||
action = "renew"
|
||||
|
||||
if action == "reinstall":
|
||||
# The lineage already exists; allow the caller to try installing
|
||||
# it without getting a new certificate at all.
|
||||
@@ -408,25 +421,31 @@ def _auth_from_domains(le_client, config, domains):
|
||||
# https://github.com/letsencrypt/letsencrypt/pull/777/files#r40498574
|
||||
new_certr, new_chain, new_key, _ = le_client.obtain_certificate(domains)
|
||||
# TODO: Check whether it worked! <- or make sure errors are thrown (jdk)
|
||||
lineage.save_successor(
|
||||
lineage.latest_common_version(), OpenSSL.crypto.dump_certificate(
|
||||
OpenSSL.crypto.FILETYPE_PEM, new_certr.body.wrapped),
|
||||
new_key.pem, crypto_util.dump_pyopenssl_chain(new_chain))
|
||||
if config.dry_run:
|
||||
logger.info("Dry run: skipping updating lineage at %s",
|
||||
os.path.dirname(lineage.cert))
|
||||
else:
|
||||
lineage.save_successor(
|
||||
lineage.latest_common_version(), OpenSSL.crypto.dump_certificate(
|
||||
OpenSSL.crypto.FILETYPE_PEM, new_certr.body.wrapped),
|
||||
new_key.pem, crypto_util.dump_pyopenssl_chain(new_chain))
|
||||
|
||||
lineage.update_all_links_to(lineage.latest_common_version())
|
||||
lineage.update_all_links_to(lineage.latest_common_version())
|
||||
# TODO: Check return value of save_successor
|
||||
# TODO: Also update lineage renewal config with any relevant
|
||||
# configuration values from this attempt? <- Absolutely (jdkasten)
|
||||
elif action == "newcert":
|
||||
# TREAT AS NEW REQUEST
|
||||
lineage = le_client.obtain_and_enroll_certificate(domains)
|
||||
if not lineage:
|
||||
if lineage is False:
|
||||
raise errors.Error("Certificate could not be obtained")
|
||||
|
||||
_report_new_cert(lineage.cert, lineage.fullchain)
|
||||
if not config.dry_run:
|
||||
_report_new_cert(lineage.cert, lineage.fullchain)
|
||||
|
||||
return lineage, action
|
||||
|
||||
|
||||
def _avoid_invalidating_lineage(config, lineage, original_server):
|
||||
"Do not renew a valid cert with one from a staging server!"
|
||||
def _is_staging(srv):
|
||||
@@ -612,7 +631,7 @@ def run(args, config, plugins): # pylint: disable=too-many-branches,too-many-lo
|
||||
else:
|
||||
display_ops.success_renewal(domains, action)
|
||||
|
||||
_suggest_donate()
|
||||
_suggest_donation_if_appropriate(config)
|
||||
|
||||
|
||||
def obtain_cert(args, config, plugins):
|
||||
@@ -636,14 +655,20 @@ def obtain_cert(args, config, plugins):
|
||||
if args.csr is not None:
|
||||
certr, chain = le_client.obtain_certificate_from_csr(le_util.CSR(
|
||||
file=args.csr[0], data=args.csr[1], form="der"))
|
||||
cert_path, _, cert_fullchain = le_client.save_certificate(
|
||||
certr, chain, args.cert_path, args.chain_path, args.fullchain_path)
|
||||
_report_new_cert(cert_path, cert_fullchain)
|
||||
if args.dry_run:
|
||||
logger.info(
|
||||
"Dry run: skipping saving certificate to %s", args.cert_path)
|
||||
else:
|
||||
cert_path, _, cert_fullchain = le_client.save_certificate(
|
||||
certr, chain, args.cert_path, args.chain_path, args.fullchain_path)
|
||||
_report_new_cert(cert_path, cert_fullchain)
|
||||
else:
|
||||
domains = _find_domains(config, installer)
|
||||
_auth_from_domains(le_client, config, domains)
|
||||
|
||||
_suggest_donate()
|
||||
if args.dry_run:
|
||||
_report_successful_dry_run()
|
||||
_suggest_donation_if_appropriate(config)
|
||||
|
||||
|
||||
def install(args, config, plugins):
|
||||
@@ -839,14 +864,23 @@ class HelpfulArgumentParser(object):
|
||||
if domain not in parsed_args.domains:
|
||||
parsed_args.domains.append(domain)
|
||||
|
||||
# argparse seemingly isn't flexible enough to give us this behaviour easily...
|
||||
if parsed_args.staging:
|
||||
if parsed_args.server not in (flag_default("server"), constants.STAGING_URI):
|
||||
raise errors.Error("--server value conflicts with --staging")
|
||||
if parsed_args.staging or parsed_args.dry_run:
|
||||
if (parsed_args.server not in
|
||||
(flag_default("server"), constants.STAGING_URI)):
|
||||
conflicts = ["--staging"] if parsed_args.staging else []
|
||||
conflicts += ["--dry-run"] if parsed_args.dry_run else []
|
||||
raise errors.Error("--server value conflicts with {0}".format(
|
||||
" and ".join(conflicts)))
|
||||
|
||||
parsed_args.server = constants.STAGING_URI
|
||||
|
||||
return parsed_args
|
||||
if parsed_args.dry_run:
|
||||
if self.verb != "certonly":
|
||||
raise errors.Error("--dry-run currently only works with the "
|
||||
"'certonly' subcommand")
|
||||
parsed_args.break_my_certs = parsed_args.staging = True
|
||||
|
||||
return parsed_args
|
||||
|
||||
def determine_verb(self):
|
||||
"""Determines the verb/subcommand provided by the user.
|
||||
@@ -1218,6 +1252,10 @@ def _paths_parser(helpful):
|
||||
add("testing", "--test-cert", "--staging", action='store_true', dest='staging',
|
||||
help='Use the staging server to obtain test (invalid) certs; equivalent'
|
||||
' to --server ' + constants.STAGING_URI)
|
||||
add("testing", "--dry-run", action="store_true", dest="dry_run",
|
||||
help="Perform a test run of the client, obtaining test (invalid) certs"
|
||||
" but not saving them to disk. This can currently only be used"
|
||||
" with the 'certonly' subcommand.")
|
||||
|
||||
|
||||
def _plugins_parsing(helpful, plugins):
|
||||
|
||||
@@ -276,8 +276,8 @@ class Client(object):
|
||||
:param plugins: A PluginsFactory object.
|
||||
|
||||
:returns: A new :class:`letsencrypt.storage.RenewableCert` instance
|
||||
referred to the enrolled cert lineage, or False if the cert could
|
||||
not be obtained.
|
||||
referred to the enrolled cert lineage, False if the cert could not
|
||||
be obtained, or None if doing a successful dry run.
|
||||
|
||||
"""
|
||||
certr, chain, key, _ = self.obtain_certificate(domains)
|
||||
@@ -298,12 +298,16 @@ class Client(object):
|
||||
"Non-standard path(s), might not work with crontab installed "
|
||||
"by your operating system package manager")
|
||||
|
||||
lineage = storage.RenewableCert.new_lineage(
|
||||
domains[0], OpenSSL.crypto.dump_certificate(
|
||||
OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped),
|
||||
key.pem, crypto_util.dump_pyopenssl_chain(chain),
|
||||
params, config, cli_config)
|
||||
return lineage
|
||||
if cli_config.dry_run:
|
||||
logger.info("Dry run: Skipping creating new lineage for %s",
|
||||
domains[0])
|
||||
return None
|
||||
else:
|
||||
return storage.RenewableCert.new_lineage(
|
||||
domains[0], OpenSSL.crypto.dump_certificate(
|
||||
OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped),
|
||||
key.pem, crypto_util.dump_pyopenssl_chain(chain),
|
||||
params, config, cli_config)
|
||||
|
||||
def save_certificate(self, certr, chain_cert,
|
||||
cert_path, chain_path, fullchain_path):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Tests for letsencrypt.cli."""
|
||||
import argparse
|
||||
import functools
|
||||
import itertools
|
||||
import os
|
||||
import shutil
|
||||
@@ -49,18 +50,16 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
|
||||
def _call(self, args):
|
||||
"Run the cli with output streams and actual client mocked out"
|
||||
with mock.patch('letsencrypt.cli._suggest_donate'):
|
||||
with mock.patch('letsencrypt.cli.client') as client:
|
||||
ret, stdout, stderr = self._call_no_clientmock(args)
|
||||
return ret, stdout, stderr, client
|
||||
with mock.patch('letsencrypt.cli.client') as client:
|
||||
ret, stdout, stderr = self._call_no_clientmock(args)
|
||||
return ret, stdout, stderr, client
|
||||
|
||||
def _call_no_clientmock(self, args):
|
||||
"Run the client with output streams mocked out"
|
||||
args = self.standard_args + args
|
||||
with mock.patch('letsencrypt.cli._suggest_donate'):
|
||||
with mock.patch('letsencrypt.cli.sys.stdout') as stdout:
|
||||
with mock.patch('letsencrypt.cli.sys.stderr') as stderr:
|
||||
ret = cli.main(args[:]) # NOTE: parser can alter its args!
|
||||
with mock.patch('letsencrypt.cli.sys.stdout') as stdout:
|
||||
with mock.patch('letsencrypt.cli.sys.stderr') as stderr:
|
||||
ret = cli.main(args[:]) # NOTE: parser can alter its args!
|
||||
return ret, stdout, stderr
|
||||
|
||||
def _call_stdout(self, args):
|
||||
@@ -69,10 +68,9 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
caller.
|
||||
"""
|
||||
args = self.standard_args + args
|
||||
with mock.patch('letsencrypt.cli._suggest_donate'):
|
||||
with mock.patch('letsencrypt.cli.sys.stderr') as stderr:
|
||||
with mock.patch('letsencrypt.cli.client') as client:
|
||||
ret = cli.main(args[:]) # NOTE: parser can alter its args!
|
||||
with mock.patch('letsencrypt.cli.sys.stderr') as stderr:
|
||||
with mock.patch('letsencrypt.cli.client') as client:
|
||||
ret = cli.main(args[:]) # NOTE: parser can alter its args!
|
||||
return ret, None, stderr, client
|
||||
|
||||
def test_no_flags(self):
|
||||
@@ -349,50 +347,91 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
self._call,
|
||||
['-d', '*.wildcard.tld'])
|
||||
|
||||
def test_parse_domains(self):
|
||||
def _get_argument_parser(self):
|
||||
plugins = disco.PluginsRegistry.find_all()
|
||||
return functools.partial(cli.prepare_and_parse_args, plugins)
|
||||
|
||||
def test_parse_domains(self):
|
||||
parse = self._get_argument_parser()
|
||||
|
||||
short_args = ['-d', 'example.com']
|
||||
namespace = cli.prepare_and_parse_args(plugins, short_args)
|
||||
namespace = parse(short_args)
|
||||
self.assertEqual(namespace.domains, ['example.com'])
|
||||
|
||||
short_args = ['-d', 'trailing.period.com.']
|
||||
namespace = cli.prepare_and_parse_args(plugins, short_args)
|
||||
namespace = parse(short_args)
|
||||
self.assertEqual(namespace.domains, ['trailing.period.com'])
|
||||
|
||||
short_args = ['-d', 'example.com,another.net,third.org,example.com']
|
||||
namespace = cli.prepare_and_parse_args(plugins, short_args)
|
||||
namespace = parse(short_args)
|
||||
self.assertEqual(namespace.domains, ['example.com', 'another.net',
|
||||
'third.org'])
|
||||
|
||||
long_args = ['--domains', 'example.com']
|
||||
namespace = cli.prepare_and_parse_args(plugins, long_args)
|
||||
namespace = parse(long_args)
|
||||
self.assertEqual(namespace.domains, ['example.com'])
|
||||
|
||||
long_args = ['--domains', 'trailing.period.com.']
|
||||
namespace = cli.prepare_and_parse_args(plugins, long_args)
|
||||
namespace = parse(long_args)
|
||||
self.assertEqual(namespace.domains, ['trailing.period.com'])
|
||||
|
||||
long_args = ['--domains', 'example.com,another.net,example.com']
|
||||
namespace = cli.prepare_and_parse_args(plugins, long_args)
|
||||
namespace = parse(long_args)
|
||||
self.assertEqual(namespace.domains, ['example.com', 'another.net'])
|
||||
|
||||
def test_parse_server(self):
|
||||
plugins = disco.PluginsRegistry.find_all()
|
||||
short_args = ['--server', 'example.com']
|
||||
namespace = cli.prepare_and_parse_args(plugins, short_args)
|
||||
def test_server_flag(self):
|
||||
parse = self._get_argument_parser()
|
||||
namespace = parse('--server example.com'.split())
|
||||
self.assertEqual(namespace.server, 'example.com')
|
||||
|
||||
def _check_server_conflict_message(self, parser_args, conflicting_args):
|
||||
parse = self._get_argument_parser()
|
||||
try:
|
||||
parse(parser_args)
|
||||
self.fail( # pragma: no cover
|
||||
"The following flags didn't conflict with "
|
||||
'--server: {0}'.format(', '.join(conflicting_args)))
|
||||
except errors.Error as error:
|
||||
self.assertTrue('--server' in error.message)
|
||||
for arg in conflicting_args:
|
||||
self.assertTrue(arg in error.message)
|
||||
|
||||
def test_staging_flag(self):
|
||||
parse = self._get_argument_parser()
|
||||
short_args = ['--staging']
|
||||
namespace = cli.prepare_and_parse_args(plugins, short_args)
|
||||
namespace = parse(short_args)
|
||||
self.assertTrue(namespace.staging)
|
||||
self.assertEqual(namespace.server, constants.STAGING_URI)
|
||||
|
||||
short_args = ['--staging', '--server', 'example.com']
|
||||
self.assertRaises(errors.Error, cli.prepare_and_parse_args, plugins, short_args)
|
||||
short_args += '--server example.com'.split()
|
||||
self._check_server_conflict_message(short_args, '--staging')
|
||||
|
||||
def _assert_dry_run_flag_worked(self, namespace):
|
||||
self.assertTrue(namespace.dry_run)
|
||||
self.assertTrue(namespace.break_my_certs)
|
||||
self.assertTrue(namespace.staging)
|
||||
self.assertEqual(namespace.server, constants.STAGING_URI)
|
||||
|
||||
def test_dry_run_flag(self):
|
||||
parse = self._get_argument_parser()
|
||||
short_args = ['--dry-run']
|
||||
self.assertRaises(errors.Error, parse, short_args)
|
||||
|
||||
self._assert_dry_run_flag_worked(parse(short_args + ['auth']))
|
||||
short_args += ['certonly']
|
||||
self._assert_dry_run_flag_worked(parse(short_args))
|
||||
|
||||
short_args += '--server example.com'.split()
|
||||
conflicts = ['--dry-run']
|
||||
self._check_server_conflict_message(short_args, '--dry-run')
|
||||
|
||||
short_args += ['--staging']
|
||||
conflicts += ['--staging']
|
||||
self._check_server_conflict_message(short_args, conflicts)
|
||||
|
||||
def _webroot_map_test(self, map_arg, path_arg, domains_arg, # pylint: disable=too-many-arguments
|
||||
expected_map, expectect_domains, extra_args=None):
|
||||
plugins = disco.PluginsRegistry.find_all()
|
||||
parse = self._get_argument_parser()
|
||||
webroot_map_args = extra_args if extra_args else []
|
||||
if map_arg:
|
||||
webroot_map_args.extend(["--webroot-map", map_arg])
|
||||
@@ -400,17 +439,17 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
webroot_map_args.extend(["-w", path_arg])
|
||||
if domains_arg:
|
||||
webroot_map_args.extend(["-d", domains_arg])
|
||||
namespace = cli.prepare_and_parse_args(plugins, webroot_map_args)
|
||||
namespace = parse(webroot_map_args)
|
||||
domains = cli._find_domains(namespace, mock.MagicMock()) # pylint: disable=protected-access
|
||||
self.assertEqual(namespace.webroot_map, expected_map)
|
||||
self.assertEqual(set(domains), set(expectect_domains))
|
||||
|
||||
def test_parse_webroot(self):
|
||||
plugins = disco.PluginsRegistry.find_all()
|
||||
parse = self._get_argument_parser()
|
||||
webroot_args = ['--webroot', '-w', '/var/www/example',
|
||||
'-d', 'example.com,www.example.com', '-w', '/var/www/superfluous',
|
||||
'-d', 'superfluo.us', '-d', 'www.superfluo.us.']
|
||||
namespace = cli.prepare_and_parse_args(plugins, webroot_args)
|
||||
'-d', 'superfluo.us', '-d', 'www.superfluo.us']
|
||||
namespace = parse(webroot_args)
|
||||
self.assertEqual(namespace.webroot_map, {
|
||||
'example.com': '/var/www/example',
|
||||
'www.example.com': '/var/www/example',
|
||||
@@ -418,7 +457,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
'superfluo.us': '/var/www/superfluous'})
|
||||
|
||||
webroot_args = ['-d', 'stray.example.com'] + webroot_args
|
||||
self.assertRaises(errors.Error, cli.prepare_and_parse_args, plugins, webroot_args)
|
||||
self.assertRaises(errors.Error, parse, webroot_args)
|
||||
|
||||
simple_map = '{"eg.com" : "/tmp"}'
|
||||
expected_map = {"eg.com": "/tmp"}
|
||||
@@ -440,14 +479,35 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
|
||||
webroot_map_args = ['--webroot-map',
|
||||
'{"eg.com.,www.eg.com": "/tmp", "eg.is.": "/tmp2"}']
|
||||
namespace = cli.prepare_and_parse_args(plugins, webroot_map_args)
|
||||
namespace = parse(webroot_map_args)
|
||||
self.assertEqual(namespace.webroot_map,
|
||||
{"eg.com": "/tmp", "www.eg.com": "/tmp", "eg.is": "/tmp2"})
|
||||
|
||||
@mock.patch('letsencrypt.cli._suggest_donate')
|
||||
def _certonly_new_request_common(self, mock_client, args=None):
|
||||
with mock.patch('letsencrypt.cli._treat_as_renewal') as mock_renewal:
|
||||
mock_renewal.return_value = ("newcert", None)
|
||||
with mock.patch('letsencrypt.cli._init_le_client') as mock_init:
|
||||
mock_init.return_value = mock_client
|
||||
if args is None:
|
||||
args = []
|
||||
args += '-d foo.bar -a standalone certonly'.split()
|
||||
self._call(args)
|
||||
|
||||
@mock.patch('letsencrypt.cli.zope.component.getUtility')
|
||||
def test_certonly_dry_run_new_request_success(self, mock_get_utility):
|
||||
mock_client = mock.MagicMock()
|
||||
mock_client.obtain_and_enroll_certificate.return_value = None
|
||||
self._certonly_new_request_common(mock_client, ['--dry-run'])
|
||||
self.assertEqual(
|
||||
mock_client.obtain_and_enroll_certificate.call_count, 1)
|
||||
self.assertTrue(
|
||||
'dry run' in mock_get_utility().add_message.call_args[0][0])
|
||||
# Asserts we don't suggest donating after a successful dry run
|
||||
self.assertEqual(mock_get_utility().add_message.call_count, 1)
|
||||
|
||||
@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, _suggest):
|
||||
def test_certonly_new_request_success(self, mock_get_utility, mock_notAfter):
|
||||
cert_path = '/etc/letsencrypt/live/foo.bar'
|
||||
date = '1970-01-01'
|
||||
mock_notAfter().date.return_value = date
|
||||
@@ -458,10 +518,11 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
self._certonly_new_request_common(mock_client)
|
||||
self.assertEqual(
|
||||
mock_client.obtain_and_enroll_certificate.call_count, 1)
|
||||
cert_msg = mock_get_utility().add_message.call_args_list[0][0][0]
|
||||
self.assertTrue(cert_path in cert_msg)
|
||||
self.assertTrue(date in cert_msg)
|
||||
self.assertTrue(
|
||||
cert_path in mock_get_utility().add_message.call_args[0][0])
|
||||
self.assertTrue(
|
||||
date in mock_get_utility().add_message.call_args[0][0])
|
||||
'donate' in mock_get_utility().add_message.call_args[0][0])
|
||||
|
||||
def test_certonly_new_request_failure(self):
|
||||
mock_client = mock.MagicMock()
|
||||
@@ -469,69 +530,101 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
||||
self.assertRaises(errors.Error,
|
||||
self._certonly_new_request_common, mock_client)
|
||||
|
||||
def _certonly_new_request_common(self, mock_client):
|
||||
with mock.patch('letsencrypt.cli._treat_as_renewal') as mock_renewal:
|
||||
mock_renewal.return_value = ("newcert", None)
|
||||
with mock.patch('letsencrypt.cli._init_le_client') as mock_init:
|
||||
mock_init.return_value = mock_client
|
||||
self._call(['-d', 'foo.bar', '-a', 'standalone', 'certonly'])
|
||||
|
||||
@mock.patch('letsencrypt.cli._suggest_donate')
|
||||
@mock.patch('letsencrypt.cli.zope.component.getUtility')
|
||||
@mock.patch('letsencrypt.cli._treat_as_renewal')
|
||||
@mock.patch('letsencrypt.cli._init_le_client')
|
||||
def test_certonly_renewal(self, mock_init, mock_renewal, mock_get_utility, _suggest):
|
||||
def _test_certonly_renewal_common(self, renewal_verb, extra_args=None):
|
||||
cert_path = 'letsencrypt/tests/testdata/cert.pem'
|
||||
chain_path = '/etc/letsencrypt/live/foo.bar/fullchain.pem'
|
||||
|
||||
mock_lineage = mock.MagicMock(cert=cert_path, fullchain=chain_path)
|
||||
mock_certr = mock.MagicMock()
|
||||
mock_key = mock.MagicMock(pem='pem_key')
|
||||
mock_renewal.return_value = ("renew", mock_lineage)
|
||||
mock_client = mock.MagicMock()
|
||||
mock_client.obtain_certificate.return_value = (mock_certr, 'chain',
|
||||
mock_key, 'csr')
|
||||
mock_init.return_value = mock_client
|
||||
with mock.patch('letsencrypt.cli.OpenSSL'):
|
||||
with mock.patch('letsencrypt.cli.crypto_util'):
|
||||
self._call(['-d', 'foo.bar', '-a', 'standalone', 'certonly'])
|
||||
with mock.patch('letsencrypt.cli._treat_as_renewal') as mock_renewal:
|
||||
mock_renewal.return_value = (renewal_verb, mock_lineage)
|
||||
mock_client = mock.MagicMock()
|
||||
mock_client.obtain_certificate.return_value = (mock_certr, 'chain',
|
||||
mock_key, 'csr')
|
||||
with mock.patch('letsencrypt.cli._init_le_client') as mock_init:
|
||||
mock_init.return_value = mock_client
|
||||
get_utility_path = 'letsencrypt.cli.zope.component.getUtility'
|
||||
with mock.patch(get_utility_path) as mock_get_utility:
|
||||
with mock.patch('letsencrypt.cli.OpenSSL'):
|
||||
with mock.patch('letsencrypt.cli.crypto_util'):
|
||||
args = ['-d', 'foo.bar', '-a',
|
||||
'standalone', 'certonly']
|
||||
if extra_args:
|
||||
args += extra_args
|
||||
self._call(args)
|
||||
|
||||
mock_client.obtain_certificate.assert_called_once_with(['foo.bar'])
|
||||
self.assertEqual(mock_lineage.save_successor.call_count, 1)
|
||||
mock_lineage.update_all_links_to.assert_called_once_with(
|
||||
mock_lineage.latest_common_version())
|
||||
self.assertTrue(
|
||||
chain_path in mock_get_utility().add_message.call_args[0][0])
|
||||
|
||||
@mock.patch('letsencrypt.cli._suggest_donate')
|
||||
@mock.patch('letsencrypt.crypto_util.notAfter')
|
||||
@mock.patch('letsencrypt.cli.display_ops.pick_installer')
|
||||
return mock_lineage, mock_get_utility
|
||||
|
||||
def test_certonly_renewal(self):
|
||||
lineage, get_utility = self._test_certonly_renewal_common('renew')
|
||||
self.assertEqual(lineage.save_successor.call_count, 1)
|
||||
lineage.update_all_links_to.assert_called_once_with(
|
||||
lineage.latest_common_version())
|
||||
cert_msg = get_utility().add_message.call_args_list[0][0][0]
|
||||
self.assertTrue('fullchain.pem' in cert_msg)
|
||||
self.assertTrue('donate' in get_utility().add_message.call_args[0][0])
|
||||
|
||||
def test_certonly_dry_run_reinstall_is_renewal(self):
|
||||
_, get_utility = self._test_certonly_renewal_common('reinstall',
|
||||
['--dry-run'])
|
||||
self.assertEqual(get_utility().add_message.call_count, 1)
|
||||
self.assertTrue('dry run' in get_utility().add_message.call_args[0][0])
|
||||
|
||||
@mock.patch('letsencrypt.cli.zope.component.getUtility')
|
||||
@mock.patch('letsencrypt.cli._treat_as_renewal')
|
||||
@mock.patch('letsencrypt.cli._init_le_client')
|
||||
@mock.patch('letsencrypt.cli.record_chosen_plugins')
|
||||
def test_certonly_csr(self, _rec, mock_init, mock_get_utility,
|
||||
mock_pick_installer, mock_notAfter, _suggest):
|
||||
cert_path = '/etc/letsencrypt/live/blahcert.pem'
|
||||
date = '1970-01-01'
|
||||
mock_notAfter().date.return_value = date
|
||||
def test_certonly_reinstall(self, mock_init, mock_renewal, mock_get_utility):
|
||||
mock_renewal.return_value = ('reinstall', mock.MagicMock())
|
||||
mock_init.return_value = mock_client = mock.MagicMock()
|
||||
self._call(['-d', 'foo.bar', '-a', 'standalone', 'certonly'])
|
||||
self.assertFalse(mock_client.obtain_certificate.called)
|
||||
self.assertFalse(mock_client.obtain_and_enroll_certificate.called)
|
||||
self.assertTrue(
|
||||
'donate' in mock_get_utility().add_message.call_args[0][0])
|
||||
|
||||
def _test_certonly_csr_common(self, extra_args=None):
|
||||
certr = 'certr'
|
||||
chain = 'chain'
|
||||
mock_client = mock.MagicMock()
|
||||
mock_client.obtain_certificate_from_csr.return_value = ('certr',
|
||||
'chain')
|
||||
mock_client.obtain_certificate_from_csr.return_value = (certr, chain)
|
||||
cert_path = '/etc/letsencrypt/live/example.com/cert.pem'
|
||||
mock_client.save_certificate.return_value = cert_path, None, None
|
||||
mock_init.return_value = mock_client
|
||||
with mock.patch('letsencrypt.cli._init_le_client') as mock_init:
|
||||
mock_init.return_value = mock_client
|
||||
get_utility_path = 'letsencrypt.cli.zope.component.getUtility'
|
||||
with mock.patch(get_utility_path) as mock_get_utility:
|
||||
chain_path = '/etc/letsencrypt/live/example.com/chain.pem'
|
||||
full_path = '/etc/letsencrypt/live/example.com/fullchain.pem'
|
||||
args = ('-a standalone certonly --csr {0} --cert-path {1} '
|
||||
'--chain-path {2} --fullchain-path {3}').format(
|
||||
CSR, cert_path, chain_path, full_path).split()
|
||||
if extra_args:
|
||||
args += extra_args
|
||||
with mock.patch('letsencrypt.cli.crypto_util'):
|
||||
self._call(args)
|
||||
|
||||
installer = 'installer'
|
||||
self._call(
|
||||
['-a', 'standalone', '-i', installer, 'certonly', '--csr', CSR,
|
||||
'--cert-path', cert_path, '--fullchain-path', '/',
|
||||
'--chain-path', '/'])
|
||||
self.assertEqual(mock_pick_installer.call_args[0][1], installer)
|
||||
mock_client.save_certificate.assert_called_once_with(
|
||||
'certr', 'chain', cert_path, '/', '/')
|
||||
if '--dry-run' in args:
|
||||
self.assertFalse(mock_client.save_certificate.called)
|
||||
else:
|
||||
mock_client.save_certificate.assert_called_once_with(
|
||||
certr, chain, cert_path, chain_path, full_path)
|
||||
|
||||
return mock_get_utility
|
||||
|
||||
def test_certonly_csr(self):
|
||||
mock_get_utility = self._test_certonly_csr_common()
|
||||
cert_msg = mock_get_utility().add_message.call_args_list[0][0][0]
|
||||
self.assertTrue('cert.pem' in cert_msg)
|
||||
self.assertTrue(
|
||||
cert_path in mock_get_utility().add_message.call_args[0][0])
|
||||
'donate' in mock_get_utility().add_message.call_args[0][0])
|
||||
|
||||
def test_certonly_csr_dry_run(self):
|
||||
mock_get_utility = self._test_certonly_csr_common(['--dry-run'])
|
||||
self.assertEqual(mock_get_utility().add_message.call_count, 1)
|
||||
self.assertTrue(
|
||||
date in mock_get_utility().add_message.call_args[0][0])
|
||||
'dry run' in mock_get_utility().add_message.call_args[0][0])
|
||||
|
||||
@mock.patch('letsencrypt.cli.client.acme_client')
|
||||
def test_revoke_with_key(self, mock_acme_client):
|
||||
|
||||
Reference in New Issue
Block a user