Compare commits

..

1 Commits

Author SHA1 Message Date
Joona Hoikkala
fe49734b67 Fix comparison to check values 2018-03-31 19:26:36 +03:00
80 changed files with 260 additions and 1273 deletions

1
.gitignore vendored
View File

@@ -38,7 +38,6 @@ tests/letstest/venv/
# pytest cache
.cache
.mypy_cache/
# docker files
.docker

View File

@@ -29,8 +29,6 @@ matrix:
addons:
- python: "2.7"
env: TOXENV=lint
- python: "3.5"
env: TOXENV=mypy
- python: "2.7"
env: TOXENV='py27-{acme,apache,certbot,dns,nginx}-oldest'
sudo: required

View File

@@ -2,49 +2,6 @@
Certbot adheres to [Semantic Versioning](http://semver.org/).
## 0.23.0 - 2018-04-04
### Added
* Support for OpenResty was added to the Nginx plugin.
### Changed
* The timestamps in Certbot's logfiles now use the system's local time zone
rather than UTC.
* Certbot's DNS plugins that use Lexicon now rely on Lexicon>=2.2.1 to be able
to create and delete multiple TXT records on a single domain.
* certbot-dns-google's test suite now works without an internet connection.
### Fixed
* Removed a small window that if during which an error occurred, Certbot
wouldn't clean up performed challenges.
* The parameters `default` and `ipv6only` are now removed from `listen`
directives when creating a new server block in the Nginx plugin.
* `server_name` directives enclosed in quotation marks in Nginx are now properly
supported.
* Resolved an issue preventing the Apache plugin from starting Apache when it's
not currently running on RHEL and Gentoo based systems.
Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
packages with changes other than their version number were:
* certbot
* certbot-apache
* certbot-dns-cloudxns
* certbot-dns-dnsimple
* certbot-dns-dnsmadeeasy
* certbot-dns-google
* certbot-dns-luadns
* certbot-dns-nsone
* certbot-dns-rfc2136
* certbot-nginx
More details about these changes can be found on our GitHub repo:
https://github.com/certbot/certbot/milestone/50?closed=1
## 0.22.2 - 2018-03-19
### Fixed

View File

@@ -1,4 +1,4 @@
FROM python:2-alpine3.7
FROM python:2-alpine
ENTRYPOINT [ "certbot" ]
EXPOSE 80 443

View File

@@ -435,7 +435,6 @@ class Authorization(ResourceBody):
# be absent'... then acme-spec gives example with 'expires'
# present... That's confusing!
expires = fields.RFC3339Field('expires', omitempty=True)
wildcard = jose.Field('wildcard', omitempty=True)
@challenges.decoder
def challenges(value): # pylint: disable=missing-docstring,no-self-argument

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [

View File

@@ -323,7 +323,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Returned objects are guaranteed to be ssl vhosts
return self._choose_vhosts_wildcard(domain, create_if_no_ssl)
else:
return [self.choose_vhost(domain, create_if_no_ssl)]
return [self.choose_vhost(domain)]
def _vhosts_for_wildcard(self, domain):
"""
@@ -475,21 +475,20 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
if chain_path is not None:
self.save_notes += "\tSSLCertificateChainFile %s\n" % chain_path
def choose_vhost(self, target_name, create_if_no_ssl=True):
def choose_vhost(self, target_name, temp=False):
"""Chooses a virtual host based on the given domain name.
If there is no clear virtual host to be selected, the user is prompted
with all available choices.
The returned vhost is guaranteed to have TLS enabled unless
create_if_no_ssl is set to False, in which case there is no such guarantee
and the result is not cached.
The returned vhost is guaranteed to have TLS enabled unless temp is
True. If temp is True, there is no such guarantee and the result is
not cached.
:param str target_name: domain name
:param bool create_if_no_ssl: If found VirtualHost doesn't have a HTTPS
counterpart, should one get created
:param bool temp: whether the vhost is only used temporarily
:returns: vhost associated with name
:returns: ssl vhost associated with name
:rtype: :class:`~certbot_apache.obj.VirtualHost`
:raises .errors.PluginError: If no vhost is available or chosen
@@ -502,7 +501,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Try to find a reasonable vhost
vhost = self._find_best_vhost(target_name)
if vhost is not None:
if not create_if_no_ssl:
if temp:
return vhost
if not vhost.ssl:
vhost = self.make_vhost_ssl(vhost)
@@ -511,9 +510,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.assoc[target_name] = vhost
return vhost
# Negate create_if_no_ssl value to indicate if we want a SSL vhost
# to get created if a non-ssl vhost is selected.
return self._choose_vhost_from_list(target_name, temp=not create_if_no_ssl)
return self._choose_vhost_from_list(target_name, temp)
def _choose_vhost_from_list(self, target_name, temp=False):
# Select a vhost from a list
@@ -1508,20 +1505,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
raise errors.PluginError(
"Unsupported enhancement: {0}".format(enhancement))
matched_vhosts = self.choose_vhosts(domain, create_if_no_ssl=False)
# We should be handling only SSL vhosts for enhancements
vhosts = [vhost for vhost in matched_vhosts if vhost.ssl]
if not vhosts:
msg_tmpl = ("Certbot was not able to find SSL VirtualHost for a "
"domain {0} for enabling enhancement \"{1}\". The requested "
"enhancement was not configured.")
msg_enhancement = enhancement
if options:
msg_enhancement += ": " + options
msg = msg_tmpl.format(domain, msg_enhancement)
logger.warning(msg)
raise errors.PluginError(msg)
vhosts = self.choose_vhosts(domain, create_if_no_ssl=False)
try:
for vhost in vhosts:
func(vhost, options)
@@ -2016,27 +2000,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:raises .errors.MisconfigurationError: If reload fails
"""
error = ""
try:
util.run_script(self.constant("restart_cmd"))
except errors.SubprocessError as err:
logger.info("Unable to restart apache using %s",
self.constant("restart_cmd"))
alt_restart = self.constant("restart_cmd_alt")
if alt_restart:
logger.debug("Trying alternative restart command: %s",
alt_restart)
# There is an alternative restart command available
# This usually is "restart" verb while original is "graceful"
try:
util.run_script(self.constant(
"restart_cmd_alt"))
return
except errors.SubprocessError as secerr:
error = str(secerr)
else:
error = str(err)
raise errors.MisconfigurationError(error)
raise errors.MisconfigurationError(str(err))
def config_test(self): # pylint: disable=no-self-use
"""Check the configuration of Apache for errors.

View File

@@ -21,7 +21,6 @@ class CentOSConfigurator(configurator.ApacheConfigurator):
version_cmd=['apachectl', '-v'],
apache_cmd="apachectl",
restart_cmd=['apachectl', 'graceful'],
restart_cmd_alt=['apachectl', 'restart'],
conftest_cmd=['apachectl', 'configtest'],
enmod=None,
dismod=None,

View File

@@ -21,7 +21,6 @@ class GentooConfigurator(configurator.ApacheConfigurator):
version_cmd=['/usr/sbin/apache2', '-v'],
apache_cmd="apache2ctl",
restart_cmd=['apache2ctl', 'graceful'],
restart_cmd_alt=['apache2ctl', 'restart'],
conftest_cmd=['apache2ctl', 'configtest'],
enmod=None,
dismod=None,

View File

@@ -4,8 +4,6 @@ import unittest
import mock
from certbot import errors
from certbot_apache import obj
from certbot_apache import override_centos
from certbot_apache.tests import util
@@ -123,17 +121,5 @@ class MultipleVhostsTestCentOS(util.ApacheTest):
self.assertTrue("MOCK_NOSEP" in self.config.parser.variables.keys())
self.assertEqual("NOSEP_VAL", self.config.parser.variables["NOSEP_TWO"])
@mock.patch("certbot_apache.configurator.util.run_script")
def test_alt_restart_works(self, mock_run_script):
mock_run_script.side_effect = [None, errors.SubprocessError, None]
self.config.restart()
self.assertEquals(mock_run_script.call_count, 3)
@mock.patch("certbot_apache.configurator.util.run_script")
def test_alt_restart_errors(self, mock_run_script):
mock_run_script.side_effect = [None,
errors.SubprocessError,
errors.SubprocessError]
self.assertRaises(errors.MisconfigurationError, self.config.restart)
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -246,7 +246,7 @@ class MultipleVhostsTest(util.ApacheTest):
@mock.patch("certbot_apache.display_ops.select_vhost")
def test_choose_vhost_select_vhost_with_temp(self, mock_select):
mock_select.return_value = self.vh_truth[0]
chosen_vhost = self.config.choose_vhost("none.com", create_if_no_ssl=False)
chosen_vhost = self.config.choose_vhost("none.com", temp=True)
self.assertEqual(self.vh_truth[0], chosen_vhost)
@mock.patch("certbot_apache.display_ops.select_vhost")
@@ -936,22 +936,6 @@ class MultipleVhostsTest(util.ApacheTest):
errors.PluginError,
self.config.enhance, "certbot.demo", "unknown_enhancement")
def test_enhance_no_ssl_vhost(self):
with mock.patch("certbot_apache.configurator.logger.warning") as mock_log:
self.assertRaises(errors.PluginError, self.config.enhance,
"certbot.demo", "redirect")
# Check that correct logger.warning was printed
self.assertTrue("not able to find" in mock_log.call_args[0][0])
self.assertTrue("\"redirect\"" in mock_log.call_args[0][0])
mock_log.reset_mock()
self.assertRaises(errors.PluginError, self.config.enhance,
"certbot.demo", "ensure-http-header", "Test")
# Check that correct logger.warning was printed
self.assertTrue("not able to find" in mock_log.call_args[0][0])
self.assertTrue("Test" in mock_log.call_args[0][0])
@mock.patch("certbot.util.exe_exists")
def test_ocsp_stapling(self, mock_exe):
self.config.parser.update_runtime_variables = mock.Mock()
@@ -961,7 +945,6 @@ class MultipleVhostsTest(util.ApacheTest):
mock_exe.return_value = True
# This will create an ssl vhost for certbot.demo
self.config.choose_vhost("certbot.demo")
self.config.enhance("certbot.demo", "staple-ocsp")
# Get the ssl vhost for certbot.demo
@@ -988,7 +971,6 @@ class MultipleVhostsTest(util.ApacheTest):
mock_exe.return_value = True
# Checking the case with already enabled ocsp stapling configuration
self.config.choose_vhost("ocspvhost.com")
self.config.enhance("ocspvhost.com", "staple-ocsp")
# Get the ssl vhost for letsencrypt.demo
@@ -1013,7 +995,6 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.parser.modules.add("mod_ssl.c")
self.config.parser.modules.add("socache_shmcb_module")
self.config.get_version = mock.Mock(return_value=(2, 2, 0))
self.config.choose_vhost("certbot.demo")
self.assertRaises(errors.PluginError,
self.config.enhance, "certbot.demo", "staple-ocsp")
@@ -1039,7 +1020,6 @@ class MultipleVhostsTest(util.ApacheTest):
mock_exe.return_value = True
# This will create an ssl vhost for certbot.demo
self.config.choose_vhost("certbot.demo")
self.config.enhance("certbot.demo", "ensure-http-header",
"Strict-Transport-Security")
@@ -1059,8 +1039,7 @@ class MultipleVhostsTest(util.ApacheTest):
# skip the enable mod
self.config.parser.modules.add("headers_module")
# This will create an ssl vhost for encryption-example.demo
self.config.choose_vhost("encryption-example.demo")
# This will create an ssl vhost for certbot.demo
self.config.enhance("encryption-example.demo", "ensure-http-header",
"Strict-Transport-Security")
@@ -1079,7 +1058,6 @@ class MultipleVhostsTest(util.ApacheTest):
mock_exe.return_value = True
# This will create an ssl vhost for certbot.demo
self.config.choose_vhost("certbot.demo")
self.config.enhance("certbot.demo", "ensure-http-header",
"Upgrade-Insecure-Requests")
@@ -1101,8 +1079,7 @@ class MultipleVhostsTest(util.ApacheTest):
# skip the enable mod
self.config.parser.modules.add("headers_module")
# This will create an ssl vhost for encryption-example.demo
self.config.choose_vhost("encryption-example.demo")
# This will create an ssl vhost for certbot.demo
self.config.enhance("encryption-example.demo", "ensure-http-header",
"Upgrade-Insecure-Requests")
@@ -1120,7 +1097,6 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.get_version = mock.Mock(return_value=(2, 2))
# This will create an ssl vhost for certbot.demo
self.config.choose_vhost("certbot.demo")
self.config.enhance("certbot.demo", "redirect")
# These are not immediately available in find_dir even with save() and
@@ -1171,7 +1147,6 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.save()
# This will create an ssl vhost for certbot.demo
self.config.choose_vhost("certbot.demo")
self.config.enhance("certbot.demo", "redirect")
# These are not immediately available in find_dir even with save() and
@@ -1238,9 +1213,6 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.parser.modules.add("rewrite_module")
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
# Creates ssl vhost for the domain
self.config.choose_vhost("red.blue.purple.com")
self.config.enhance("red.blue.purple.com", "redirect")
verify_no_redirect = ("certbot_apache.configurator."
"ApacheConfigurator._verify_no_certbot_redirect")
@@ -1252,7 +1224,7 @@ class MultipleVhostsTest(util.ApacheTest):
# Skip the enable mod
self.config.parser.modules.add("rewrite_module")
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
self.config.choose_vhost("red.blue.purple.com")
self.config.enhance("red.blue.purple.com", "redirect")
# Clear state about enabling redirect on this run
# pylint: disable=protected-access
@@ -1474,7 +1446,6 @@ class MultipleVhostsTest(util.ApacheTest):
# pylint: disable=protected-access
self.config.parser.modules.add("mod_ssl.c")
self.config.parser.modules.add("headers_module")
self.vh_truth[3].ssl = True
self.config._wildcard_vhosts["*.certbot.demo"] = [self.vh_truth[3]]
self.config.enhance("*.certbot.demo", "ensure-http-header",
"Upgrade-Insecure-Requests")
@@ -1482,7 +1453,6 @@ class MultipleVhostsTest(util.ApacheTest):
@mock.patch("certbot_apache.configurator.ApacheConfigurator._choose_vhosts_wildcard")
def test_enhance_wildcard_no_install(self, mock_choose):
self.vh_truth[3].ssl = True
mock_choose.return_value = [self.vh_truth[3]]
self.config.parser.modules.add("mod_ssl.c")
self.config.parser.modules.add("headers_module")

View File

@@ -161,8 +161,6 @@ class MultipleVhostsTestDebian(util.ApacheTest):
self.config.parser.modules.add("mod_ssl.c")
self.config.get_version = mock.Mock(return_value=(2, 4, 7))
mock_exe.return_value = True
# This will create an ssl vhost for certbot.demo
self.config.choose_vhost("certbot.demo")
self.config.enhance("certbot.demo", "staple-ocsp")
self.assertTrue("socache_shmcb_module" in self.config.parser.modules)
@@ -174,7 +172,6 @@ class MultipleVhostsTestDebian(util.ApacheTest):
mock_exe.return_value = True
# This will create an ssl vhost for certbot.demo
self.config.choose_vhost("certbot.demo")
self.config.enhance("certbot.demo", "ensure-http-header",
"Strict-Transport-Security")
self.assertTrue("headers_module" in self.config.parser.modules)
@@ -186,7 +183,6 @@ class MultipleVhostsTestDebian(util.ApacheTest):
mock_exe.return_value = True
self.config.get_version = mock.Mock(return_value=(2, 2))
# This will create an ssl vhost for certbot.demo
self.config.choose_vhost("certbot.demo")
self.config.enhance("certbot.demo", "redirect")
self.assertTrue("rewrite_module" in self.config.parser.modules)

View File

@@ -4,8 +4,6 @@ import unittest
import mock
from certbot import errors
from certbot_apache import override_gentoo
from certbot_apache import obj
from certbot_apache.tests import util
@@ -125,11 +123,5 @@ class MultipleVhostsTestGentoo(util.ApacheTest):
self.assertEquals(len(self.config.parser.modules), 4)
self.assertTrue("mod_another.c" in self.config.parser.modules)
@mock.patch("certbot_apache.configurator.util.run_script")
def test_alt_restart_works(self, mock_run_script):
mock_run_script.side_effect = [None, errors.SubprocessError, None]
self.config.restart()
self.assertEquals(mock_run_script.call_count, 3)
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -16,9 +16,30 @@ from certbot_apache.tests import util
NUM_ACHALLS = 3
class ApacheHttp01TestMeta(type):
"""Generates parmeterized tests for testing perform."""
def __new__(mcs, name, bases, class_dict):
def _gen_test(num_achalls, minor_version):
def _test(self):
achalls = self.achalls[:num_achalls]
vhosts = self.vhosts[:num_achalls]
self.config.version = (2, minor_version)
self.common_perform_test(achalls, vhosts)
return _test
for i in range(1, NUM_ACHALLS + 1):
for j in (2, 4):
test_name = "test_perform_{0}_{1}".format(i, j)
class_dict[test_name] = _gen_test(i, j)
return type.__new__(mcs, name, bases, class_dict)
class ApacheHttp01Test(util.ApacheTest):
"""Test for certbot_apache.http_01.ApacheHttp01."""
__metaclass__ = ApacheHttp01TestMeta
def setUp(self, *args, **kwargs):
super(ApacheHttp01Test, self).setUp(*args, **kwargs)
@@ -50,7 +71,7 @@ class ApacheHttp01Test(util.ApacheTest):
self.assertFalse(self.http.perform())
@mock.patch("certbot_apache.configurator.ApacheConfigurator.enable_mod")
def test_enable_modules_apache_2_2(self, mock_enmod):
def test_enable_modules_22(self, mock_enmod):
self.config.version = (2, 2)
self.config.parser.modules.remove("authz_host_module")
self.config.parser.modules.remove("mod_authz_host.c")
@@ -59,7 +80,7 @@ class ApacheHttp01Test(util.ApacheTest):
self.assertEqual(enmod_calls[0][0][0], "authz_host")
@mock.patch("certbot_apache.configurator.ApacheConfigurator.enable_mod")
def test_enable_modules_apache_2_4(self, mock_enmod):
def test_enable_modules_24(self, mock_enmod):
self.config.parser.modules.remove("authz_core_module")
self.config.parser.modules.remove("mod_authz_core.c")
@@ -116,31 +137,6 @@ class ApacheHttp01Test(util.ApacheTest):
self.config.config.http01_port = 12345
self.assertRaises(errors.PluginError, self.http.perform)
def test_perform_1_achall_apache_2_2(self):
self.combinations_perform_test(num_achalls=1, minor_version=2)
def test_perform_1_achall_apache_2_4(self):
self.combinations_perform_test(num_achalls=1, minor_version=4)
def test_perform_2_achall_apache_2_2(self):
self.combinations_perform_test(num_achalls=2, minor_version=2)
def test_perform_2_achall_apache_2_4(self):
self.combinations_perform_test(num_achalls=2, minor_version=4)
def test_perform_3_achall_apache_2_2(self):
self.combinations_perform_test(num_achalls=3, minor_version=2)
def test_perform_3_achall_apache_2_4(self):
self.combinations_perform_test(num_achalls=3, minor_version=4)
def combinations_perform_test(self, num_achalls, minor_version):
"""Test perform with the given achall count and Apache version."""
achalls = self.achalls[:num_achalls]
vhosts = self.vhosts[:num_achalls]
self.config.version = (2, minor_version)
self.common_perform_test(achalls, vhosts)
def common_perform_test(self, achalls, vhosts):
"""Tests perform with the given achalls."""
challenge_dir = self.http.challenge_dir

View File

@@ -123,8 +123,7 @@ class ApacheTlsSni01(common.TLSSNI01):
self.configurator.config.tls_sni_01_port)))
try:
vhost = self.configurator.choose_vhost(achall.domain,
create_if_no_ssl=False)
vhost = self.configurator.choose_vhost(achall.domain, temp=True)
except (PluginError, MissingCommandlineFlag):
# We couldn't find the virtualhost for this domain, possibly
# because it's a new vhost that's not configured yet

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.23.0"
LE_AUTO_VERSION="0.22.2"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -1199,18 +1199,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.23.0 \
--hash=sha256:66c42cf780ddbf582ecc52aa6a61242450a2650227b436ad0d260685c4ef8a49 \
--hash=sha256:6cff4c5da1228661ccaf95195064cb29e6cdf80913193bdb2eb20e164c76053e
acme==0.23.0 \
--hash=sha256:02e9b596bd3bf8f0733d6d43ec2464ac8185a000acb58d2b4fd9e19223bbbf0b \
--hash=sha256:08c16635578507f526c338b3418c1147a9f015bf2d366abd51f38918703b4550
certbot-apache==0.23.0 \
--hash=sha256:50077742d2763b7600dfda618eb89c870aeea5e6a4c00f60157877f7a7d81f7c \
--hash=sha256:6b7acec243e224de5268d46c2597277586dffa55e838c252b6931c30d549028e
certbot-nginx==0.23.0 \
--hash=sha256:f12c21bbe3eb955ca533f1da96d28c6310378b138e844d83253562e18b6cbb32 \
--hash=sha256:cadf14e4bd504d9ce5987a5ec6dbd8e136638e55303ad5dc81dcb723ddd64324
certbot==0.22.2 \
--hash=sha256:c8c63bdf0fed6258bdbc892454314ec37bcd1c35a7f62524a083d93ccdfc420d \
--hash=sha256:e6e3639293e78397f31f7d99e3c63aff82d91e2b0d50d146ee3c77f830464bef
acme==0.22.2 \
--hash=sha256:59a55244612ee305d2caa6bb4cddd400fb60ec841bf011ed29a2899832a682c2 \
--hash=sha256:0ecd0ea369f53d5bc744d6e72717f9af2e1ceb558d109dbd433148851027adb4
certbot-apache==0.22.2 \
--hash=sha256:b5340d4b9190358fde8eb6a5be0def37e32014b5142ee79ef5d2319ccbbde754 \
--hash=sha256:3cd26912bb5732d917ddf7aad2fe870090d4ece9a408b2c2de8e9723ec99c759
certbot-nginx==0.22.2 \
--hash=sha256:91feef0d879496835d355e82841f92e5ecb5abbf6f23ea0ee5bbb8f5a92b278a \
--hash=sha256:b10bf04c1a20cf878d5e0d1877deb0e0780bc31b0ffda08ce7199bbc39d0753b
UNLIKELY_EOF
# -------------------------------------------------------------------------

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
install_requires = [
'certbot',

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -50,8 +50,7 @@ class AuthenticatorTest(test_util.TempDirTestCase, dns_test_common.BaseAuthentic
class DigitalOceanClientTest(unittest.TestCase):
id_num = 1
id = 1
record_prefix = "_acme-challenge"
record_name = record_prefix + "." + DOMAIN
record_content = "bar"
@@ -71,7 +70,7 @@ class DigitalOceanClientTest(unittest.TestCase):
domain_mock = mock.MagicMock()
domain_mock.name = DOMAIN
domain_mock.create_new_domain_record.return_value = {'domain_record': {'id': self.id_num}}
domain_mock.create_new_domain_record.return_value = {'domain_record': {'id': self.id}}
self.manager.get_all_domains.return_value = [wrong_domain_mock, domain_mock]

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -1,4 +1,3 @@
include LICENSE.txt
include README.rst
recursive-include docs *
recursive-include certbot_dns_google/testdata *

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -21,9 +21,8 @@ Credentials
-----------
Use of this plugin requires a configuration file containing the target DNS
server and optional port that supports RFC 2136 Dynamic Updates, the name
of the TSIG key, the TSIG key secret itself and the algorithm used if it's
different to HMAC-MD5.
server that supports RFC 2136 Dynamic Updates, the name of the TSIG key, the
TSIG key secret itself and the algorithm used if it's different to HMAC-MD5.
.. code-block:: ini
:name: credentials.ini
@@ -31,8 +30,6 @@ different to HMAC-MD5.
# Target DNS server
dns_rfc2136_server = 192.0.2.1
# Target DNS port
dns_rfc2136_port = 53
# TSIG key name
dns_rfc2136_name = keyname.
# TSIG key secret

View File

@@ -36,8 +36,6 @@ class Authenticator(dns_common.DNSAuthenticator):
'HMAC-SHA512': dns.tsig.HMAC_SHA512
}
PORT = 53
description = 'Obtain certificates using a DNS TXT record (if you are using BIND for DNS).'
ttl = 120
@@ -80,7 +78,6 @@ class Authenticator(dns_common.DNSAuthenticator):
def _get_rfc2136_client(self):
return _RFC2136Client(self.credentials.conf('server'),
int(self.credentials.conf('port') or self.PORT),
self.credentials.conf('name'),
self.credentials.conf('secret'),
self.ALGORITHMS.get(self.credentials.conf('algorithm'),
@@ -91,9 +88,8 @@ class _RFC2136Client(object):
"""
Encapsulates all communication with the target DNS server.
"""
def __init__(self, server, port, key_name, key_secret, key_algorithm):
def __init__(self, server, key_name, key_secret, key_algorithm):
self.server = server
self.port = port
self.keyring = dns.tsigkeyring.from_text({
key_name: key_secret
})
@@ -122,7 +118,7 @@ class _RFC2136Client(object):
update.add(rel, record_ttl, dns.rdatatype.TXT, record_content)
try:
response = dns.query.tcp(update, self.server, port=self.port)
response = dns.query.tcp(update, self.server)
except Exception as e:
raise errors.PluginError('Encountered error adding TXT record: {0}'
.format(e))
@@ -157,7 +153,7 @@ class _RFC2136Client(object):
update.delete(rel, dns.rdatatype.TXT, record_content)
try:
response = dns.query.tcp(update, self.server, port=self.port)
response = dns.query.tcp(update, self.server)
except Exception as e:
raise errors.PluginError('Encountered error deleting TXT record: {0}'
.format(e))
@@ -206,7 +202,7 @@ class _RFC2136Client(object):
request.flags ^= dns.flags.RD
try:
response = dns.query.udp(request, self.server, port=self.port)
response = dns.query.udp(request, self.server)
rcode = response.rcode()
# Authoritative Answer bit should be set

View File

@@ -14,7 +14,6 @@ from certbot.plugins.dns_test_common import DOMAIN
from certbot.tests import util as test_util
SERVER = '192.0.2.1'
PORT = 53
NAME = 'a-tsig-key.'
SECRET = 'SSB3b25kZXIgd2hvIHdpbGwgYm90aGVyIHRvIGRlY29kZSB0aGlzIHRleHQK'
VALID_CONFIG = {"rfc2136_server": SERVER, "rfc2136_name": NAME, "rfc2136_secret": SECRET}
@@ -75,7 +74,7 @@ class RFC2136ClientTest(unittest.TestCase):
def setUp(self):
from certbot_dns_rfc2136.dns_rfc2136 import _RFC2136Client
self.rfc2136_client = _RFC2136Client(SERVER, PORT, NAME, SECRET, dns.tsig.HMAC_MD5)
self.rfc2136_client = _RFC2136Client(SERVER, NAME, SECRET, dns.tsig.HMAC_MD5)
@mock.patch("dns.query.tcp")
def test_add_txt_record(self, query_mock):
@@ -85,7 +84,7 @@ class RFC2136ClientTest(unittest.TestCase):
self.rfc2136_client.add_txt_record("bar", "baz", 42)
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
query_mock.assert_called_with(mock.ANY, SERVER)
self.assertTrue("bar. 42 IN TXT \"baz\"" in str(query_mock.call_args[0][0]))
@mock.patch("dns.query.tcp")
@@ -118,7 +117,7 @@ class RFC2136ClientTest(unittest.TestCase):
self.rfc2136_client.del_txt_record("bar", "baz")
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
query_mock.assert_called_with(mock.ANY, SERVER)
self.assertTrue("bar. 0 NONE TXT \"baz\"" in str(query_mock.call_args[0][0]))
@mock.patch("dns.query.tcp")
@@ -170,7 +169,7 @@ class RFC2136ClientTest(unittest.TestCase):
# _query_soa | pylint: disable=protected-access
result = self.rfc2136_client._query_soa(DOMAIN)
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
query_mock.assert_called_with(mock.ANY, SERVER)
self.assertTrue(result == True)
@mock.patch("dns.query.udp")
@@ -180,7 +179,7 @@ class RFC2136ClientTest(unittest.TestCase):
# _query_soa | pylint: disable=protected-access
result = self.rfc2136_client._query_soa(DOMAIN)
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
query_mock.assert_called_with(mock.ANY, SERVER)
self.assertTrue(result == False)
@mock.patch("dns.query.udp")

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -42,26 +42,14 @@ class Authenticator(dns_common.DNSAuthenticator):
def _setup_credentials(self):
pass
def _perform(self, domain, validation_domain_name, validation): # pylint: disable=missing-docstring
pass
def perform(self, achalls):
self._attempt_cleanup = True
def _perform(self, domain, validation_domain_name, validation):
try:
change_ids = [
self._change_txt_record("UPSERT",
achall.validation_domain_name(achall.domain),
achall.validation(achall.account_key))
for achall in achalls
]
change_id = self._change_txt_record("UPSERT", validation_domain_name, validation)
for change_id in change_ids:
self._wait_for_change(change_id)
self._wait_for_change(change_id)
except (NoCredentialsError, ClientError) as e:
logger.debug('Encountered error during perform: %s', e, exc_info=True)
raise errors.PluginError("\n".join([str(e), INSTRUCTIONS]))
return [achall.response(achall.account_key) for achall in achalls]
def _cleanup(self, domain, validation_domain_name, validation):
try:

View File

@@ -3,7 +3,7 @@ import sys
from distutils.core import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -743,7 +743,7 @@ def _parse_server_raw(server):
if addr.ssl:
parsed_server['ssl'] = True
elif directive[0] == 'server_name':
parsed_server['names'].update(x.strip('"\'') for x in directive[1:])
parsed_server['names'].update(directive[1:])
elif _is_ssl_on_directive(directive):
parsed_server['ssl'] = True
apply_ssl_to_all_addrs = True

View File

@@ -639,7 +639,7 @@ class NginxConfiguratorTest(util.NginxTest):
self.assertEqual([[['server'],
[['listen', 'myhost', 'default_server'],
['listen', 'otherhost', 'default_server'],
['server_name', '"www.example.org"'],
['server_name', 'www.example.org'],
[['location', '/'],
[['root', 'html'],
['index', 'index.html', 'index.htm']]]]],

View File

@@ -1,7 +1,7 @@
server {
listen myhost default_server;
listen otherhost default_server;
server_name "www.example.org";
server_name www.example.org;
location / {
root html;

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.24.0.dev0'
version = '0.23.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -1,4 +1,4 @@
"""Certbot client."""
# version number like 1.2.3a0, must have at least 2 parts, like 1.2
__version__ = '0.24.0.dev0'
__version__ = '0.23.0.dev0'

View File

@@ -189,7 +189,7 @@ class AuthHandler(object):
return active_achalls
def _poll_challenges(self, aauthzrs, chall_update,
best_effort, min_sleep=3, max_rounds=30):
best_effort, min_sleep=3, max_rounds=15):
"""Wait for all challenge results to be determined."""
indices_to_check = set(chall_update.keys())
comp_indices = set()

View File

@@ -46,7 +46,7 @@ def rename_lineage(config):
"""
disp = zope.component.getUtility(interfaces.IDisplay)
certname = get_certnames(config, "rename")[0]
certname = _get_certnames(config, "rename")[0]
new_certname = config.new_certname
if not new_certname:
@@ -88,7 +88,7 @@ def certificates(config):
def delete(config):
"""Delete Certbot files associated with a certificate lineage."""
certnames = get_certnames(config, "delete", allow_multiple=True)
certnames = _get_certnames(config, "delete", allow_multiple=True)
for certname in certnames:
storage.delete_files(config, certname)
disp = zope.component.getUtility(interfaces.IDisplay)
@@ -288,7 +288,11 @@ def human_readable_cert_info(config, cert, skip_filter_checks=False):
cert.privkey))
return "".join(certinfo)
def get_certnames(config, verb, allow_multiple=False, custom_prompt=None):
###################
# Private Helpers
###################
def _get_certnames(config, verb, allow_multiple=False):
"""Get certname from flag, interactively, or error out.
"""
certname = config.certname
@@ -301,32 +305,22 @@ def get_certnames(config, verb, allow_multiple=False, custom_prompt=None):
if not choices:
raise errors.Error("No existing certificates found.")
if allow_multiple:
if not custom_prompt:
prompt = "Which certificate(s) would you like to {0}?".format(verb)
else:
prompt = custom_prompt
code, certnames = disp.checklist(
prompt, choices, cli_flag="--cert-name", force_interactive=True)
"Which certificate(s) would you like to {0}?".format(verb),
choices, cli_flag="--cert-name",
force_interactive=True)
if code != display_util.OK:
raise errors.Error("User ended interaction.")
else:
if not custom_prompt:
prompt = "Which certificate would you like to {0}?".format(verb)
else:
prompt = custom_prompt
code, index = disp.menu(
prompt, choices, cli_flag="--cert-name", force_interactive=True)
code, index = disp.menu("Which certificate would you like to {0}?".format(verb),
choices, cli_flag="--cert-name",
force_interactive=True)
if code != display_util.OK or index not in range(0, len(choices)):
raise errors.Error("User ended interaction.")
certnames = [choices[index]]
return certnames
###################
# Private Helpers
###################
def _report_lines(msgs):
"""Format a results report for a category of single-line renewal outcomes"""
return " " + "\n ".join(str(msg) for msg in msgs)

View File

@@ -76,7 +76,6 @@ obtain, install, and renew certificates:
(default) run Obtain & install a certificate in your current webserver
certonly Obtain or renew a certificate, but do not install it
renew Renew all previously obtained certificates that are near expiry
enhance Add security enhancements to your existing configuration
-d DOMAINS Comma-separated list of domains to obtain a certificate for
%s
@@ -416,12 +415,6 @@ VERB_HELP = [
os.path.join(flag_default("config_dir"), "live"))),
"usage": "\n\n certbot update_symlinks [options]\n\n"
}),
("enhance", {
"short": "Add security enhancements to your existing configuration",
"opts": ("Helps to harden the TLS configration by adding security enhancements "
"to already existing configuration."),
"usage": "\n\n certbot enhance [options]\n\n"
}),
]
# VERB_HELP is a list in order to preserve order, but a dict is sometimes useful
@@ -456,7 +449,6 @@ class HelpfulArgumentParser(object):
"update_symlinks": main.update_symlinks,
"certificates": main.certificates,
"delete": main.delete,
"enhance": main.enhance,
}
# Get notification function for printing
@@ -891,22 +883,21 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
"flag to 0 disables log rotation entirely, causing "
"Certbot to always append to the same log file.")
helpful.add(
[None, "automation", "run", "certonly", "enhance"],
"-n", "--non-interactive", "--noninteractive",
[None, "automation", "run", "certonly"], "-n", "--non-interactive", "--noninteractive",
dest="noninteractive_mode", action="store_true",
default=flag_default("noninteractive_mode"),
help="Run without ever asking for user input. This may require "
"additional command line flags; the client will try to explain "
"which ones are required if it finds one missing")
helpful.add(
[None, "register", "run", "certonly", "enhance"],
[None, "register", "run", "certonly"],
constants.FORCE_INTERACTIVE_FLAG, action="store_true",
default=flag_default("force_interactive"),
help="Force Certbot to be interactive even if it detects it's not "
"being run in a terminal. This flag cannot be used with the "
"renew subcommand.")
helpful.add(
[None, "run", "certonly", "certificates", "enhance"],
[None, "run", "certonly", "certificates"],
"-d", "--domains", "--domain", dest="domains",
metavar="DOMAIN", action=_DomainsAction,
default=flag_default("domains"),
@@ -922,8 +913,8 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
"name. In the case of a name collision it will append a number "
"like 0001 to the file path name. (default: Ask)")
helpful.add(
[None, "run", "certonly", "manage", "delete", "certificates",
"renew", "enhance"], "--cert-name", dest="certname",
[None, "run", "certonly", "manage", "delete", "certificates", "renew"],
"--cert-name", dest="certname",
metavar="CERTNAME", default=flag_default("certname"),
help="Certificate name to apply. This name is used by Certbot for housekeeping "
"and in file paths; it doesn't affect the content of the certificate itself. "
@@ -1094,8 +1085,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
dest="must_staple", default=flag_default("must_staple"),
help=config_help("must_staple"))
helpful.add(
["security", "enhance"],
"--redirect", action="store_true", dest="redirect",
"security", "--redirect", action="store_true", dest="redirect",
default=flag_default("redirect"),
help="Automatically redirect all HTTP traffic to HTTPS for the newly "
"authenticated vhost. (default: Ask)")
@@ -1105,8 +1095,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
help="Do not automatically redirect all HTTP traffic to HTTPS for the newly "
"authenticated vhost. (default: Ask)")
helpful.add(
["security", "enhance"],
"--hsts", action="store_true", dest="hsts", default=flag_default("hsts"),
"security", "--hsts", action="store_true", dest="hsts", default=flag_default("hsts"),
help="Add the Strict-Transport-Security header to every HTTP response."
" Forcing browser to always use SSL for the domain."
" Defends against SSL Stripping.")
@@ -1114,8 +1103,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
"security", "--no-hsts", action="store_false", dest="hsts",
default=flag_default("hsts"), help=argparse.SUPPRESS)
helpful.add(
["security", "enhance"],
"--uir", action="store_true", dest="uir", default=flag_default("uir"),
"security", "--uir", action="store_true", dest="uir", default=flag_default("uir"),
help='Add the "Content-Security-Policy: upgrade-insecure-requests"'
' header to every HTTP response. Forcing the browser to use'
' https:// for every http:// resource.')
@@ -1192,14 +1180,6 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
default=flag_default("directory_hooks"), dest="directory_hooks",
help="Disable running executables found in Certbot's hook directories"
" during renewal. (default: False)")
helpful.add(
"renew", "--disable-renew-updates", action="store_true",
default=flag_default("disable_renew_updates"), dest="disable_renew_updates",
help="Disable automatic updates to your server configuration that"
" would otherwise be done by the selected installer plugin, and triggered"
" when the user executes \"certbot renew\", regardless of if the certificate"
" is renewed. This setting does not apply to important TLS configuration"
" updates.")
helpful.add_deprecated_argument("--agree-dev-preview", 0)
helpful.add_deprecated_argument("--dialog", 0)

View File

@@ -338,10 +338,9 @@ class Client(object):
authenticator and installer, and then create a new renewable lineage
containing it.
:param domains: domains to request a certificate for
:type domains: `list` of `str`
:param certname: requested name of lineage
:type certname: `str` or `None`
:param list domains: Domains to request.
:param plugins: A PluginsFactory object.
:param str certname: Name of new cert
:returns: A new :class:`certbot.storage.RenewableCert` instance
referred to the enrolled cert lineage, False if the cert could not
@@ -352,11 +351,17 @@ class Client(object):
if (self.config.config_dir != constants.CLI_DEFAULTS["config_dir"] or
self.config.work_dir != constants.CLI_DEFAULTS["work_dir"]):
logger.info(
logger.warning(
"Non-standard path(s), might not work with crontab installed "
"by your operating system package manager")
new_name = self._choose_lineagename(domains, certname)
if certname:
new_name = certname
elif util.is_wildcard_domain(domains[0]):
# Don't make files and directories starting with *.
new_name = domains[0][2:]
else:
new_name = domains[0]
if self.config.dry_run:
logger.debug("Dry run: Skipping creating new lineage for %s",
@@ -368,26 +373,6 @@ class Client(object):
key.pem, chain,
self.config)
def _choose_lineagename(self, domains, certname):
"""Chooses a name for the new lineage.
:param domains: domains in certificate request
:type domains: `list` of `str`
:param certname: requested name of lineage
:type certname: `str` or `None`
:returns: lineage name that should be used
:rtype: str
"""
if certname:
return certname
elif util.is_wildcard_domain(domains[0]):
# Don't make files and directories starting with *.
return domains[0][2:]
else:
return domains[0]
def save_certificate(self, cert_pem, chain_pem,
cert_path, chain_path, fullchain_path):
"""Saves the certificate received from the ACME server.
@@ -466,7 +451,7 @@ class Client(object):
# sites may have been enabled / final cleanup
self.installer.restart()
def enhance_config(self, domains, chain_path, ask_redirect=True):
def enhance_config(self, domains, chain_path):
"""Enhance the configuration.
:param list domains: list of domains to configure
@@ -493,9 +478,8 @@ class Client(object):
for config_name, enhancement_name, option in enhancement_info:
config_value = getattr(self.config, config_name)
if enhancement_name in supported:
if ask_redirect:
if config_name == "redirect" and config_value is None:
config_value = enhancements.ask(enhancement_name)
if config_name == "redirect" and config_value is None:
config_value = enhancements.ask(enhancement_name)
if config_value:
self.apply_enhancement(domains, enhancement_name, option)
enhanced = True
@@ -531,12 +515,8 @@ class Client(object):
try:
self.installer.enhance(dom, enhancement, options)
except errors.PluginEnhancementAlreadyPresent:
if enhancement == "ensure-http-header":
logger.warning("Enhancement %s was already set.",
options)
else:
logger.warning("Enhancement %s was already set.",
enhancement)
logger.warning("Enhancement %s was already set.",
enhancement)
except errors.PluginError:
logger.warning("Unable to set enhancement %s for %s",
enhancement, dom)

View File

@@ -64,7 +64,6 @@ CLI_DEFAULTS = dict(
pref_challs=[],
validate_hooks=True,
directory_hooks=True,
disable_renew_updates=False,
# Subparsers
num=None,
@@ -85,7 +84,7 @@ CLI_DEFAULTS = dict(
config_dir="/etc/letsencrypt",
work_dir="/var/lib/letsencrypt",
logs_dir="/var/log/letsencrypt",
server="https://acme-v01.api.letsencrypt.org/directory",
server="https://acme-v02.api.letsencrypt.org/directory",
# Plugins parsers
configurator=None,

View File

@@ -13,7 +13,7 @@ import pyrfc3339
import six
import zope.component
from cryptography.hazmat.backends import default_backend
from cryptography import x509 # type: ignore
from cryptography import x509
from acme import crypto_util as acme_crypto_util

View File

@@ -86,31 +86,13 @@ def choose_account(accounts):
else:
return None
def choose_values(values, question=None):
"""Display screen to let user pick one or multiple values from the provided
list.
:param list values: Values to select from
:returns: List of selected values
:rtype: list
"""
code, items = z_util(interfaces.IDisplay).checklist(
question, tags=values, force_interactive=True)
if code == display_util.OK and items:
return items
else:
return []
def choose_names(installer, question=None):
def choose_names(installer):
"""Display screen to select domains to validate.
:param installer: An installer object
:type installer: :class:`certbot.interfaces.IInstaller`
:param `str` question: Overriding dialog question to ask the user if asked
to choose from domain names.
:returns: List of selected names
:rtype: `list` of `str`
@@ -126,7 +108,7 @@ def choose_names(installer, question=None):
return _choose_names_manually(
"No names were found in your configuration files. ")
code, names = _filter_names(names, question)
code, names = _filter_names(names)
if code == display_util.OK and names:
return names
else:
@@ -160,7 +142,7 @@ def _sort_names(FQDNs):
return sorted(FQDNs, key=lambda fqdn: fqdn.split('.')[::-1][1:])
def _filter_names(names, override_question=None):
def _filter_names(names):
"""Determine which names the user would like to select from a list.
:param list names: domain names
@@ -173,12 +155,10 @@ def _filter_names(names, override_question=None):
"""
#Sort by domain first, and then by subdomain
sorted_names = _sort_names(names)
if override_question:
question = override_question
else:
question = "Which names would you like to activate HTTPS for?"
code, names = z_util(interfaces.IDisplay).checklist(
question, tags=sorted_names, cli_flag="--domains", force_interactive=True)
"Which names would you like to activate HTTPS for?",
tags=sorted_names, cli_flag="--domains", force_interactive=True)
return code, [str(s) for s in names]

View File

@@ -87,10 +87,6 @@ class NotSupportedError(PluginError):
"""Certbot Plugin function not supported error."""
class PluginStorageError(PluginError):
"""Certbot Plugin Storage error."""
class StandaloneBindError(Error):
"""Standalone plugin bind error."""

View File

@@ -1,6 +1,5 @@
"""Certbot client interfaces."""
import abc
import six
import zope.interface
# pylint: disable=no-self-argument,no-method-argument,no-init,inherit-non-class
@@ -257,10 +256,6 @@ class IConfig(zope.interface.Interface):
"user; only needed if your config is somewhere unsafe like /tmp/."
"This is a boolean")
disable_renew_updates = zope.interface.Attribute(
"If updates provided by installer enhancements when Certbot is being run"
" with \"renew\" verb should be disabled.")
class IInstaller(IPlugin):
"""Generic Certbot Installer Interface.
@@ -596,72 +591,3 @@ class IReporter(zope.interface.Interface):
def print_messages(self):
"""Prints messages to the user and clears the message queue."""
# Updater interfaces
#
# When "certbot renew" is run, Certbot will iterate over each lineage and check
# if the selected installer for that lineage is a subclass of each updater
# class. If it is and the update of that type is configured to be run for that
# lineage, the relevant update function will be called for each domain in the
# lineage. These functions are never called for other subcommands, so if an
# installer wants to perform an update during the run or install subcommand, it
# should do so when :func:`IInstaller.deploy_cert` is called.
@six.add_metaclass(abc.ABCMeta)
class GenericUpdater(object):
"""Interface for update types not currently specified by Certbot.
This class allows plugins to perform types of updates that Certbot hasn't
defined (yet).
To make use of this interface, the installer should implement the interface
methods, and interfaces.GenericUpdater.register(InstallerClass) should
be called from the installer code.
"""
@abc.abstractmethod
def generic_updates(self, domain, *args, **kwargs):
"""Perform any update types defined by the installer.
If an installer is a subclass of the class containing this method, this
function will always be called when "certbot renew" is run. If the
update defined by the installer should be run conditionally, the
installer needs to handle checking the conditions itself.
This method is called once for each domain.
:param str domain: domain to handle the updates for
"""
@six.add_metaclass(abc.ABCMeta)
class RenewDeployer(object):
"""Interface for update types run when a lineage is renewed
This class allows plugins to perform types of updates that need to run at
lineage renewal that Certbot hasn't defined (yet).
To make use of this interface, the installer should implement the interface
methods, and interfaces.RenewDeployer.register(InstallerClass) should
be called from the installer code.
"""
@abc.abstractmethod
def renew_deploy(self, lineage, *args, **kwargs):
"""Perform updates defined by installer when a certificate has been renewed
If an installer is a subclass of the class containing this method, this
function will always be called when a certficate has been renewed by
running "certbot renew". For example if a plugin needs to copy a
certificate over, or change configuration based on the new certificate.
This method is called once for each lineage renewed
:param lineage: Certificate lineage object that is set if certificate
was renewed on this run.
:type lineage: storage.RenewableCert
"""

View File

@@ -29,7 +29,6 @@ from certbot import log
from certbot import renewal
from certbot import reporter
from certbot import storage
from certbot import updater
from certbot import util
from certbot.display import util as display_util, ops as display_ops
@@ -383,7 +382,7 @@ def _ask_user_to_confirm_new_names(config, new_domains, certname, old_domains):
if not obj.yesno(msg, "Update cert", "Cancel", default=True):
raise errors.ConfigurationError("Specified mismatched cert name and domains.")
def _find_domains_or_certname(config, installer, question=None):
def _find_domains_or_certname(config, installer):
"""Retrieve domains and certname from config or user input.
:param config: Configuration object
@@ -392,8 +391,6 @@ def _find_domains_or_certname(config, installer, question=None):
:param installer: Installer object
:type installer: interfaces.IInstaller
:param `str` question: Overriding dialog question to ask the user if asked
to choose from domain names.
:returns: Two-part tuple of domains and certname
:rtype: `tuple` of list of `str` and `str`
@@ -414,7 +411,7 @@ def _find_domains_or_certname(config, installer, question=None):
# that certname might not have existed, or there was a problem.
# try to get domains from the user.
if not domains:
domains = display_ops.choose_names(installer, question)
domains = display_ops.choose_names(installer)
if not domains and not certname:
raise errors.Error("Please specify --domains, or --installer that "
@@ -862,53 +859,6 @@ def plugins_cmd(config, plugins):
logger.debug("Prepared plugins: %s", available)
notify(str(available))
def enhance(config, plugins):
"""Add security enhancements to existing configuration
:param config: Configuration object
:type config: interfaces.IConfig
:param plugins: List of plugins
:type plugins: `list` of `str`
:returns: `None`
:rtype: None
"""
supported_enhancements = ["hsts", "redirect", "uir", "staple"]
# Check that at least one enhancement was requested on command line
if not any([getattr(config, enh) for enh in supported_enhancements]):
msg = ("Please specify one or more enhancement types to configure. To list "
"the available enhancement types, run:\n\n%s --help enhance\n")
logger.warning(msg, sys.argv[0])
raise errors.MisconfigurationError("No enhancements requested, exiting.")
try:
installer, _ = plug_sel.choose_configurator_plugins(config, plugins, "enhance")
except errors.PluginSelectionError as e:
return str(e)
certname_question = ("Which certificate would you like to use to enhance "
"your configuration?")
config.certname = cert_manager.get_certnames(
config, "enhance", allow_multiple=False,
custom_prompt=certname_question)[0]
cert_domains = cert_manager.domains_for_certname(config, config.certname)
if config.noninteractive_mode:
domains = cert_domains
else:
domain_question = ("Which domain names would you like to enable the "
"selected enhancements for?")
domains = display_ops.choose_values(cert_domains, domain_question)
if not domains:
raise errors.Error("User cancelled the domain selection. No domains "
"defined, exiting.")
if not config.chain_path:
lineage = cert_manager.lineage_for_certname(config, config.certname)
config.chain_path = lineage.chain_path
le_client = _init_le_client(config, authenticator=None, installer=installer)
le_client.enhance_config(domains, config.chain_path, ask_redirect=False)
def rollback(config, plugins):
"""Rollback server configuration changes made during install.
@@ -1146,9 +1096,10 @@ def renew_cert(config, plugins, lineage):
except errors.PluginSelectionError as e:
logger.info("Could not choose appropriate plugin: %s", e)
raise
le_client = _init_le_client(config, auth, installer)
renewed_lineage = _get_and_save_cert(le_client, config, lineage=lineage)
_get_and_save_cert(le_client, config, lineage=lineage)
notify = zope.component.getUtility(interfaces.IDisplay).notification
if installer is None:
@@ -1158,11 +1109,9 @@ def renew_cert(config, plugins, lineage):
# In case of a renewal, reload server to pick up new certificate.
# In principle we could have a configuration option to inhibit this
# from happening.
updater.run_renewal_deployer(renewed_lineage, installer, config)
installer.restart()
notify("new certificate deployed with reload of {0} server; fullchain is {1}".format(
config.installer, lineage.fullchain), pause=False)
# Run deployer
def certonly(config, plugins):
"""Authenticate & obtain cert, but do not install it.

View File

@@ -18,8 +18,6 @@ from certbot import interfaces
from certbot import reverter
from certbot import util
from certbot.plugins.storage import PluginStorage
logger = logging.getLogger(__name__)
@@ -101,6 +99,7 @@ class Plugin(object):
def conf(self, var):
"""Find a configuration value for variable ``var``."""
return getattr(self.config, self.dest(var))
# other
class Installer(Plugin):
@@ -111,7 +110,6 @@ class Installer(Plugin):
"""
def __init__(self, *args, **kwargs):
super(Installer, self).__init__(*args, **kwargs)
self.storage = PluginStorage(self.config, self.name)
self.reverter = reverter.Reverter(self.config)
def add_to_checkpoint(self, save_files, save_notes, temporary=False):

View File

@@ -147,7 +147,6 @@ def record_chosen_plugins(config, plugins, auth, inst):
def choose_configurator_plugins(config, plugins, verb):
# pylint: disable=too-many-branches
"""
Figure out which configurator we're going to use, modifies
config.authenticator and config.installer strings to reflect that choice if
@@ -160,11 +159,6 @@ def choose_configurator_plugins(config, plugins, verb):
"""
req_auth, req_inst = cli_plugin_requests(config)
installer_question = None
if verb == "enhance":
installer_question = ("Which installer would you like to use to "
"configure the selected enhancements?")
# Which plugins do we need?
if verb == "run":
@@ -182,11 +176,11 @@ def choose_configurator_plugins(config, plugins, verb):
need_inst = need_auth = False
if verb == "certonly":
need_auth = True
if verb == "install" or verb == "enhance":
if verb == "install":
need_inst = True
if config.authenticator:
logger.warning("Specifying an authenticator doesn't make sense when "
"running Certbot with verb \"%s\"", verb)
logger.warning("Specifying an authenticator doesn't make sense in install mode")
# Try to meet the user's request and/or ask them to pick plugins
authenticator = installer = None
if verb == "run" and req_auth == req_inst:
@@ -195,7 +189,7 @@ def choose_configurator_plugins(config, plugins, verb):
authenticator = installer = pick_configurator(config, req_inst, plugins)
else:
if need_inst or req_inst:
installer = pick_installer(config, req_inst, plugins, installer_question)
installer = pick_installer(config, req_inst, plugins)
if need_auth:
authenticator = pick_authenticator(config, req_auth, plugins)
logger.debug("Selected authenticator %s and installer %s", authenticator, installer)

View File

@@ -1,117 +0,0 @@
"""Plugin storage class."""
import json
import logging
import os
from certbot import errors
logger = logging.getLogger(__name__)
class PluginStorage(object):
"""Class implementing storage functionality for plugins"""
def __init__(self, config, classkey):
"""Initializes PluginStorage object storing required configuration
options.
:param .configuration.NamespaceConfig config: Configuration object
:param str classkey: class name to use as root key in storage file
"""
self._config = config
self._classkey = classkey
self._initialized = False
self._data = None
self._storagepath = None
def _initialize_storage(self):
"""Initializes PluginStorage data and reads current state from the disk
if the storage json exists."""
self._storagepath = os.path.join(self._config.config_dir, ".pluginstorage.json")
self._load()
self._initialized = True
def _load(self):
"""Reads PluginStorage content from the disk to a dict structure
:raises .errors.PluginStorageError: when unable to open or read the file
"""
data = dict()
filedata = ""
try:
with open(self._storagepath, 'r') as fh:
filedata = fh.read()
except IOError as e:
errmsg = "Could not read PluginStorage data file: {0} : {1}".format(
self._storagepath, str(e))
if os.path.isfile(self._storagepath):
# Only error out if file exists, but cannot be read
logger.error(errmsg)
raise errors.PluginStorageError(errmsg)
try:
data = json.loads(filedata)
except ValueError:
if not filedata:
logger.debug("Plugin storage file %s was empty, no values loaded",
self._storagepath)
else:
errmsg = "PluginStorage file {0} is corrupted.".format(
self._storagepath)
logger.error(errmsg)
raise errors.PluginStorageError(errmsg)
self._data = data
def save(self):
"""Saves PluginStorage content to disk
:raises .errors.PluginStorageError: when unable to serialize the data
or write it to the filesystem
"""
if not self._initialized:
errmsg = "Unable to save, no values have been added to PluginStorage."
logger.error(errmsg)
raise errors.PluginStorageError(errmsg)
try:
serialized = json.dumps(self._data)
except TypeError as e:
errmsg = "Could not serialize PluginStorage data: {0}".format(
str(e))
logger.error(errmsg)
raise errors.PluginStorageError(errmsg)
try:
with os.fdopen(os.open(self._storagepath,
os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:
fh.write(serialized)
except IOError as e:
errmsg = "Could not write PluginStorage data to file {0} : {1}".format(
self._storagepath, str(e))
logger.error(errmsg)
raise errors.PluginStorageError(errmsg)
def put(self, key, value):
"""Put configuration value to PluginStorage
:param str key: Key to store the value to
:param value: Data to store
"""
if not self._initialized:
self._initialize_storage()
if not self._classkey in self._data.keys():
self._data[self._classkey] = dict()
self._data[self._classkey][key] = value
def fetch(self, key):
"""Get configuration value from PluginStorage
:param str key: Key to get value from the storage
:raises KeyError: If the key doesn't exist in the storage
"""
if not self._initialized:
self._initialize_storage()
return self._data[self._classkey][key]

View File

@@ -1,117 +0,0 @@
"""Tests for certbot.plugins.storage.PluginStorage"""
import json
import mock
import os
import unittest
from certbot import errors
from certbot.plugins import common
from certbot.tests import util as test_util
class PluginStorageTest(test_util.ConfigTestCase):
"""Test for certbot.plugins.storage.PluginStorage"""
def setUp(self):
super(PluginStorageTest, self).setUp()
self.plugin_cls = common.Installer
os.mkdir(self.config.config_dir)
with mock.patch("certbot.reverter.util"):
self.plugin = self.plugin_cls(config=self.config, name="mockplugin")
def test_load_errors_cant_read(self):
with open(os.path.join(self.config.config_dir,
".pluginstorage.json"), "w") as fh:
fh.write("dummy")
# When unable to read file that exists
mock_open = mock.mock_open()
mock_open.side_effect = IOError
self.plugin.storage.storagepath = os.path.join(self.config.config_dir,
".pluginstorage.json")
with mock.patch("six.moves.builtins.open", mock_open):
with mock.patch('os.path.isfile', return_value=True):
with mock.patch("certbot.reverter.util"):
self.assertRaises(errors.PluginStorageError,
self.plugin.storage._load) # pylint: disable=protected-access
def test_load_errors_empty(self):
with open(os.path.join(self.config.config_dir, ".pluginstorage.json"), "w") as fh:
fh.write('')
with mock.patch("certbot.plugins.storage.logger.debug") as mock_log:
# Should not error out but write a debug log line instead
with mock.patch("certbot.reverter.util"):
nocontent = self.plugin_cls(self.config, "mockplugin")
self.assertRaises(KeyError,
nocontent.storage.fetch, "value")
self.assertTrue(mock_log.called)
self.assertTrue("no values loaded" in mock_log.call_args[0][0])
def test_load_errors_corrupted(self):
with open(os.path.join(self.config.config_dir,
".pluginstorage.json"), "w") as fh:
fh.write('invalid json')
with mock.patch("certbot.plugins.storage.logger.error") as mock_log:
with mock.patch("certbot.reverter.util"):
corrupted = self.plugin_cls(self.config, "mockplugin")
self.assertRaises(errors.PluginError,
corrupted.storage.fetch,
"value")
self.assertTrue("is corrupted" in mock_log.call_args[0][0])
def test_save_errors_cant_serialize(self):
with mock.patch("certbot.plugins.storage.logger.error") as mock_log:
# Set data as something that can't be serialized
self.plugin.storage._initialized = True # pylint: disable=protected-access
self.plugin.storage.storagepath = "/tmp/whatever"
self.plugin.storage._data = self.plugin_cls # pylint: disable=protected-access
self.assertRaises(errors.PluginStorageError,
self.plugin.storage.save)
self.assertTrue("Could not serialize" in mock_log.call_args[0][0])
def test_save_errors_unable_to_write_file(self):
mock_open = mock.mock_open()
mock_open.side_effect = IOError
with mock.patch("os.open", mock_open):
with mock.patch("certbot.plugins.storage.logger.error") as mock_log:
self.plugin.storage._data = {"valid": "data"} # pylint: disable=protected-access
self.plugin.storage._initialized = True # pylint: disable=protected-access
self.assertRaises(errors.PluginStorageError,
self.plugin.storage.save)
self.assertTrue("Could not write" in mock_log.call_args[0][0])
def test_save_uninitialized(self):
with mock.patch("certbot.reverter.util"):
self.assertRaises(errors.PluginStorageError,
self.plugin_cls(self.config, "x").storage.save)
def test_namespace_isolation(self):
with mock.patch("certbot.reverter.util"):
plugin1 = self.plugin_cls(self.config, "first")
plugin2 = self.plugin_cls(self.config, "second")
plugin1.storage.put("first_key", "first_value")
self.assertRaises(KeyError,
plugin2.storage.fetch, "first_key")
self.assertRaises(KeyError,
plugin2.storage.fetch, "first")
self.assertEqual(plugin1.storage.fetch("first_key"), "first_value")
def test_saved_state(self):
self.plugin.storage.put("testkey", "testvalue")
# Write to disk
self.plugin.storage.save()
with mock.patch("certbot.reverter.util"):
another = self.plugin_cls(self.config, "mockplugin")
self.assertEqual(another.storage.fetch("testkey"), "testvalue")
with open(os.path.join(self.config.config_dir,
".pluginstorage.json"), 'r') as fh:
psdata = fh.read()
psjson = json.loads(psdata)
self.assertTrue("mockplugin" in psjson.keys())
self.assertEqual(len(psjson), 1)
self.assertEqual(psjson["mockplugin"]["testkey"], "testvalue")
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -12,14 +12,13 @@ import zope.component
import OpenSSL
from certbot import cli
from certbot import crypto_util
from certbot import errors
from certbot import interfaces
from certbot import util
from certbot import hooks
from certbot import storage
from certbot import updater
from certbot.plugins import disco as plugins_disco
logger = logging.getLogger(__name__)
@@ -412,9 +411,9 @@ def handle_renewal_request(config):
# XXX: ensure that each call here replaces the previous one
zope.component.provideUtility(lineage_config)
renewal_candidate.ensure_deployed()
from certbot import main
plugins = plugins_disco.PluginsRegistry.find_all()
if should_renew(lineage_config, renewal_candidate):
plugins = plugins_disco.PluginsRegistry.find_all()
from certbot import main
# domains have been restored into lineage_config by reconstitute
# but they're unnecessary anyway because renew_cert here
# will just grab them from the certificate
@@ -427,10 +426,6 @@ def handle_renewal_request(config):
"cert", renewal_candidate.latest_common_version()))
renew_skipped.append("%s expires on %s" % (renewal_candidate.fullchain,
expiry.strftime("%Y-%m-%d")))
# Run updater interface methods
updater.run_generic_updaters(lineage_config, plugins,
renewal_candidate)
except Exception as e: # pylint: disable=broad-except
# obtain_cert (presumably) encountered an unanticipated problem.
logger.warning("Attempting to renew cert (%s) from %s produced an "

View File

@@ -1053,9 +1053,6 @@ class RenewableCert(object):
"`cert.pem` : will break many server configurations, and "
"should not be used\n"
" without reading further documentation (see link below).\n\n"
"WARNING: DO NOT MOVE THESE FILES!\n"
" Certbot expects these files to remain in this location in order\n"
" to function properly!\n\n"
"We recommend not moving these files. For more information, see the Certbot\n"
"User Guide at https://certbot.eff.org/docs/using.html#where-are-my-"
"certificates.\n")

View File

@@ -216,12 +216,11 @@ class CertificatesTest(BaseCertManagerTest):
cert.is_test_cert = False
parsed_certs = [cert]
mock_config = mock.MagicMock(certname=None, lineagename=None)
# pylint: disable=protected-access
# pylint: disable=protected-access
get_report = lambda: cert_manager._report_human_readable(mock_config, parsed_certs)
mock_config = mock.MagicMock(certname=None, lineagename=None)
# pylint: disable=protected-access
out = get_report()
self.assertTrue("INVALID: EXPIRED" in out)
@@ -569,103 +568,5 @@ class MatchAndCheckOverlaps(storage_test.BaseRenewableCertTest):
self.assertRaises(errors.OverlappingMatchFound, self._call, self.config, None, None, None)
class GetCertnameTest(unittest.TestCase):
"""Tests for certbot.cert_manager."""
def setUp(self):
self.get_utility_patch = test_util.patch_get_utility()
self.mock_get_utility = self.get_utility_patch.start()
self.config = mock.MagicMock()
self.config.certname = None
def tearDown(self):
self.get_utility_patch.stop()
@mock.patch('certbot.storage.renewal_conf_files')
@mock.patch('certbot.storage.lineagename_for_filename')
def test_get_certnames(self, mock_name, mock_files):
mock_files.return_value = ['example.com.conf']
mock_name.return_value = 'example.com'
from certbot import cert_manager
prompt = "Which certificate would you"
self.mock_get_utility().menu.return_value = (display_util.OK, 0)
self.assertEquals(
cert_manager.get_certnames(
self.config, "verb", allow_multiple=False), ['example.com'])
self.assertTrue(
prompt in self.mock_get_utility().menu.call_args[0][0])
@mock.patch('certbot.storage.renewal_conf_files')
@mock.patch('certbot.storage.lineagename_for_filename')
def test_get_certnames_custom_prompt(self, mock_name, mock_files):
mock_files.return_value = ['example.com.conf']
mock_name.return_value = 'example.com'
from certbot import cert_manager
prompt = "custom prompt"
self.mock_get_utility().menu.return_value = (display_util.OK, 0)
self.assertEquals(
cert_manager.get_certnames(
self.config, "verb", allow_multiple=False, custom_prompt=prompt),
['example.com'])
self.assertEquals(self.mock_get_utility().menu.call_args[0][0],
prompt)
@mock.patch('certbot.storage.renewal_conf_files')
@mock.patch('certbot.storage.lineagename_for_filename')
def test_get_certnames_user_abort(self, mock_name, mock_files):
mock_files.return_value = ['example.com.conf']
mock_name.return_value = 'example.com'
from certbot import cert_manager
self.mock_get_utility().menu.return_value = (display_util.CANCEL, 0)
self.assertRaises(
errors.Error,
cert_manager.get_certnames,
self.config, "erroring_anyway", allow_multiple=False)
@mock.patch('certbot.storage.renewal_conf_files')
@mock.patch('certbot.storage.lineagename_for_filename')
def test_get_certnames_allow_multiple(self, mock_name, mock_files):
mock_files.return_value = ['example.com.conf']
mock_name.return_value = 'example.com'
from certbot import cert_manager
prompt = "Which certificate(s) would you"
self.mock_get_utility().checklist.return_value = (display_util.OK,
['example.com'])
self.assertEquals(
cert_manager.get_certnames(
self.config, "verb", allow_multiple=True), ['example.com'])
self.assertTrue(
prompt in self.mock_get_utility().checklist.call_args[0][0])
@mock.patch('certbot.storage.renewal_conf_files')
@mock.patch('certbot.storage.lineagename_for_filename')
def test_get_certnames_allow_multiple_custom_prompt(self, mock_name, mock_files):
mock_files.return_value = ['example.com.conf']
mock_name.return_value = 'example.com'
from certbot import cert_manager
prompt = "custom prompt"
self.mock_get_utility().checklist.return_value = (display_util.OK,
['example.com'])
self.assertEquals(
cert_manager.get_certnames(
self.config, "verb", allow_multiple=True, custom_prompt=prompt),
['example.com'])
self.assertEquals(
self.mock_get_utility().checklist.call_args[0][0],
prompt)
@mock.patch('certbot.storage.renewal_conf_files')
@mock.patch('certbot.storage.lineagename_for_filename')
def test_get_certnames_allow_multiple_user_abort(self, mock_name, mock_files):
mock_files.return_value = ['example.com.conf']
mock_name.return_value = 'example.com'
from certbot import cert_manager
self.mock_get_utility().checklist.return_value = (display_util.CANCEL, [])
self.assertRaises(
errors.Error,
cert_manager.get_certnames,
self.config, "erroring_anyway", allow_multiple=True)
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -433,22 +433,6 @@ class EnhanceConfigTest(ClientTestCommon):
self.client.installer.enhance.assert_not_called()
mock_enhancements.ask.assert_not_called()
@mock.patch("certbot.client.logger")
def test_already_exists_header(self, mock_log):
self.config.hsts = True
self._test_with_already_existing()
self.assertTrue(mock_log.warning.called)
self.assertEquals(mock_log.warning.call_args[0][1],
'Strict-Transport-Security')
@mock.patch("certbot.client.logger")
def test_already_exists_redirect(self, mock_log):
self.config.redirect = True
self._test_with_already_existing()
self.assertTrue(mock_log.warning.called)
self.assertEquals(mock_log.warning.call_args[0][1],
'redirect')
def test_no_ask_hsts(self):
self.config.hsts = True
self._test_with_all_supported()
@@ -524,13 +508,6 @@ class EnhanceConfigTest(ClientTestCommon):
self.assertEqual(self.client.installer.save.call_count, 1)
self.assertEqual(self.client.installer.restart.call_count, 1)
def _test_with_already_existing(self):
self.client.installer = mock.MagicMock()
self.client.installer.supported_enhancements.return_value = [
"ensure-http-header", "redirect", "staple-ocsp"]
self.client.installer.enhance.side_effect = errors.PluginEnhancementAlreadyPresent()
self.client.enhance_config([self.domain], None)
class RollbackTest(unittest.TestCase):
"""Tests for certbot.client.rollback."""

View File

@@ -207,9 +207,9 @@ class ChooseNamesTest(unittest.TestCase):
self.mock_install = mock.MagicMock()
@classmethod
def _call(cls, installer, question=None):
def _call(cls, installer):
from certbot.display.ops import choose_names
return choose_names(installer, question)
return choose_names(installer)
@mock.patch("certbot.display.ops._choose_names_manually")
def test_no_installer(self, mock_manual):
@@ -281,15 +281,6 @@ class ChooseNamesTest(unittest.TestCase):
self.assertEqual(names, ["example.com"])
self.assertEqual(mock_util().checklist.call_count, 1)
@test_util.patch_get_utility("certbot.display.ops.z_util")
def test_filter_namees_override_question(self, mock_util):
self.mock_install.get_all_names.return_value = set(["example.com"])
mock_util().checklist.return_value = (display_util.OK, ["example.com"])
names = self._call(self.mock_install, "Custom")
self.assertEqual(names, ["example.com"])
self.assertEqual(mock_util().checklist.call_count, 1)
self.assertEqual(mock_util().checklist.call_args[0][0], "Custom")
@test_util.patch_get_utility("certbot.display.ops.z_util")
def test_filter_names_nothing_selected(self, mock_util):
self.mock_install.get_all_names.return_value = set(["example.com"])
@@ -490,42 +481,5 @@ class ValidatorTests(unittest.TestCase):
self.__validator, "msg", default="")
class ChooseValuesTest(unittest.TestCase):
"""Test choose_values."""
@classmethod
def _call(cls, values, question):
from certbot.display.ops import choose_values
return choose_values(values, question)
@test_util.patch_get_utility("certbot.display.ops.z_util")
def test_choose_names_success(self, mock_util):
items = ["first", "second", "third"]
mock_util().checklist.return_value = (display_util.OK, [items[2]])
result = self._call(items, None)
self.assertEquals(result, [items[2]])
self.assertTrue(mock_util().checklist.called)
self.assertEquals(mock_util().checklist.call_args[0][0], None)
@test_util.patch_get_utility("certbot.display.ops.z_util")
def test_choose_names_success_question(self, mock_util):
items = ["first", "second", "third"]
question = "Which one?"
mock_util().checklist.return_value = (display_util.OK, [items[1]])
result = self._call(items, question)
self.assertEquals(result, [items[1]])
self.assertTrue(mock_util().checklist.called)
self.assertEquals(mock_util().checklist.call_args[0][0], question)
@test_util.patch_get_utility("certbot.display.ops.z_util")
def test_choose_names_user_cancel(self, mock_util):
items = ["first", "second", "third"]
question = "Want to cancel?"
mock_util().checklist.return_value = (display_util.CANCEL, [])
result = self._call(items, question)
self.assertEquals(result, [])
self.assertTrue(mock_util().checklist.called)
self.assertEquals(mock_util().checklist.call_args[0][0], question)
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -23,7 +23,6 @@ from certbot import configuration
from certbot import crypto_util
from certbot import errors
from certbot import main
from certbot import updater
from certbot import util
from certbot.plugins import disco
@@ -1233,9 +1232,7 @@ class MainTest(test_util.ConfigTestCase): # pylint: disable=too-many-public-met
self._test_renew_common(renewalparams=renewalparams, error_expected=True,
names=names, assert_oc_called=False)
@mock.patch('certbot.plugins.selection.choose_configurator_plugins')
def test_renew_with_configurator(self, mock_sel):
mock_sel.return_value = (mock.MagicMock(), mock.MagicMock())
def test_renew_with_configurator(self):
renewalparams = {'authenticator': 'webroot'}
self._test_renew_common(
renewalparams=renewalparams, assert_oc_called=True,
@@ -1451,18 +1448,6 @@ class MainTest(test_util.ConfigTestCase): # pylint: disable=too-many-public-met
email in mock_utility().add_message.call_args[0][0])
self.assertTrue(mock_handle.called)
@mock.patch('certbot.plugins.selection.choose_configurator_plugins')
def test_plugin_selection_error(self, mock_choose):
mock_choose.side_effect = errors.PluginSelectionError
self.assertRaises(errors.PluginSelectionError, main.renew_cert,
None, None, None)
with mock.patch('certbot.updater.logger.warning') as mock_log:
updater.run_generic_updaters(None, None, None)
self.assertTrue(mock_log.called)
self.assertTrue("Could not choose appropriate plugin for updaters"
in mock_log.call_args[0][0])
class UnregisterTest(unittest.TestCase):
def setUp(self):
@@ -1548,114 +1533,5 @@ class MakeOrVerifyNeededDirs(test_util.ConfigTestCase):
strict=self.config.strict_permissions)
class EnhanceTest(unittest.TestCase):
"""Tests for certbot.main.enhance."""
def setUp(self):
self.get_utility_patch = test_util.patch_get_utility()
self.mock_get_utility = self.get_utility_patch.start()
def tearDown(self):
self.get_utility_patch.stop()
def _call(self, args):
plugins = disco.PluginsRegistry.find_all()
config = configuration.NamespaceConfig(
cli.prepare_and_parse_args(plugins, args))
with mock.patch('certbot.cert_manager.get_certnames') as mock_certs:
mock_certs.return_value = ['example.com']
with mock.patch('certbot.cert_manager.domains_for_certname') as mock_dom:
mock_dom.return_value = ['example.com']
with mock.patch('certbot.main._init_le_client') as mock_init:
mock_client = mock.MagicMock()
mock_client.config = config
mock_init.return_value = mock_client
main.enhance(config, plugins)
return mock_client # returns the client
@mock.patch('certbot.main.plug_sel.record_chosen_plugins')
@mock.patch('certbot.cert_manager.lineage_for_certname')
@mock.patch('certbot.main.display_ops.choose_values')
@mock.patch('certbot.main._find_domains_or_certname')
def test_selection_question(self, mock_find, mock_choose, mock_lineage, _rec):
mock_lineage.return_value = mock.MagicMock(chain_path="/tmp/nonexistent")
mock_choose.return_value = ['example.com']
mock_find.return_value = (None, None)
with mock.patch('certbot.main.plug_sel.pick_installer') as mock_pick:
self._call(['enhance', '--redirect'])
self.assertTrue(mock_pick.called)
# Check that the message includes "enhancements"
self.assertTrue("enhancements" in mock_pick.call_args[0][3])
@mock.patch('certbot.main.plug_sel.record_chosen_plugins')
@mock.patch('certbot.cert_manager.lineage_for_certname')
@mock.patch('certbot.main.display_ops.choose_values')
@mock.patch('certbot.main._find_domains_or_certname')
def test_selection_auth_warning(self, mock_find, mock_choose, mock_lineage, _rec):
mock_lineage.return_value = mock.MagicMock(chain_path="/tmp/nonexistent")
mock_choose.return_value = ["example.com"]
mock_find.return_value = (None, None)
with mock.patch('certbot.main.plug_sel.pick_installer'):
with mock.patch('certbot.main.plug_sel.logger.warning') as mock_log:
mock_client = self._call(['enhance', '-a', 'webroot', '--redirect'])
self.assertTrue(mock_log.called)
self.assertTrue("make sense" in mock_log.call_args[0][0])
self.assertTrue(mock_client.enhance_config.called)
@mock.patch('certbot.cert_manager.lineage_for_certname')
@mock.patch('certbot.main.display_ops.choose_values')
@mock.patch('certbot.main.plug_sel.record_chosen_plugins')
def test_enhance_config_call(self, _rec, mock_choose, mock_lineage):
mock_lineage.return_value = mock.MagicMock(chain_path="/tmp/nonexistent")
mock_choose.return_value = ["example.com"]
with mock.patch('certbot.main.plug_sel.pick_installer'):
mock_client = self._call(['enhance', '--redirect', '--hsts'])
req_enh = ["redirect", "hsts"]
not_req_enh = ["uir"]
self.assertTrue(mock_client.enhance_config.called)
self.assertTrue(
all([getattr(mock_client.config, e) for e in req_enh]))
self.assertFalse(
any([getattr(mock_client.config, e) for e in not_req_enh]))
self.assertTrue(
"example.com" in mock_client.enhance_config.call_args[0][0])
@mock.patch('certbot.cert_manager.lineage_for_certname')
@mock.patch('certbot.main.display_ops.choose_values')
@mock.patch('certbot.main.plug_sel.record_chosen_plugins')
def test_enhance_noninteractive(self, _rec, mock_choose, mock_lineage):
mock_lineage.return_value = mock.MagicMock(
chain_path="/tmp/nonexistent")
mock_choose.return_value = ["example.com"]
with mock.patch('certbot.main.plug_sel.pick_installer'):
mock_client = self._call(['enhance', '--redirect',
'--hsts', '--non-interactive'])
self.assertTrue(mock_client.enhance_config.called)
self.assertFalse(mock_choose.called)
@mock.patch('certbot.main.display_ops.choose_values')
@mock.patch('certbot.main.plug_sel.record_chosen_plugins')
def test_user_abort_domains(self, _rec, mock_choose):
mock_choose.return_value = []
with mock.patch('certbot.main.plug_sel.pick_installer'):
self.assertRaises(errors.Error,
self._call,
['enhance', '--redirect', '--hsts'])
def test_no_enhancements_defined(self):
self.assertRaises(errors.MisconfigurationError,
self._call, ['enhance'])
@mock.patch('certbot.main.plug_sel.choose_configurator_plugins')
@mock.patch('certbot.main.display_ops.choose_values')
@mock.patch('certbot.main.plug_sel.record_chosen_plugins')
def test_plugin_selection_error(self, _rec, mock_choose, mock_pick):
mock_choose.return_value = ["example.com"]
mock_pick.return_value = (None, None)
mock_pick.side_effect = errors.PluginSelectionError()
mock_client = self._call(['enhance', '--hsts'])
self.assertFalse(mock_client.enhance_config.called)
if __name__ == '__main__':
unittest.main() # pragma: no cover

View File

@@ -1,76 +0,0 @@
"""Tests for renewal updater interfaces"""
import unittest
import mock
from certbot import interfaces
from certbot import main
from certbot import updater
import certbot.tests.util as test_util
class RenewUpdaterTest(unittest.TestCase):
"""Tests for interfaces.RenewDeployer and interfaces.GenericUpdater"""
def setUp(self):
class MockInstallerGenericUpdater(interfaces.GenericUpdater):
"""Mock class that implements GenericUpdater"""
def __init__(self, *args, **kwargs):
# pylint: disable=unused-argument
self.restart = mock.MagicMock()
self.callcounter = mock.MagicMock()
def generic_updates(self, domain, *args, **kwargs):
self.callcounter(*args, **kwargs)
class MockInstallerRenewDeployer(interfaces.RenewDeployer):
"""Mock class that implements RenewDeployer"""
def __init__(self, *args, **kwargs):
# pylint: disable=unused-argument
self.callcounter = mock.MagicMock()
def renew_deploy(self, lineage, *args, **kwargs):
self.callcounter(*args, **kwargs)
self.generic_updater = MockInstallerGenericUpdater()
self.renew_deployer = MockInstallerRenewDeployer()
def get_config(self, args):
"""Get mock config from dict of parameters"""
config = mock.MagicMock()
for key in args.keys():
config.__dict__[key] = args[key]
return config
@mock.patch('certbot.main._get_and_save_cert')
@mock.patch('certbot.plugins.selection.choose_configurator_plugins')
@test_util.patch_get_utility()
def test_server_updates(self, _, mock_select, mock_getsave):
config = self.get_config({"disable_renew_updates": False})
lineage = mock.MagicMock()
lineage.names.return_value = ['firstdomain', 'seconddomain']
mock_getsave.return_value = lineage
mock_generic_updater = self.generic_updater
# Generic Updater
mock_select.return_value = (mock_generic_updater, None)
with mock.patch('certbot.main._init_le_client'):
main.renew_cert(config, None, mock.MagicMock())
self.assertTrue(mock_generic_updater.restart.called)
mock_generic_updater.restart.reset_mock()
mock_generic_updater.callcounter.reset_mock()
updater.run_generic_updaters(config, None, lineage)
self.assertEqual(mock_generic_updater.callcounter.call_count, 2)
self.assertFalse(mock_generic_updater.restart.called)
def test_renew_deployer(self):
config = self.get_config({"disable_renew_updates": False})
lineage = mock.MagicMock()
lineage.names.return_value = ['firstdomain', 'seconddomain']
mock_deployer = self.renew_deployer
updater.run_renewal_deployer(lineage, mock_deployer, config)
self.assertTrue(mock_deployer.callcounter.called_with(lineage))
if __name__ == '__main__':
unittest.main() # pragma: no cover

View File

@@ -1,67 +0,0 @@
"""Updaters run at renewal"""
import logging
from certbot import errors
from certbot import interfaces
from certbot.plugins import selection as plug_sel
logger = logging.getLogger(__name__)
def run_generic_updaters(config, plugins, lineage):
"""Run updaters that the plugin supports
:param config: Configuration object
:type config: interfaces.IConfig
:param plugins: List of plugins
:type plugins: `list` of `str`
:param lineage: Certificate lineage object
:type lineage: storage.RenewableCert
:returns: `None`
:rtype: None
"""
try:
# installers are used in auth mode to determine domain names
installer, _ = plug_sel.choose_configurator_plugins(config, plugins, "certonly")
except errors.PluginSelectionError as e:
logger.warning("Could not choose appropriate plugin for updaters: %s", e)
return
_run_updaters(lineage, installer, config)
def run_renewal_deployer(lineage, installer, config):
"""Helper function to run deployer interface method if supported by the used
installer plugin.
:param lineage: Certificate lineage object
:type lineage: storage.RenewableCert
:param installer: Installer object
:type installer: interfaces.IInstaller
:returns: `None`
:rtype: None
"""
if not config.disable_renew_updates and isinstance(installer,
interfaces.RenewDeployer):
installer.renew_deploy(lineage)
def _run_updaters(lineage, installer, config):
"""Helper function to run the updater interface methods if supported by the
used installer plugin.
:param lineage: Certificate lineage object
:type lineage: storage.RenewableCert
:param installer: Installer object
:type installer: interfaces.IInstaller
:returns: `None`
:rtype: None
"""
for domain in lineage.names():
if not config.disable_renew_updates:
if isinstance(installer, interfaces.GenericUpdater):
installer.generic_updates(domain)

View File

@@ -54,7 +54,7 @@ _INITIAL_PID = os.getpid()
# the dict are attempted to be cleaned up at program exit. If the
# program exits before the lock is cleaned up, it is automatically
# released, but the file isn't deleted.
_LOCKS = OrderedDict() # type: OrderedDict[str, lock.LockFile]
_LOCKS = OrderedDict()
def run_script(params, log=logger.error):

View File

@@ -3,7 +3,3 @@
.. automodule:: certbot.constants
:members:
:exclude-members: SSL_DHPARAMS_SRC
.. autodata:: SSL_DHPARAMS_SRC
:annotation: = '/path/to/certbot/ssl-dhparams.pem'

View File

@@ -107,8 +107,8 @@ optional arguments:
case, and to know when to deprecate support for past
Python versions and flags. If you wish to hide this
information from the Let's Encrypt server, set this to
"". (default: CertbotACMEClient/0.23.0 (certbot;
darwin 10.13.4) Authenticator/XXX Installer/YYY
"". (default: CertbotACMEClient/0.22.2 (certbot;
darwin 10.13.3) Authenticator/XXX Installer/YYY
(SUBCOMMAND; flags: FLAGS) Py/2.7.14). The flags
encoded in the user agent are: --duplicate, --force-
renew, --allow-subset-of-names, -n, and whether any

View File

@@ -63,7 +63,7 @@ Find issues to work on
----------------------
You can find the open issues in the `github issue tracker`_. Comparatively
easy ones are marked `good first issue`_. If you're starting work on
easy ones are marked `Good Volunteer Task`_. If you're starting work on
something, post a comment to let others know and seek feedback on your plan
where appropriate.
@@ -72,7 +72,7 @@ your pull request must have thorough unit test coverage, pass our
tests, and be compliant with the :ref:`coding style <coding-style>`.
.. _github issue tracker: https://github.com/certbot/certbot/issues
.. _good first issue: https://github.com/certbot/certbot/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22
.. _Good Volunteer Task: https://github.com/certbot/certbot/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+Volunteer+Task%22
.. _testing:
@@ -376,9 +376,6 @@ commands:
This should generate documentation in the ``docs/_build/html``
directory.
.. note:: If you skipped the "Getting Started" instructions above,
run ``pip install -e ".[docs]"`` to install Certbot's docs extras modules.
.. _docker-dev:

View File

@@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.23.0"
LE_AUTO_VERSION="0.22.2"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -1199,18 +1199,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.23.0 \
--hash=sha256:66c42cf780ddbf582ecc52aa6a61242450a2650227b436ad0d260685c4ef8a49 \
--hash=sha256:6cff4c5da1228661ccaf95195064cb29e6cdf80913193bdb2eb20e164c76053e
acme==0.23.0 \
--hash=sha256:02e9b596bd3bf8f0733d6d43ec2464ac8185a000acb58d2b4fd9e19223bbbf0b \
--hash=sha256:08c16635578507f526c338b3418c1147a9f015bf2d366abd51f38918703b4550
certbot-apache==0.23.0 \
--hash=sha256:50077742d2763b7600dfda618eb89c870aeea5e6a4c00f60157877f7a7d81f7c \
--hash=sha256:6b7acec243e224de5268d46c2597277586dffa55e838c252b6931c30d549028e
certbot-nginx==0.23.0 \
--hash=sha256:f12c21bbe3eb955ca533f1da96d28c6310378b138e844d83253562e18b6cbb32 \
--hash=sha256:cadf14e4bd504d9ce5987a5ec6dbd8e136638e55303ad5dc81dcb723ddd64324
certbot==0.22.2 \
--hash=sha256:c8c63bdf0fed6258bdbc892454314ec37bcd1c35a7f62524a083d93ccdfc420d \
--hash=sha256:e6e3639293e78397f31f7d99e3c63aff82d91e2b0d50d146ee3c77f830464bef
acme==0.22.2 \
--hash=sha256:59a55244612ee305d2caa6bb4cddd400fb60ec841bf011ed29a2899832a682c2 \
--hash=sha256:0ecd0ea369f53d5bc744d6e72717f9af2e1ceb558d109dbd433148851027adb4
certbot-apache==0.22.2 \
--hash=sha256:b5340d4b9190358fde8eb6a5be0def37e32014b5142ee79ef5d2319ccbbde754 \
--hash=sha256:3cd26912bb5732d917ddf7aad2fe870090d4ece9a408b2c2de8e9723ec99c759
certbot-nginx==0.22.2 \
--hash=sha256:91feef0d879496835d355e82841f92e5ecb5abbf6f23ea0ee5bbb8f5a92b278a \
--hash=sha256:b10bf04c1a20cf878d5e0d1877deb0e0780bc31b0ffda08ce7199bbc39d0753b
UNLIKELY_EOF
# -------------------------------------------------------------------------

View File

@@ -1,11 +1,11 @@
-----BEGIN PGP SIGNATURE-----
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAlrFS/EACgkQTRfJlc2X
dfK+rQf8DcKY5bMi5eJnwwAlui6WIyWSrf1KAKt09tEGZSHQ1fcyCPrGVhk7VVDg
NJ1/XiYBquPW+7mYUcHrIRsiKYbTUcmVjyqP6tZd67IxRH9ToNqBzA6kq99T+IPd
iTGdczHMSPcxM6/Fa5PYMHXy2+ctTr/8+gnsxth9QfcM62Yd6ecfqIdoId3vk9Aw
UBMENZhUasIvgZDWuow+1XVZ/DAmdvj2Xl/E3sA9i2ArREJhkhVegtdrHkwSY+Hm
MKfZGqNVse6ZAF/8YdEVBum0OngMMs63DwucwFxmw5DqWtmnXm6awLNW/LQ/3R5L
xuKjcVaAT1h5TgIyRT6opH8JBKmLpg==
=Ouj4
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAlqwWJwACgkQTRfJlc2X
dfIzmwgAghmc3W63/qpCtJdezYeGLJdu03LvKoWYc7dTNYj2+0P5qmAAgCvKNY34
qYzXA1jfCOgILSzRNE5WY+rbgjcmxxsxH+luYm6Ik0909MaMQ0D3h+5cRFs/tTtd
5cX0gxL3RQQTBwpnwbAZibe7lhjs9pXBiob2ek67hVr+xEwem69BQMlOhtYJbOs1
osccoKc4NqaKbrfgOjjtMaL8YoRPO9vJHS9rRr6hxRZlPsmvusAHAiCbIrbX4XKE
CgxJFnuHK+amtfRoZg/xCqIK3Z94yZXPezywsri/YvDteOIs+DZ2qG/StfUrNYFX
WYfFFFyld0xwQtb4Oi9u4mx4sPg7lw==
=jZDE
-----END PGP SIGNATURE-----

View File

@@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.24.0.dev0"
LE_AUTO_VERSION="0.23.0.dev0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -1089,7 +1089,7 @@ cryptography==2.0.2 \
--hash=sha256:01e6e60654df64cca53733cda39446d67100c819c181d403afb120e0d2a71e1b \
--hash=sha256:d46f4e5d455cb5563685c52ef212696f0a6cc1ea627603218eabbd8a095291d8 \
--hash=sha256:3780b2663ee7ebb37cb83263326e3cd7f8b2ea439c448539d4b87de12c8d06ab
enum34==1.1.2 ; python_version < '3.4' \
enum34==1.1.2 \
--hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \
--hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501
funcsigs==1.0.2 \
@@ -1199,18 +1199,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.23.0 \
--hash=sha256:66c42cf780ddbf582ecc52aa6a61242450a2650227b436ad0d260685c4ef8a49 \
--hash=sha256:6cff4c5da1228661ccaf95195064cb29e6cdf80913193bdb2eb20e164c76053e
acme==0.23.0 \
--hash=sha256:02e9b596bd3bf8f0733d6d43ec2464ac8185a000acb58d2b4fd9e19223bbbf0b \
--hash=sha256:08c16635578507f526c338b3418c1147a9f015bf2d366abd51f38918703b4550
certbot-apache==0.23.0 \
--hash=sha256:50077742d2763b7600dfda618eb89c870aeea5e6a4c00f60157877f7a7d81f7c \
--hash=sha256:6b7acec243e224de5268d46c2597277586dffa55e838c252b6931c30d549028e
certbot-nginx==0.23.0 \
--hash=sha256:f12c21bbe3eb955ca533f1da96d28c6310378b138e844d83253562e18b6cbb32 \
--hash=sha256:cadf14e4bd504d9ce5987a5ec6dbd8e136638e55303ad5dc81dcb723ddd64324
certbot==0.22.2 \
--hash=sha256:c8c63bdf0fed6258bdbc892454314ec37bcd1c35a7f62524a083d93ccdfc420d \
--hash=sha256:e6e3639293e78397f31f7d99e3c63aff82d91e2b0d50d146ee3c77f830464bef
acme==0.22.2 \
--hash=sha256:59a55244612ee305d2caa6bb4cddd400fb60ec841bf011ed29a2899832a682c2 \
--hash=sha256:0ecd0ea369f53d5bc744d6e72717f9af2e1ceb558d109dbd433148851027adb4
certbot-apache==0.22.2 \
--hash=sha256:b5340d4b9190358fde8eb6a5be0def37e32014b5142ee79ef5d2319ccbbde754 \
--hash=sha256:3cd26912bb5732d917ddf7aad2fe870090d4ece9a408b2c2de8e9723ec99c759
certbot-nginx==0.22.2 \
--hash=sha256:91feef0d879496835d355e82841f92e5ecb5abbf6f23ea0ee5bbb8f5a92b278a \
--hash=sha256:b10bf04c1a20cf878d5e0d1877deb0e0780bc31b0ffda08ce7199bbc39d0753b
UNLIKELY_EOF
# -------------------------------------------------------------------------

View File

@@ -1,12 +1,12 @@
certbot==0.23.0 \
--hash=sha256:66c42cf780ddbf582ecc52aa6a61242450a2650227b436ad0d260685c4ef8a49 \
--hash=sha256:6cff4c5da1228661ccaf95195064cb29e6cdf80913193bdb2eb20e164c76053e
acme==0.23.0 \
--hash=sha256:02e9b596bd3bf8f0733d6d43ec2464ac8185a000acb58d2b4fd9e19223bbbf0b \
--hash=sha256:08c16635578507f526c338b3418c1147a9f015bf2d366abd51f38918703b4550
certbot-apache==0.23.0 \
--hash=sha256:50077742d2763b7600dfda618eb89c870aeea5e6a4c00f60157877f7a7d81f7c \
--hash=sha256:6b7acec243e224de5268d46c2597277586dffa55e838c252b6931c30d549028e
certbot-nginx==0.23.0 \
--hash=sha256:f12c21bbe3eb955ca533f1da96d28c6310378b138e844d83253562e18b6cbb32 \
--hash=sha256:cadf14e4bd504d9ce5987a5ec6dbd8e136638e55303ad5dc81dcb723ddd64324
certbot==0.22.2 \
--hash=sha256:c8c63bdf0fed6258bdbc892454314ec37bcd1c35a7f62524a083d93ccdfc420d \
--hash=sha256:e6e3639293e78397f31f7d99e3c63aff82d91e2b0d50d146ee3c77f830464bef
acme==0.22.2 \
--hash=sha256:59a55244612ee305d2caa6bb4cddd400fb60ec841bf011ed29a2899832a682c2 \
--hash=sha256:0ecd0ea369f53d5bc744d6e72717f9af2e1ceb558d109dbd433148851027adb4
certbot-apache==0.22.2 \
--hash=sha256:b5340d4b9190358fde8eb6a5be0def37e32014b5142ee79ef5d2319ccbbde754 \
--hash=sha256:3cd26912bb5732d917ddf7aad2fe870090d4ece9a408b2c2de8e9723ec99c759
certbot-nginx==0.22.2 \
--hash=sha256:91feef0d879496835d355e82841f92e5ecb5abbf6f23ea0ee5bbb8f5a92b278a \
--hash=sha256:b10bf04c1a20cf878d5e0d1877deb0e0780bc31b0ffda08ce7199bbc39d0753b

View File

@@ -93,7 +93,7 @@ cryptography==2.0.2 \
--hash=sha256:01e6e60654df64cca53733cda39446d67100c819c181d403afb120e0d2a71e1b \
--hash=sha256:d46f4e5d455cb5563685c52ef212696f0a6cc1ea627603218eabbd8a095291d8 \
--hash=sha256:3780b2663ee7ebb37cb83263326e3cd7f8b2ea439c448539d4b87de12c8d06ab
enum34==1.1.2 ; python_version < '3.4' \
enum34==1.1.2 \
--hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \
--hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501
funcsigs==1.0.2 \

View File

@@ -1,3 +0,0 @@
[mypy]
python_version = 2.7
ignore_missing_imports = True

2
pytest.ini Normal file
View File

@@ -0,0 +1,2 @@
[pytest]
addopts = --quiet

View File

@@ -34,7 +34,9 @@ version = meta['version']
# specified here to avoid masking the more specific request requirements in
# acme. See https://github.com/pypa/pip/issues/988 for more info.
install_requires = [
'acme>=0.22.1',
# Remember to update local-oldest-requirements.txt when changing the
# minimum acme version.
'acme>0.21.1',
# We technically need ConfigArgParse 0.10.0 for Python 2.6 support, but
# saying so here causes a runtime error against our temporary fork of 0.9.3
# in which we added 2.6 support (see #2243), so we relax the requirement.
@@ -65,10 +67,6 @@ dev_extras = [
'wheel',
]
dev3_extras = [
'mypy',
]
docs_extras = [
'repoze.sphinx.autointerface',
# autodoc_member_order = 'bysource', autodoc_default_flags, and #4686
@@ -114,7 +112,6 @@ setup(
install_requires=install_requires,
extras_require={
'dev': dev_extras,
'dev3': dev3_extras,
'docs': docs_extras,
},

View File

@@ -1,6 +1,16 @@
targets:
#-----------------------------------------------------------------------------
#Ubuntu
- ami: ami-26d5af4c
name: ubuntu15.10
type: ubuntu
virt: hvm
user: ubuntu
- ami: ami-d92e6bb3
name: ubuntu15.04LTS
type: ubuntu
virt: hvm
user: ubuntu
- ami: ami-7b89cc11
name: ubuntu14.04LTS
type: ubuntu
@@ -11,6 +21,11 @@ targets:
type: ubuntu
virt: pv
user: ubuntu
- ami: ami-0611546c
name: ubuntu12.04LTS
type: ubuntu
virt: hvm
user: ubuntu
#-----------------------------------------------------------------------------
# Debian
- ami: ami-116d857a

View File

@@ -30,7 +30,6 @@ josepy==1.0.1
logger==1.4
logilab-common==1.4.1
MarkupSafe==1.0
mypy==0.580
ndg-httpsclient==0.3.2
oauth2client==2.0.0
pathlib2==2.3.0
@@ -67,8 +66,6 @@ tox==2.9.1
tqdm==4.19.4
traitlets==4.3.2
twine==1.9.1
typed-ast==1.1.0
typing==3.6.4
uritemplate==0.6
virtualenv==15.1.0
wcwidth==0.1.7

View File

@@ -19,5 +19,5 @@ for requirement in "$@" ; do
if [ $pkg = "." ]; then
pkg="certbot"
fi
pytest --numprocesses auto --quiet --pyargs $pkg
"$(dirname $0)/pytest.sh" --pyargs $pkg
done

15
tools/pytest.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
# Runs pytest with the provided arguments, adding --numprocesses to the command
# line. This argument is set to "auto" if the environmnent variable TRAVIS is
# not set, otherwise, it is set to 2. This works around
# https://github.com/pytest-dev/pytest-xdist/issues/9. Currently every Travis
# environnment provides two cores. See
# https://docs.travis-ci.com/user/reference/overview/#Virtualization-environments.
if ${TRAVIS:-false}; then
NUMPROCESSES="2"
else
NUMPROCESSES="auto"
fi
pytest --numprocesses "$NUMPROCESSES" "$@"

View File

@@ -51,7 +51,8 @@ cover () {
fi
pkg_dir=$(echo "$1" | tr _ -)
pytest --cov "$pkg_dir" --cov-append --cov-report= --numprocesses auto --pyargs "$1"
pytest="$(dirname $0)/tools/pytest.sh"
"$pytest" --cov "$pkg_dir" --cov-append --cov-report= --pyargs "$1"
coverage report --fail-under="$min" --include="$pkg_dir/*" --show-missing
}

22
tox.ini
View File

@@ -60,6 +60,8 @@ commands =
setenv =
PYTHONPATH = {toxinidir}
PYTHONHASHSEED = 0
passenv =
TRAVIS
[testenv:py27-oldest]
commands =
@@ -67,30 +69,40 @@ commands =
setenv =
{[testenv]setenv}
CERTBOT_OLDEST=1
passenv =
{[testenv]passenv}
[testenv:py27-acme-oldest]
commands =
{[base]install_and_test} acme[dev]
setenv =
{[testenv:py27-oldest]setenv}
passenv =
{[testenv:py27-oldest]passenv}
[testenv:py27-apache-oldest]
commands =
{[base]install_and_test} certbot-apache
setenv =
{[testenv:py27-oldest]setenv}
passenv =
{[testenv:py27-oldest]passenv}
[testenv:py27-certbot-oldest]
commands =
{[base]install_and_test} .[dev]
setenv =
{[testenv:py27-oldest]setenv}
passenv =
{[testenv:py27-oldest]passenv}
[testenv:py27-dns-oldest]
commands =
{[base]install_and_test} {[base]dns_packages}
setenv =
{[testenv:py27-oldest]setenv}
passenv =
{[testenv:py27-oldest]passenv}
[testenv:py27-nginx-oldest]
commands =
@@ -98,6 +110,8 @@ commands =
python tests/lock_test.py
setenv =
{[testenv:py27-oldest]setenv}
passenv =
{[testenv:py27-oldest]passenv}
[testenv:py27_install]
basepython = python2.7
@@ -109,6 +123,8 @@ basepython = python2.7
commands =
{[base]install_packages}
./tox.cover.sh
passenv =
{[testenv]passenv}
[testenv:lint]
basepython = python2.7
@@ -120,11 +136,11 @@ commands =
pylint --reports=n --rcfile=.pylintrc {[base]source_paths}
[testenv:mypy]
basepython = python3
basepython = python3.4
commands =
{[base]pip_install} .[dev3]
{[base]pip_install} mypy
{[base]install_packages}
mypy {[base]source_paths}
mypy --py2 --ignore-missing-imports {[base]source_paths}
[testenv:apacheconftest]
#basepython = python2.7