mirror of
https://github.com/certbot/certbot.git
synced 2026-08-01 02:35:06 +02:00
Lint certbot code on Python 3, and update Pylint to the latest version (#7551)
Part of #7550 This PR makes appropriate corrections to run pylint on Python 3. Why not keeping the dependencies unchanged and just run pylint on Python 3? Because the old version of pylint breaks horribly on Python 3 because of unsupported version of astroid. Why updating pylint + astroid to the latest version ? Because this version only fixes some internal errors occuring during the lint of Certbot code, and is also ready to run gracefully on Python 3.8. Why upgrading mypy ? Because the old version does not support the new version of astroid required to run pylint correctly. Why not upgrading mypy to its latest version ? Because this latest version includes a new typshed version, that adds a lot of new type definitions, and brings dozens of new errors on the Certbot codebase. I would like to fix that in a future PR. That said so, the work has been to find the correct set of new dependency versions, then configure pylint for sane configuration errors in our situation, disable irrelevant lintings errors, then fixing (or ignoring for good reason) the remaining mypy errors. I also made PyLint and MyPy checks run correctly on Windows. * Start configuration * Reconfigure travis * Suspend a check specific to python 3. Start fixing code. * Repair call_args * Fix return + elif lints * Reconfigure development to run mainly on python3 * Remove incompatible Python 3.4 jobs * Suspend pylint in some assertions * Remove pylint in dev * Take first mypy that supports typed-ast>=1.4.0 to limit the migration path * Various return + else lint errors * Find a set of deps that is working with current mypy version * Update local oldest requirements * Remove all current pylint errors * Rebuild letsencrypt-auto * Update mypy to fix pylint with new astroid version, and fix mypy issues * Explain type: ignore * Reconfigure tox, fix none path * Simplify pinning * Remove useless directive * Remove debugging code * Remove continue * Update requirements * Disable unsubscriptable-object check * Disable one check, enabling two more * Plug certbot dev version for oldest requirements * Remove useless disable directives * Remove useless no-member disable * Remove no-else-* checks. Use elif in symetric branches. * Add back assertion * Add new line * Remove unused pylint disable * Remove other pylint disable
This commit is contained in:
committed by
Brad Warren
parent
e048da1e38
commit
9e5bca4bbf
@@ -24,6 +24,11 @@ persistent=yes
|
|||||||
# usually to register additional checkers.
|
# usually to register additional checkers.
|
||||||
load-plugins=linter_plugin
|
load-plugins=linter_plugin
|
||||||
|
|
||||||
|
# A comma-separated list of package or module names from where C extensions may
|
||||||
|
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||||
|
# run arbitrary code.
|
||||||
|
extension-pkg-whitelist=pywintypes,win32api,win32file,win32security
|
||||||
|
|
||||||
|
|
||||||
[MESSAGES CONTROL]
|
[MESSAGES CONTROL]
|
||||||
|
|
||||||
@@ -41,10 +46,14 @@ load-plugins=linter_plugin
|
|||||||
# --enable=similarities". If you want to run only the classes checker, but have
|
# --enable=similarities". If you want to run only the classes checker, but have
|
||||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||||
# --disable=W"
|
# --disable=W"
|
||||||
disable=fixme,locally-disabled,locally-enabled,abstract-class-not-used,abstract-class-little-used,bad-continuation,no-self-use,invalid-name,cyclic-import,duplicate-code,design
|
# CERTBOT COMMENT
|
||||||
# abstract-class-not-used cannot be disabled locally (at least in
|
# 1) Once certbot codebase is claimed to be compatible exclusively with Python 3,
|
||||||
# pylint 1.4.1), same for abstract-class-little-used
|
# the useless-object-inheritance check can be enabled again, and code fixed accordingly.
|
||||||
|
# 2) Check unsubscriptable-object tends to create a lot of false positives. Let's disable it.
|
||||||
|
# See https://github.com/PyCQA/pylint/issues/1498.
|
||||||
|
# 3) Same as point 2 for no-value-for-parameter.
|
||||||
|
# See https://github.com/PyCQA/pylint/issues/2820.
|
||||||
|
disable=fixme,locally-disabled,locally-enabled,bad-continuation,no-self-use,invalid-name,cyclic-import,duplicate-code,design,import-outside-toplevel,useless-object-inheritance,unsubscriptable-object,no-value-for-parameter,no-else-return,no-else-raise,no-else-break,no-else-continue
|
||||||
|
|
||||||
[REPORTS]
|
[REPORTS]
|
||||||
|
|
||||||
|
|||||||
+1
-4
@@ -46,12 +46,9 @@ matrix:
|
|||||||
- python: "2.7"
|
- python: "2.7"
|
||||||
env: TOXENV=py27-cover FYI="py27 tests + code coverage"
|
env: TOXENV=py27-cover FYI="py27 tests + code coverage"
|
||||||
|
|
||||||
- python: "2.7"
|
- python: "3.7"
|
||||||
env: TOXENV=lint
|
env: TOXENV=lint
|
||||||
<<: *not-on-master
|
<<: *not-on-master
|
||||||
- python: "3.4"
|
|
||||||
env: TOXENV=mypy
|
|
||||||
<<: *not-on-master
|
|
||||||
- python: "3.5"
|
- python: "3.5"
|
||||||
env: TOXENV=mypy
|
env: TOXENV=mypy
|
||||||
<<: *not-on-master
|
<<: *not-on-master
|
||||||
|
|||||||
+4
-5
@@ -6,16 +6,15 @@ EXPOSE 80 443
|
|||||||
|
|
||||||
WORKDIR /opt/certbot/src
|
WORKDIR /opt/certbot/src
|
||||||
|
|
||||||
# TODO: Install Apache/Nginx for plugin development.
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install apache2 git nginx-light -y && \
|
apt-get install apache2 git python3-dev python3-venv gcc libaugeas0 \
|
||||||
letsencrypt-auto-source/letsencrypt-auto --os-packages-only && \
|
libssl-dev libffi-dev ca-certificates openssl nginx-light -y && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
rm -rf /var/lib/apt/lists/* \
|
rm -rf /var/lib/apt/lists/* \
|
||||||
/tmp/* \
|
/tmp/* \
|
||||||
/var/tmp/*
|
/var/tmp/*
|
||||||
|
|
||||||
RUN VENV_NAME="../venv" python tools/venv.py
|
RUN VENV_NAME="../venv3" python3 tools/venv3.py
|
||||||
|
|
||||||
ENV PATH /opt/certbot/venv/bin:$PATH
|
ENV PATH /opt/certbot/venv3/bin:$PATH
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ class UnrecognizedChallenge(Challenge):
|
|||||||
object.__setattr__(self, "jobj", jobj)
|
object.__setattr__(self, "jobj", jobj)
|
||||||
|
|
||||||
def to_partial_json(self):
|
def to_partial_json(self):
|
||||||
# pylint: disable=no-member
|
return self.jobj # pylint: disable=no-member
|
||||||
return self.jobj
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, jobj):
|
def from_json(cls, jobj):
|
||||||
@@ -113,7 +112,7 @@ class KeyAuthorizationChallengeResponse(ChallengeResponse):
|
|||||||
:rtype: bool
|
:rtype: bool
|
||||||
|
|
||||||
"""
|
"""
|
||||||
parts = self.key_authorization.split('.') # pylint: disable=no-member
|
parts = self.key_authorization.split('.')
|
||||||
if len(parts) != 2:
|
if len(parts) != 2:
|
||||||
logger.debug("Key authorization (%r) is not well formed",
|
logger.debug("Key authorization (%r) is not well formed",
|
||||||
self.key_authorization)
|
self.key_authorization)
|
||||||
|
|||||||
+5
-11
@@ -34,7 +34,6 @@ logger = logging.getLogger(__name__)
|
|||||||
# https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning
|
# https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning
|
||||||
if sys.version_info < (2, 7, 9): # pragma: no cover
|
if sys.version_info < (2, 7, 9): # pragma: no cover
|
||||||
try:
|
try:
|
||||||
# pylint: disable=no-member
|
|
||||||
requests.packages.urllib3.contrib.pyopenssl.inject_into_urllib3() # type: ignore
|
requests.packages.urllib3.contrib.pyopenssl.inject_into_urllib3() # type: ignore
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
import urllib3.contrib.pyopenssl # pylint: disable=import-error
|
import urllib3.contrib.pyopenssl # pylint: disable=import-error
|
||||||
@@ -280,7 +279,6 @@ class Client(ClientBase):
|
|||||||
assert response.status_code == http_client.CREATED
|
assert response.status_code == http_client.CREATED
|
||||||
|
|
||||||
# "Instance of 'Field' has no key/contact member" bug:
|
# "Instance of 'Field' has no key/contact member" bug:
|
||||||
# pylint: disable=no-member
|
|
||||||
return self._regr_from_response(response)
|
return self._regr_from_response(response)
|
||||||
|
|
||||||
def query_registration(self, regr):
|
def query_registration(self, regr):
|
||||||
@@ -465,7 +463,6 @@ class Client(ClientBase):
|
|||||||
updated[authzr] = updated_authzr
|
updated[authzr] = updated_authzr
|
||||||
|
|
||||||
attempts[authzr] += 1
|
attempts[authzr] += 1
|
||||||
# pylint: disable=no-member
|
|
||||||
if updated_authzr.body.status not in (
|
if updated_authzr.body.status not in (
|
||||||
messages.STATUS_VALID, messages.STATUS_INVALID):
|
messages.STATUS_VALID, messages.STATUS_INVALID):
|
||||||
if attempts[authzr] < max_attempts:
|
if attempts[authzr] < max_attempts:
|
||||||
@@ -606,7 +603,6 @@ class ClientV2(ClientBase):
|
|||||||
if response.status_code == 200 and 'Location' in response.headers:
|
if response.status_code == 200 and 'Location' in response.headers:
|
||||||
raise errors.ConflictError(response.headers.get('Location'))
|
raise errors.ConflictError(response.headers.get('Location'))
|
||||||
# "Instance of 'Field' has no key/contact member" bug:
|
# "Instance of 'Field' has no key/contact member" bug:
|
||||||
# pylint: disable=no-member
|
|
||||||
regr = self._regr_from_response(response)
|
regr = self._regr_from_response(response)
|
||||||
self.net.account = regr
|
self.net.account = regr
|
||||||
return regr
|
return regr
|
||||||
@@ -730,7 +726,7 @@ class ClientV2(ClientBase):
|
|||||||
for authzr in responses:
|
for authzr in responses:
|
||||||
if authzr.body.status != messages.STATUS_VALID:
|
if authzr.body.status != messages.STATUS_VALID:
|
||||||
for chall in authzr.body.challenges:
|
for chall in authzr.body.challenges:
|
||||||
if chall.error != None:
|
if chall.error is not None:
|
||||||
failed.append(authzr)
|
failed.append(authzr)
|
||||||
if failed:
|
if failed:
|
||||||
raise errors.ValidationError(failed)
|
raise errors.ValidationError(failed)
|
||||||
@@ -1125,10 +1121,9 @@ class ClientNetwork(object):
|
|||||||
err_regex = r".*host='(\S*)'.*Max retries exceeded with url\: (\/\w*).*(\[Errno \d+\])([A-Za-z ]*)"
|
err_regex = r".*host='(\S*)'.*Max retries exceeded with url\: (\/\w*).*(\[Errno \d+\])([A-Za-z ]*)"
|
||||||
m = re.match(err_regex, str(e))
|
m = re.match(err_regex, str(e))
|
||||||
if m is None:
|
if m is None:
|
||||||
raise # pragma: no cover
|
raise # pragma: no cover
|
||||||
else:
|
host, path, _err_no, err_msg = m.groups()
|
||||||
host, path, _err_no, err_msg = m.groups()
|
raise ValueError("Requesting {0}{1}:{2}".format(host, path, err_msg))
|
||||||
raise ValueError("Requesting {0}{1}:{2}".format(host, path, err_msg))
|
|
||||||
|
|
||||||
# If content is DER, log the base64 of it instead of raw bytes, to keep
|
# If content is DER, log the base64 of it instead of raw bytes, to keep
|
||||||
# binary data out of the logs.
|
# binary data out of the logs.
|
||||||
@@ -1194,8 +1189,7 @@ class ClientNetwork(object):
|
|||||||
if error.code == 'badNonce':
|
if error.code == 'badNonce':
|
||||||
logger.debug('Retrying request after error:\n%s', error)
|
logger.debug('Retrying request after error:\n%s', error)
|
||||||
return self._post_once(*args, **kwargs)
|
return self._post_once(*args, **kwargs)
|
||||||
else:
|
raise
|
||||||
raise
|
|
||||||
|
|
||||||
def _post_once(self, url, obj, content_type=JOSE_CONTENT_TYPE,
|
def _post_once(self, url, obj, content_type=JOSE_CONTENT_TYPE,
|
||||||
acme_version=1, **kwargs):
|
acme_version=1, **kwargs):
|
||||||
|
|||||||
+13
-3
@@ -29,7 +29,12 @@ class NonceError(ClientError):
|
|||||||
class BadNonce(NonceError):
|
class BadNonce(NonceError):
|
||||||
"""Bad nonce error."""
|
"""Bad nonce error."""
|
||||||
def __init__(self, nonce, error, *args, **kwargs):
|
def __init__(self, nonce, error, *args, **kwargs):
|
||||||
super(BadNonce, self).__init__(*args, **kwargs)
|
# MyPy complains here that there is too many arguments for BaseException constructor.
|
||||||
|
# This is an error fixed in typeshed, see https://github.com/python/mypy/issues/4183
|
||||||
|
# The fix is included in MyPy>=0.740, but upgrading it would bring dozen of errors due to
|
||||||
|
# new types definitions. So we ignore the error until the code base is fixed to match
|
||||||
|
# with MyPy>=0.740 referential.
|
||||||
|
super(BadNonce, self).__init__(*args, **kwargs) # type: ignore
|
||||||
self.nonce = nonce
|
self.nonce = nonce
|
||||||
self.error = error
|
self.error = error
|
||||||
|
|
||||||
@@ -48,7 +53,8 @@ class MissingNonce(NonceError):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, response, *args, **kwargs):
|
def __init__(self, response, *args, **kwargs):
|
||||||
super(MissingNonce, self).__init__(*args, **kwargs)
|
# See comment in BadNonce constructor above for an explanation of type: ignore here.
|
||||||
|
super(MissingNonce, self).__init__(*args, **kwargs) # type: ignore
|
||||||
self.response = response
|
self.response = response
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -83,6 +89,7 @@ class PollError(ClientError):
|
|||||||
return '{0}(exhausted={1!r}, updated={2!r})'.format(
|
return '{0}(exhausted={1!r}, updated={2!r})'.format(
|
||||||
self.__class__.__name__, self.exhausted, self.updated)
|
self.__class__.__name__, self.exhausted, self.updated)
|
||||||
|
|
||||||
|
|
||||||
class ValidationError(Error):
|
class ValidationError(Error):
|
||||||
"""Error for authorization failures. Contains a list of authorization
|
"""Error for authorization failures. Contains a list of authorization
|
||||||
resources, each of which is invalid and should have an error field.
|
resources, each of which is invalid and should have an error field.
|
||||||
@@ -91,9 +98,11 @@ class ValidationError(Error):
|
|||||||
self.failed_authzrs = failed_authzrs
|
self.failed_authzrs = failed_authzrs
|
||||||
super(ValidationError, self).__init__()
|
super(ValidationError, self).__init__()
|
||||||
|
|
||||||
class TimeoutError(Error):
|
|
||||||
|
class TimeoutError(Error): # pylint: disable=redefined-builtin
|
||||||
"""Error for when polling an authorization or an order times out."""
|
"""Error for when polling an authorization or an order times out."""
|
||||||
|
|
||||||
|
|
||||||
class IssuanceError(Error):
|
class IssuanceError(Error):
|
||||||
"""Error sent by the server after requesting issuance of a certificate."""
|
"""Error sent by the server after requesting issuance of a certificate."""
|
||||||
|
|
||||||
@@ -105,6 +114,7 @@ class IssuanceError(Error):
|
|||||||
self.error = error
|
self.error = error
|
||||||
super(IssuanceError, self).__init__()
|
super(IssuanceError, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
class ConflictError(ClientError):
|
class ConflictError(ClientError):
|
||||||
"""Error for when the server returns a 409 (Conflict) HTTP status.
|
"""Error for when the server returns a 409 (Conflict) HTTP status.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ class Signature(jose.Signature):
|
|||||||
class JWS(jose.JWS):
|
class JWS(jose.JWS):
|
||||||
"""ACME-specific JWS. Includes none, url, and kid in protected header."""
|
"""ACME-specific JWS. Includes none, url, and kid in protected header."""
|
||||||
signature_cls = Signature
|
signature_cls = Signature
|
||||||
__slots__ = jose.JWS._orig_slots # pylint: disable=no-member
|
__slots__ = jose.JWS._orig_slots
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
# pylint: disable=arguments-differ
|
# pylint: disable=arguments-differ
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ class _Constant(jose.JSONDeSerializable, Hashable): # type: ignore
|
|||||||
if jobj not in cls.POSSIBLE_NAMES: # pylint: disable=unsupported-membership-test
|
if jobj not in cls.POSSIBLE_NAMES: # pylint: disable=unsupported-membership-test
|
||||||
raise jose.DeserializationError(
|
raise jose.DeserializationError(
|
||||||
'{0} not recognized'.format(cls.__name__))
|
'{0} not recognized'.format(cls.__name__))
|
||||||
return cls.POSSIBLE_NAMES[jobj] # pylint: disable=unsubscriptable-object
|
return cls.POSSIBLE_NAMES[jobj]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '{0}({1})'.format(self.__class__.__name__, self.name)
|
return '{0}({1})'.format(self.__class__.__name__, self.name)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class TLSServer(socketserver.TCPServer):
|
|||||||
return socketserver.TCPServer.server_bind(self)
|
return socketserver.TCPServer.server_bind(self)
|
||||||
|
|
||||||
|
|
||||||
class ACMEServerMixin: # pylint: disable=old-style-class
|
class ACMEServerMixin:
|
||||||
"""ACME server common settings mixin."""
|
"""ACME server common settings mixin."""
|
||||||
# TODO: c.f. #858
|
# TODO: c.f. #858
|
||||||
server_version = "ACME client standalone challenge solver"
|
server_version = "ACME client standalone challenge solver"
|
||||||
@@ -105,7 +105,6 @@ class BaseDualNetworkedServers(object):
|
|||||||
"""Wraps socketserver.TCPServer.serve_forever"""
|
"""Wraps socketserver.TCPServer.serve_forever"""
|
||||||
for server in self.servers:
|
for server in self.servers:
|
||||||
thread = threading.Thread(
|
thread = threading.Thread(
|
||||||
# pylint: disable=no-member
|
|
||||||
target=server.serve_forever)
|
target=server.serve_forever)
|
||||||
thread.start()
|
thread.start()
|
||||||
self.threads.append(thread)
|
self.threads.append(thread)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import unittest
|
|||||||
import josepy as jose
|
import josepy as jose
|
||||||
import mock
|
import mock
|
||||||
import requests
|
import requests
|
||||||
from six.moves.urllib import parse as urllib_parse # pylint: disable=relative-import
|
from six.moves.urllib import parse as urllib_parse
|
||||||
|
|
||||||
import test_util
|
import test_util
|
||||||
|
|
||||||
@@ -18,7 +18,6 @@ class ChallengeTest(unittest.TestCase):
|
|||||||
from acme.challenges import Challenge
|
from acme.challenges import Challenge
|
||||||
from acme.challenges import UnrecognizedChallenge
|
from acme.challenges import UnrecognizedChallenge
|
||||||
chall = UnrecognizedChallenge({"type": "foo"})
|
chall = UnrecognizedChallenge({"type": "foo"})
|
||||||
# pylint: disable=no-member
|
|
||||||
self.assertEqual(chall, Challenge.from_json(chall.jobj))
|
self.assertEqual(chall, Challenge.from_json(chall.jobj))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class ClientTestBase(unittest.TestCase):
|
|||||||
self.contact = ('mailto:cert-admin@example.com', 'tel:+12025551212')
|
self.contact = ('mailto:cert-admin@example.com', 'tel:+12025551212')
|
||||||
reg = messages.Registration(
|
reg = messages.Registration(
|
||||||
contact=self.contact, key=KEY.public_key())
|
contact=self.contact, key=KEY.public_key())
|
||||||
the_arg = dict(reg) # type: Dict
|
the_arg = dict(reg) # type: Dict
|
||||||
self.new_reg = messages.NewRegistration(**the_arg)
|
self.new_reg = messages.NewRegistration(**the_arg)
|
||||||
self.regr = messages.RegistrationResource(
|
self.regr = messages.RegistrationResource(
|
||||||
body=reg, uri='https://www.letsencrypt-demo.org/acme/reg/1')
|
body=reg, uri='https://www.letsencrypt-demo.org/acme/reg/1')
|
||||||
@@ -963,8 +963,8 @@ class ClientNetworkTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_check_response_not_ok_jobj_error(self):
|
def test_check_response_not_ok_jobj_error(self):
|
||||||
self.response.ok = False
|
self.response.ok = False
|
||||||
self.response.json.return_value = messages.Error(
|
self.response.json.return_value = messages.Error.with_code(
|
||||||
detail='foo', typ='serverInternal', title='some title').to_json()
|
'serverInternal', detail='foo', title='some title').to_json()
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
messages.Error, self.net._check_response, self.response)
|
messages.Error, self.net._check_response, self.response)
|
||||||
@@ -989,7 +989,7 @@ class ClientNetworkTest(unittest.TestCase):
|
|||||||
self.response.json.side_effect = ValueError
|
self.response.json.side_effect = ValueError
|
||||||
for response_ct in [self.net.JSON_CONTENT_TYPE, 'foo']:
|
for response_ct in [self.net.JSON_CONTENT_TYPE, 'foo']:
|
||||||
self.response.headers['Content-Type'] = response_ct
|
self.response.headers['Content-Type'] = response_ct
|
||||||
# pylint: disable=protected-access,no-value-for-parameter
|
# pylint: disable=protected-access
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.response, self.net._check_response(self.response))
|
self.response, self.net._check_response(self.response))
|
||||||
|
|
||||||
@@ -1003,7 +1003,7 @@ class ClientNetworkTest(unittest.TestCase):
|
|||||||
self.response.json.return_value = {}
|
self.response.json.return_value = {}
|
||||||
for response_ct in [self.net.JSON_CONTENT_TYPE, 'foo']:
|
for response_ct in [self.net.JSON_CONTENT_TYPE, 'foo']:
|
||||||
self.response.headers['Content-Type'] = response_ct
|
self.response.headers['Content-Type'] = response_ct
|
||||||
# pylint: disable=protected-access,no-value-for-parameter
|
# pylint: disable=protected-access
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.response, self.net._check_response(self.response))
|
self.response, self.net._check_response(self.response))
|
||||||
|
|
||||||
@@ -1128,8 +1128,8 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase):
|
|||||||
self.response.headers = {}
|
self.response.headers = {}
|
||||||
self.response.links = {}
|
self.response.links = {}
|
||||||
self.response.checked = False
|
self.response.checked = False
|
||||||
self.acmev1_nonce_response = mock.MagicMock(ok=False,
|
self.acmev1_nonce_response = mock.MagicMock(
|
||||||
status_code=http_client.METHOD_NOT_ALLOWED)
|
ok=False, status_code=http_client.METHOD_NOT_ALLOWED)
|
||||||
self.acmev1_nonce_response.headers = {}
|
self.acmev1_nonce_response.headers = {}
|
||||||
self.obj = mock.MagicMock()
|
self.obj = mock.MagicMock()
|
||||||
self.wrapped_obj = mock.MagicMock()
|
self.wrapped_obj = mock.MagicMock()
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ class SSLSocketAndProbeSNITest(unittest.TestCase):
|
|||||||
self.server = _TestServer(('', 0), socketserver.BaseRequestHandler)
|
self.server = _TestServer(('', 0), socketserver.BaseRequestHandler)
|
||||||
self.port = self.server.socket.getsockname()[1]
|
self.port = self.server.socket.getsockname()[1]
|
||||||
self.server_thread = threading.Thread(
|
self.server_thread = threading.Thread(
|
||||||
# pylint: disable=no-member
|
|
||||||
target=self.server.handle_request)
|
target=self.server.handle_request)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
@@ -65,7 +64,7 @@ class SSLSocketAndProbeSNITest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_probe_connection_error(self):
|
def test_probe_connection_error(self):
|
||||||
# pylint has a hard time with six
|
# pylint has a hard time with six
|
||||||
self.server.server_close() # pylint: disable=no-member
|
self.server.server_close()
|
||||||
original_timeout = socket.getdefaulttimeout()
|
original_timeout = socket.getdefaulttimeout()
|
||||||
try:
|
try:
|
||||||
socket.setdefaulttimeout(1)
|
socket.setdefaulttimeout(1)
|
||||||
|
|||||||
@@ -21,11 +21,10 @@ class JoseTest(unittest.TestCase):
|
|||||||
|
|
||||||
# We use the imports below with eval, but pylint doesn't
|
# We use the imports below with eval, but pylint doesn't
|
||||||
# understand that.
|
# understand that.
|
||||||
# pylint: disable=eval-used,unused-variable
|
import acme # pylint: disable=unused-import
|
||||||
import acme
|
import josepy # pylint: disable=unused-import
|
||||||
import josepy
|
acme_jose_mod = eval(acme_jose_path) # pylint: disable=eval-used
|
||||||
acme_jose_mod = eval(acme_jose_path)
|
josepy_mod = eval(josepy_path) # pylint: disable=eval-used
|
||||||
josepy_mod = eval(josepy_path)
|
|
||||||
self.assertIs(acme_jose_mod, josepy_mod)
|
self.assertIs(acme_jose_mod, josepy_mod)
|
||||||
self.assertIs(getattr(acme_jose_mod, attribute), getattr(josepy_mod, attribute))
|
self.assertIs(getattr(acme_jose_mod, attribute), getattr(josepy_mod, attribute))
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ class ErrorTest(unittest.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
from acme.messages import Error, ERROR_PREFIX
|
from acme.messages import Error, ERROR_PREFIX
|
||||||
self.error = Error(
|
self.error = Error.with_code('malformed', detail='foo', title='title')
|
||||||
detail='foo', typ=ERROR_PREFIX + 'malformed', title='title')
|
|
||||||
self.jobj = {
|
self.jobj = {
|
||||||
'detail': 'foo',
|
'detail': 'foo',
|
||||||
'title': 'some title',
|
'title': 'some title',
|
||||||
@@ -27,7 +26,6 @@ class ErrorTest(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
self.error_custom = Error(typ='custom', detail='bar')
|
self.error_custom = Error(typ='custom', detail='bar')
|
||||||
self.empty_error = Error()
|
self.empty_error = Error()
|
||||||
self.jobj_custom = {'type': 'custom', 'detail': 'bar'}
|
|
||||||
|
|
||||||
def test_default_typ(self):
|
def test_default_typ(self):
|
||||||
from acme.messages import Error
|
from acme.messages import Error
|
||||||
@@ -42,8 +40,7 @@ class ErrorTest(unittest.TestCase):
|
|||||||
hash(Error.from_json(self.error.to_json()))
|
hash(Error.from_json(self.error.to_json()))
|
||||||
|
|
||||||
def test_description(self):
|
def test_description(self):
|
||||||
self.assertEqual(
|
self.assertEqual('The request message was malformed', self.error.description)
|
||||||
'The request message was malformed', self.error.description)
|
|
||||||
self.assertTrue(self.error_custom.description is None)
|
self.assertTrue(self.error_custom.description is None)
|
||||||
|
|
||||||
def test_code(self):
|
def test_code(self):
|
||||||
@@ -53,17 +50,17 @@ class ErrorTest(unittest.TestCase):
|
|||||||
self.assertEqual(None, Error().code)
|
self.assertEqual(None, Error().code)
|
||||||
|
|
||||||
def test_is_acme_error(self):
|
def test_is_acme_error(self):
|
||||||
from acme.messages import is_acme_error
|
from acme.messages import is_acme_error, Error
|
||||||
self.assertTrue(is_acme_error(self.error))
|
self.assertTrue(is_acme_error(self.error))
|
||||||
self.assertFalse(is_acme_error(self.error_custom))
|
self.assertFalse(is_acme_error(self.error_custom))
|
||||||
|
self.assertFalse(is_acme_error(Error()))
|
||||||
self.assertFalse(is_acme_error(self.empty_error))
|
self.assertFalse(is_acme_error(self.empty_error))
|
||||||
self.assertFalse(is_acme_error("must pet all the {dogs|rabbits}"))
|
self.assertFalse(is_acme_error("must pet all the {dogs|rabbits}"))
|
||||||
|
|
||||||
def test_unicode_error(self):
|
def test_unicode_error(self):
|
||||||
from acme.messages import Error, ERROR_PREFIX, is_acme_error
|
from acme.messages import Error, is_acme_error
|
||||||
arabic_error = Error(
|
arabic_error = Error.with_code(
|
||||||
detail=u'\u0639\u062f\u0627\u0644\u0629', typ=ERROR_PREFIX + 'malformed',
|
'malformed', detail=u'\u0639\u062f\u0627\u0644\u0629', title='title')
|
||||||
title='title')
|
|
||||||
self.assertTrue(is_acme_error(arabic_error))
|
self.assertTrue(is_acme_error(arabic_error))
|
||||||
|
|
||||||
def test_with_code(self):
|
def test_with_code(self):
|
||||||
@@ -304,8 +301,7 @@ class ChallengeBodyTest(unittest.TestCase):
|
|||||||
from acme.messages import Error
|
from acme.messages import Error
|
||||||
from acme.messages import STATUS_INVALID
|
from acme.messages import STATUS_INVALID
|
||||||
self.status = STATUS_INVALID
|
self.status = STATUS_INVALID
|
||||||
error = Error(typ='urn:ietf:params:acme:error:serverInternal',
|
error = Error.with_code('serverInternal', detail='Unable to communicate with DNS server')
|
||||||
detail='Unable to communicate with DNS server')
|
|
||||||
self.challb = ChallengeBody(
|
self.challb = ChallengeBody(
|
||||||
uri='http://challb', chall=self.chall, status=self.status,
|
uri='http://challb', chall=self.chall, status=self.status,
|
||||||
error=error)
|
error=error)
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ def _guess_loader(filename, loader_pem, loader_der):
|
|||||||
return loader_pem
|
return loader_pem
|
||||||
elif ext.lower() == '.der':
|
elif ext.lower() == '.der':
|
||||||
return loader_der
|
return loader_der
|
||||||
else: # pragma: no cover
|
raise ValueError("Loader could not be recognized based on extension") # pragma: no cover
|
||||||
raise ValueError("Loader could not be recognized based on extension")
|
|
||||||
|
|
||||||
|
|
||||||
def load_cert(*names):
|
def load_cert(*names):
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ class ApacheConfigurator(common.Installer):
|
|||||||
filtered_vhosts[name] = vhost
|
filtered_vhosts[name] = vhost
|
||||||
|
|
||||||
# Only unique VHost objects
|
# Only unique VHost objects
|
||||||
dialog_input = set([vhost for vhost in filtered_vhosts.values()])
|
dialog_input = set(filtered_vhosts.values())
|
||||||
|
|
||||||
# Ask the user which of names to enable, expect list of names back
|
# Ask the user which of names to enable, expect list of names back
|
||||||
dialog_output = display_ops.select_vhost_multiple(list(dialog_input))
|
dialog_output = display_ops.select_vhost_multiple(list(dialog_input))
|
||||||
@@ -600,9 +600,9 @@ class ApacheConfigurator(common.Installer):
|
|||||||
"in the Apache config.",
|
"in the Apache config.",
|
||||||
target_name)
|
target_name)
|
||||||
raise errors.PluginError("No vhost selected")
|
raise errors.PluginError("No vhost selected")
|
||||||
elif temp:
|
if temp:
|
||||||
return vhost
|
return vhost
|
||||||
elif not vhost.ssl:
|
if not vhost.ssl:
|
||||||
addrs = self._get_proposed_addrs(vhost, "443")
|
addrs = self._get_proposed_addrs(vhost, "443")
|
||||||
# TODO: Conflicts is too conservative
|
# TODO: Conflicts is too conservative
|
||||||
if not any(vhost.enabled and vhost.conflicts(addrs) for
|
if not any(vhost.enabled and vhost.conflicts(addrs) for
|
||||||
@@ -951,13 +951,12 @@ class ApacheConfigurator(common.Installer):
|
|||||||
|
|
||||||
loc = parser.get_aug_path(self.parser.loc["name"])
|
loc = parser.get_aug_path(self.parser.loc["name"])
|
||||||
if addr.get_port() == "443":
|
if addr.get_port() == "443":
|
||||||
path = self.parser.add_dir_to_ifmodssl(
|
self.parser.add_dir_to_ifmodssl(
|
||||||
loc, "NameVirtualHost", [str(addr)])
|
loc, "NameVirtualHost", [str(addr)])
|
||||||
else:
|
else:
|
||||||
path = self.parser.add_dir(loc, "NameVirtualHost", [str(addr)])
|
self.parser.add_dir(loc, "NameVirtualHost", [str(addr)])
|
||||||
|
|
||||||
msg = ("Setting %s to be NameBasedVirtualHost\n"
|
msg = "Setting {0} to be NameBasedVirtualHost\n".format(addr)
|
||||||
"\tDirective added to %s\n" % (addr, path))
|
|
||||||
logger.debug(msg)
|
logger.debug(msg)
|
||||||
self.save_notes += msg
|
self.save_notes += msg
|
||||||
|
|
||||||
@@ -1365,12 +1364,9 @@ class ApacheConfigurator(common.Installer):
|
|||||||
result.append(comment)
|
result.append(comment)
|
||||||
sift = True
|
sift = True
|
||||||
|
|
||||||
result.append('\n'.join(
|
result.append('\n'.join(['# ' + l for l in chunk]))
|
||||||
['# ' + l for l in chunk]))
|
|
||||||
continue
|
|
||||||
else:
|
else:
|
||||||
result.append('\n'.join(chunk))
|
result.append('\n'.join(chunk))
|
||||||
continue
|
|
||||||
return result, sift
|
return result, sift
|
||||||
|
|
||||||
def _get_vhost_block(self, vhost):
|
def _get_vhost_block(self, vhost):
|
||||||
@@ -2513,4 +2509,4 @@ class ApacheConfigurator(common.Installer):
|
|||||||
self._autohsts_save_state()
|
self._autohsts_save_state()
|
||||||
|
|
||||||
|
|
||||||
AutoHSTSEnhancement.register(ApacheConfigurator) # pylint: disable=no-member
|
AutoHSTSEnhancement.register(ApacheConfigurator)
|
||||||
|
|||||||
@@ -194,8 +194,8 @@ class ApacheHttp01(common.ChallengePerformer):
|
|||||||
|
|
||||||
if vhost not in self.moded_vhosts:
|
if vhost not in self.moded_vhosts:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Adding a temporary challenge validation Include for name: %s " +
|
"Adding a temporary challenge validation Include for name: %s in: %s",
|
||||||
"in: %s", vhost.name, vhost.filep)
|
vhost.name, vhost.filep)
|
||||||
self.configurator.parser.add_dir_beginning(
|
self.configurator.parser.add_dir_beginning(
|
||||||
vhost.path, "Include", self.challenge_conf_pre)
|
vhost.path, "Include", self.challenge_conf_pre)
|
||||||
self.configurator.parser.add_dir(
|
self.configurator.parser.add_dir(
|
||||||
|
|||||||
@@ -70,15 +70,14 @@ class DebianConfigurator(configurator.ApacheConfigurator):
|
|||||||
# Already in shape
|
# Already in shape
|
||||||
vhost.enabled = True
|
vhost.enabled = True
|
||||||
return None
|
return None
|
||||||
else:
|
logger.warning(
|
||||||
logger.warning(
|
"Could not symlink %s to %s, got error: %s", enabled_path,
|
||||||
"Could not symlink %s to %s, got error: %s", enabled_path,
|
vhost.filep, err.strerror)
|
||||||
vhost.filep, err.strerror)
|
errstring = ("Encountered error while trying to enable a " +
|
||||||
errstring = ("Encountered error while trying to enable a " +
|
"newly created VirtualHost located at {0} by " +
|
||||||
"newly created VirtualHost located at {0} by " +
|
"linking to it from {1}")
|
||||||
"linking to it from {1}")
|
raise errors.NotSupportedError(errstring.format(vhost.filep,
|
||||||
raise errors.NotSupportedError(errstring.format(vhost.filep,
|
enabled_path))
|
||||||
enabled_path))
|
|
||||||
vhost.enabled = True
|
vhost.enabled = True
|
||||||
logger.info("Enabling available site: %s", vhost.filep)
|
logger.info("Enabling available site: %s", vhost.filep)
|
||||||
self.save_notes += "Enabled site %s\n" % vhost.filep
|
self.save_notes += "Enabled site %s\n" % vhost.filep
|
||||||
|
|||||||
@@ -284,8 +284,8 @@ class ApacheParser(object):
|
|||||||
mods.add(mod_name)
|
mods.add(mod_name)
|
||||||
mods.add(os.path.basename(mod_filename)[:-2] + "c")
|
mods.add(os.path.basename(mod_filename)[:-2] + "c")
|
||||||
else:
|
else:
|
||||||
logger.debug("Could not read LoadModule directive from " +
|
logger.debug("Could not read LoadModule directive from Augeas path: %s",
|
||||||
"Augeas path: %s", match_name[6:])
|
match_name[6:])
|
||||||
self.modules.update(mods)
|
self.modules.update(mods)
|
||||||
|
|
||||||
def update_runtime_variables(self):
|
def update_runtime_variables(self):
|
||||||
@@ -625,7 +625,7 @@ class ApacheParser(object):
|
|||||||
# https://httpd.apache.org/docs/2.4/mod/core.html#include
|
# https://httpd.apache.org/docs/2.4/mod/core.html#include
|
||||||
for match in matches:
|
for match in matches:
|
||||||
dir_ = self.aug.get(match).lower()
|
dir_ = self.aug.get(match).lower()
|
||||||
if dir_ == "include" or dir_ == "includeoptional":
|
if dir_ in ("include", "includeoptional"):
|
||||||
ordered_matches.extend(self.find_dir(
|
ordered_matches.extend(self.find_dir(
|
||||||
directive, arg,
|
directive, arg,
|
||||||
self._get_include_path(self.get_arg(match + "/arg")),
|
self._get_include_path(self.get_arg(match + "/arg")),
|
||||||
@@ -665,8 +665,7 @@ class ApacheParser(object):
|
|||||||
# e.g. strip now, not later
|
# e.g. strip now, not later
|
||||||
if not value:
|
if not value:
|
||||||
return None
|
return None
|
||||||
else:
|
value = value.strip("'\"")
|
||||||
value = value.strip("'\"")
|
|
||||||
|
|
||||||
variables = ApacheParser.arg_var_interpreter.findall(value)
|
variables = ApacheParser.arg_var_interpreter.findall(value)
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.29.0
|
acme[dev]==0.29.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.29.0',
|
'acme>=0.29.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'mock',
|
'mock',
|
||||||
'python-augeas',
|
'python-augeas',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ class Proxy(object):
|
|||||||
method = getattr(self._configurator, name, None)
|
method = getattr(self._configurator, name, None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method
|
return method
|
||||||
else:
|
raise AttributeError()
|
||||||
raise AttributeError()
|
|
||||||
|
|
||||||
def has_more_configs(self):
|
def has_more_configs(self):
|
||||||
"""Returns true if there are more configs to test"""
|
"""Returns true if there are more configs to test"""
|
||||||
@@ -82,8 +81,7 @@ class Proxy(object):
|
|||||||
"""Returns the set of domain names that the plugin should find"""
|
"""Returns the set of domain names that the plugin should find"""
|
||||||
if self._all_names:
|
if self._all_names:
|
||||||
return self._all_names
|
return self._all_names
|
||||||
else:
|
raise errors.Error("No configuration file loaded")
|
||||||
raise errors.Error("No configuration file loaded")
|
|
||||||
|
|
||||||
def get_testable_domain_names(self):
|
def get_testable_domain_names(self):
|
||||||
"""Returns the set of domain names that can be tested against"""
|
"""Returns the set of domain names that can be tested against"""
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import tempfile
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
import OpenSSL
|
import OpenSSL
|
||||||
from six.moves import xrange # pylint: disable=import-error,redefined-builtin
|
|
||||||
from urllib3.util import connection
|
from urllib3.util import connection
|
||||||
|
|
||||||
from acme import challenges
|
from acme import challenges
|
||||||
@@ -57,26 +56,27 @@ def test_authenticator(plugin, config, temp_dir):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
success = True
|
success = True
|
||||||
for i in xrange(len(responses)):
|
for i, response in enumerate(responses):
|
||||||
if not responses[i]:
|
achall = achalls[i]
|
||||||
|
if not response:
|
||||||
logger.error(
|
logger.error(
|
||||||
"Plugin failed to complete %s for %s in %s",
|
"Plugin failed to complete %s for %s in %s",
|
||||||
type(achalls[i]), achalls[i].domain, config)
|
type(achall), achall.domain, config)
|
||||||
success = False
|
success = False
|
||||||
elif isinstance(responses[i], challenges.HTTP01Response):
|
elif isinstance(response, challenges.HTTP01Response):
|
||||||
# We fake the DNS resolution to ensure that any domain is resolved
|
# We fake the DNS resolution to ensure that any domain is resolved
|
||||||
# to the local HTTP server setup for the compatibility tests
|
# to the local HTTP server setup for the compatibility tests
|
||||||
with _fake_dns_resolution("127.0.0.1"):
|
with _fake_dns_resolution("127.0.0.1"):
|
||||||
verified = responses[i].simple_verify(
|
verified = response.simple_verify(
|
||||||
achalls[i].chall, achalls[i].domain,
|
achall.chall, achall.domain,
|
||||||
util.JWK.public_key(), port=plugin.http_port)
|
util.JWK.public_key(), port=plugin.http_port)
|
||||||
if verified:
|
if verified:
|
||||||
logger.info(
|
logger.info(
|
||||||
"http-01 verification for %s succeeded", achalls[i].domain)
|
"http-01 verification for %s succeeded", achall.domain)
|
||||||
else:
|
else:
|
||||||
logger.error(
|
logger.error(
|
||||||
"**** http-01 verification for %s in %s failed",
|
"**** http-01 verification for %s in %s failed",
|
||||||
achalls[i].domain, config)
|
achall.domain, config)
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
@@ -89,8 +89,7 @@ def test_authenticator(plugin, config, temp_dir):
|
|||||||
if _dirs_are_unequal(config, backup):
|
if _dirs_are_unequal(config, backup):
|
||||||
logger.error("Challenge cleanup failed for %s", config)
|
logger.error("Challenge cleanup failed for %s", config)
|
||||||
return False
|
return False
|
||||||
else:
|
logger.info("Challenge cleanup succeeded")
|
||||||
logger.info("Challenge cleanup succeeded")
|
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
@@ -305,7 +304,7 @@ def get_args():
|
|||||||
"-e", "--enhance", action="store_true", help="tests the enhancements "
|
"-e", "--enhance", action="store_true", help="tests the enhancements "
|
||||||
"the plugin supports (implicitly includes installer tests)")
|
"the plugin supports (implicitly includes installer tests)")
|
||||||
|
|
||||||
for plugin in PLUGINS.itervalues():
|
for plugin in PLUGINS.values():
|
||||||
plugin.add_parser_arguments(parser)
|
plugin.add_parser_arguments(parser)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.29.0
|
acme[dev]==0.29.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.29.0',
|
'acme>=0.29.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'cloudflare>=1.5.1',
|
'cloudflare>=1.5.1',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.31.0
|
acme[dev]==0.31.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.31.0',
|
'acme>=0.31.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.29.0
|
acme[dev]==0.29.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.29.0',
|
'acme>=0.29.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'mock',
|
'mock',
|
||||||
'python-digitalocean>=1.11',
|
'python-digitalocean>=1.11',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.31.0
|
acme[dev]==0.31.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.31.0',
|
'acme>=0.31.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
'zope.interface',
|
'zope.interface',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.31.0
|
acme[dev]==0.31.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.31.0',
|
'acme>=0.31.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.31.0
|
acme[dev]==0.31.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ version = '1.1.0.dev0'
|
|||||||
# Please update tox.ini when modifying dependency version requirements
|
# Please update tox.ini when modifying dependency version requirements
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.31.0',
|
'acme>=0.31.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'dns-lexicon>=2.1.22',
|
'dns-lexicon>=2.1.22',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ class _GoogleClient(object):
|
|||||||
:rtype: `list` of `string` or `None`
|
:rtype: `list` of `string` or `None`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
rrs_request = self.dns.resourceRecordSets() # pylint: disable=no-member
|
rrs_request = self.dns.resourceRecordSets()
|
||||||
request = rrs_request.list(managedZone=zone_id, project=self.project_id)
|
request = rrs_request.list(managedZone=zone_id, project=self.project_id)
|
||||||
# Add dot as the API returns absolute domains
|
# Add dot as the API returns absolute domains
|
||||||
record_name += "."
|
record_name += "."
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.29.0
|
acme[dev]==0.29.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.29.0',
|
'acme>=0.29.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'google-api-python-client>=1.5.5',
|
'google-api-python-client>=1.5.5',
|
||||||
'mock',
|
'mock',
|
||||||
'oauth2client>=4.0',
|
'oauth2client>=4.0',
|
||||||
|
|||||||
@@ -288,7 +288,6 @@ class GoogleClientTest(unittest.TestCase):
|
|||||||
def test_get_existing_fallback(self, unused_credential_mock):
|
def test_get_existing_fallback(self, unused_credential_mock):
|
||||||
client, unused_changes = self._setUp_client_with_mock(
|
client, unused_changes = self._setUp_client_with_mock(
|
||||||
[{'managedZones': [{'id': self.zone}]}])
|
[{'managedZones': [{'id': self.zone}]}])
|
||||||
# pylint: disable=no-member
|
|
||||||
mock_execute = client.dns.resourceRecordSets.return_value.list.return_value.execute
|
mock_execute = client.dns.resourceRecordSets.return_value.list.return_value.execute
|
||||||
mock_execute.side_effect = API_ERROR
|
mock_execute.side_effect = API_ERROR
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.31.0
|
acme[dev]==0.31.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
dns-lexicon==2.2.3
|
dns-lexicon==2.2.3
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ version = '1.1.0.dev0'
|
|||||||
# Please update tox.ini when modifying dependency version requirements
|
# Please update tox.ini when modifying dependency version requirements
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.31.0',
|
'acme>=0.31.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'dns-lexicon>=2.2.3',
|
'dns-lexicon>=2.2.3',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.31.0
|
acme[dev]==0.31.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.31.0',
|
'acme>=0.31.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.31.0
|
acme[dev]==0.31.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.31.0',
|
'acme>=0.31.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.31.0
|
acme[dev]==0.31.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
dns-lexicon==2.7.14
|
dns-lexicon==2.7.14
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.31.0',
|
'acme>=0.31.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'dns-lexicon>=2.7.14', # Correct proxy use on OVH provider
|
'dns-lexicon>=2.7.14', # Correct proxy use on OVH provider
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.29.0
|
acme[dev]==0.29.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.29.0',
|
'acme>=0.29.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'dnspython',
|
'dnspython',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.29.0
|
acme[dev]==0.29.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.29.0',
|
'acme>=0.29.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'boto3',
|
'boto3',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==0.31.0
|
acme[dev]==0.31.0
|
||||||
certbot[dev]==0.39.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ version = '1.1.0.dev0'
|
|||||||
# Please update tox.ini when modifying dependency version requirements
|
# Please update tox.ini when modifying dependency version requirements
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=0.31.0',
|
'acme>=0.31.0',
|
||||||
'certbot>=0.39.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'dns-lexicon>=2.1.23',
|
'dns-lexicon>=2.1.23',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ class NginxConfigurator(common.Installer):
|
|||||||
filtered_vhosts[name] = vhost
|
filtered_vhosts[name] = vhost
|
||||||
|
|
||||||
# Only unique VHost objects
|
# Only unique VHost objects
|
||||||
dialog_input = set([vhost for vhost in filtered_vhosts.values()])
|
dialog_input = set(filtered_vhosts.values())
|
||||||
|
|
||||||
# Ask the user which of names to enable, expect list of names back
|
# Ask the user which of names to enable, expect list of names back
|
||||||
return_vhosts = display_ops.select_vhost_multiple(list(dialog_input))
|
return_vhosts = display_ops.select_vhost_multiple(list(dialog_input))
|
||||||
|
|||||||
@@ -186,12 +186,11 @@ class UnspacedList(list):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
if not isinstance(inbound, list): # str or None
|
if not isinstance(inbound, list): # str or None
|
||||||
return (inbound, inbound)
|
return inbound, inbound
|
||||||
else:
|
else:
|
||||||
if not hasattr(inbound, "spaced"):
|
if not hasattr(inbound, "spaced"):
|
||||||
inbound = UnspacedList(inbound)
|
inbound = UnspacedList(inbound)
|
||||||
return (inbound, inbound.spaced)
|
return inbound, inbound.spaced
|
||||||
|
|
||||||
|
|
||||||
def insert(self, i, x):
|
def insert(self, i, x):
|
||||||
item, spaced_item = self._coerce(x)
|
item, spaced_item = self._coerce(x)
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ class NginxParser(object):
|
|||||||
for directive in server:
|
for directive in server:
|
||||||
if not directive:
|
if not directive:
|
||||||
continue
|
continue
|
||||||
elif _is_ssl_on_directive(directive):
|
if _is_ssl_on_directive(directive):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@@ -489,7 +489,7 @@ def get_best_match(target_name, names):
|
|||||||
|
|
||||||
|
|
||||||
def _exact_match(target_name, name):
|
def _exact_match(target_name, name):
|
||||||
return target_name == name or '.' + target_name == name
|
return name in (target_name, '.' + target_name)
|
||||||
|
|
||||||
|
|
||||||
def _wildcard_match(target_name, name, start):
|
def _wildcard_match(target_name, name, start):
|
||||||
@@ -507,7 +507,7 @@ def _wildcard_match(target_name, name, start):
|
|||||||
|
|
||||||
# The first part must be a wildcard or blank, e.g. '.eff.org'
|
# The first part must be a wildcard or blank, e.g. '.eff.org'
|
||||||
first = match_parts.pop(0)
|
first = match_parts.pop(0)
|
||||||
if first != '*' and first != '':
|
if first not in ('*', ''):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
target_name = '.'.join(parts)
|
target_name = '.'.join(parts)
|
||||||
@@ -585,7 +585,7 @@ def comment_directive(block, location):
|
|||||||
if isinstance(next_entry, list) and next_entry:
|
if isinstance(next_entry, list) and next_entry:
|
||||||
if len(next_entry) >= 2 and next_entry[-2] == "#" and COMMENT in next_entry[-1]:
|
if len(next_entry) >= 2 and next_entry[-2] == "#" and COMMENT in next_entry[-1]:
|
||||||
return
|
return
|
||||||
elif isinstance(next_entry, nginxparser.UnspacedList):
|
if isinstance(next_entry, nginxparser.UnspacedList):
|
||||||
next_entry = next_entry.spaced[0]
|
next_entry = next_entry.spaced[0]
|
||||||
else:
|
else:
|
||||||
next_entry = next_entry[0]
|
next_entry = next_entry[0]
|
||||||
@@ -661,13 +661,12 @@ def _add_directive(block, directive, insert_at_top):
|
|||||||
for included_directive in included_directives:
|
for included_directive in included_directives:
|
||||||
included_dir_loc = _find_location(block, included_directive[0])
|
included_dir_loc = _find_location(block, included_directive[0])
|
||||||
included_dir_name = included_directive[0]
|
included_dir_name = included_directive[0]
|
||||||
if not _is_whitespace_or_comment(included_directive) \
|
if (not _is_whitespace_or_comment(included_directive)
|
||||||
and not can_append(included_dir_loc, included_dir_name):
|
and not can_append(included_dir_loc, included_dir_name)):
|
||||||
if block[included_dir_loc] != included_directive:
|
if block[included_dir_loc] != included_directive:
|
||||||
raise errors.MisconfigurationError(err_fmt.format(included_directive,
|
raise errors.MisconfigurationError(err_fmt.format(included_directive,
|
||||||
block[included_dir_loc]))
|
block[included_dir_loc]))
|
||||||
else:
|
_comment_out_directive(block, included_dir_loc, directive[1])
|
||||||
_comment_out_directive(block, included_dir_loc, directive[1])
|
|
||||||
|
|
||||||
if can_append(location, directive_name):
|
if can_append(location, directive_name):
|
||||||
if insert_at_top:
|
if insert_at_top:
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Remember to update setup.py to match the package versions below.
|
# Remember to update setup.py to match the package versions below.
|
||||||
acme[dev]==1.0.0
|
acme[dev]==1.0.0
|
||||||
certbot[dev]==1.0.0
|
-e certbot[dev]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ version = '1.1.0.dev0'
|
|||||||
# acme/certbot version.
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme>=1.0.0',
|
'acme>=1.0.0',
|
||||||
'certbot>=1.0.0',
|
'certbot>=1.0.0.dev0',
|
||||||
'mock',
|
'mock',
|
||||||
'PyOpenSSL',
|
'PyOpenSSL',
|
||||||
'pyparsing>=1.5.5', # Python3 support; perhaps unnecessary?
|
'pyparsing>=1.5.5', # Python3 support; perhaps unnecessary?
|
||||||
|
|||||||
@@ -1091,7 +1091,7 @@ class DetermineDefaultServerRootTest(certbot_test_util.ConfigTestCase):
|
|||||||
self.assertIn("/usr/local/etc/nginx", server_root)
|
self.assertIn("/usr/local/etc/nginx", server_root)
|
||||||
self.assertIn("/etc/nginx", server_root)
|
self.assertIn("/etc/nginx", server_root)
|
||||||
else:
|
else:
|
||||||
self.assertTrue(server_root == "/etc/nginx" or server_root == "/usr/local/etc/nginx")
|
self.assertTrue(server_root in ("/etc/nginx", "/usr/local/etc/nginx"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -49,16 +49,16 @@ class NginxParserTest(util.NginxTest):
|
|||||||
"""
|
"""
|
||||||
nparser = parser.NginxParser(self.config_path)
|
nparser = parser.NginxParser(self.config_path)
|
||||||
nparser.load()
|
nparser.load()
|
||||||
self.assertEqual(set([nparser.abs_path(x) for x in
|
self.assertEqual({nparser.abs_path(x) for x in
|
||||||
['foo.conf', 'nginx.conf', 'server.conf',
|
['foo.conf', 'nginx.conf', 'server.conf',
|
||||||
'sites-enabled/default',
|
'sites-enabled/default',
|
||||||
'sites-enabled/example.com',
|
'sites-enabled/example.com',
|
||||||
'sites-enabled/headers.com',
|
'sites-enabled/headers.com',
|
||||||
'sites-enabled/migration.com',
|
'sites-enabled/migration.com',
|
||||||
'sites-enabled/sslon.com',
|
'sites-enabled/sslon.com',
|
||||||
'sites-enabled/globalssl.com',
|
'sites-enabled/globalssl.com',
|
||||||
'sites-enabled/ipv6.com',
|
'sites-enabled/ipv6.com',
|
||||||
'sites-enabled/ipv6ssl.com']]),
|
'sites-enabled/ipv6ssl.com']},
|
||||||
set(nparser.parsed.keys()))
|
set(nparser.parsed.keys()))
|
||||||
self.assertEqual([['server_name', 'somename', 'alias', 'another.alias']],
|
self.assertEqual([['server_name', 'somename', 'alias', 'another.alias']],
|
||||||
nparser.parsed[nparser.abs_path('server.conf')])
|
nparser.parsed[nparser.abs_path('server.conf')])
|
||||||
|
|||||||
@@ -216,9 +216,8 @@ class AccountFileStorage(interfaces.AccountStorage):
|
|||||||
else:
|
else:
|
||||||
self._symlink_to_accounts_dir(prev_server_path, server_path)
|
self._symlink_to_accounts_dir(prev_server_path, server_path)
|
||||||
return prev_loaded_account
|
return prev_loaded_account
|
||||||
else:
|
raise errors.AccountNotFound(
|
||||||
raise errors.AccountNotFound(
|
"Account at %s does not exist" % account_dir_path)
|
||||||
"Account at %s does not exist" % account_dir_path)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(self._regr_path(account_dir_path)) as regr_file:
|
with open(self._regr_path(account_dir_path)) as regr_file:
|
||||||
|
|||||||
@@ -285,9 +285,8 @@ def challb_to_achall(challb, account_key, domain):
|
|||||||
challb=challb, domain=domain, account_key=account_key)
|
challb=challb, domain=domain, account_key=account_key)
|
||||||
elif isinstance(chall, challenges.DNS):
|
elif isinstance(chall, challenges.DNS):
|
||||||
return achallenges.DNS(challb=challb, domain=domain)
|
return achallenges.DNS(challb=challb, domain=domain)
|
||||||
else:
|
raise errors.Error(
|
||||||
raise errors.Error(
|
"Received unsupported challenge of type: {0}".format(chall.typ))
|
||||||
"Received unsupported challenge of type: {0}".format(chall.typ))
|
|
||||||
|
|
||||||
|
|
||||||
def gen_challenge_path(challbs, preferences, combinations):
|
def gen_challenge_path(challbs, preferences, combinations):
|
||||||
|
|||||||
@@ -242,8 +242,8 @@ def match_and_check_overlaps(cli_config, acceptable_matches, match_func, rv_func
|
|||||||
raise errors.Error("No match found for cert-path {0}!".format(cli_config.cert_path[0]))
|
raise errors.Error("No match found for cert-path {0}!".format(cli_config.cert_path[0]))
|
||||||
elif len(matched) > 1:
|
elif len(matched) > 1:
|
||||||
raise errors.OverlappingMatchFound()
|
raise errors.OverlappingMatchFound()
|
||||||
else:
|
return matched
|
||||||
return matched
|
|
||||||
|
|
||||||
def human_readable_cert_info(config, cert, skip_filter_checks=False):
|
def human_readable_cert_info(config, cert, skip_filter_checks=False):
|
||||||
""" Returns a human readable description of info about a RenewableCert object"""
|
""" Returns a human readable description of info about a RenewableCert object"""
|
||||||
|
|||||||
@@ -287,10 +287,9 @@ def flag_default(name):
|
|||||||
|
|
||||||
def config_help(name, hidden=False):
|
def config_help(name, hidden=False):
|
||||||
"""Extract the help message for an `.IConfig` attribute."""
|
"""Extract the help message for an `.IConfig` attribute."""
|
||||||
# pylint: disable=no-member
|
|
||||||
if hidden:
|
if hidden:
|
||||||
return argparse.SUPPRESS
|
return argparse.SUPPRESS
|
||||||
field = interfaces.IConfig.__getitem__(name) # type: zope.interface.interface.Attribute # pylint: disable=no-value-for-parameter
|
field = interfaces.IConfig.__getitem__(name) # type: zope.interface.interface.Attribute
|
||||||
return field.__doc__
|
return field.__doc__
|
||||||
|
|
||||||
|
|
||||||
@@ -674,7 +673,7 @@ class HelpfulArgumentParser(object):
|
|||||||
|
|
||||||
parsed_args.actual_csr = (csr, typ)
|
parsed_args.actual_csr = (csr, typ)
|
||||||
|
|
||||||
csr_domains = set([d.lower() for d in domains])
|
csr_domains = {d.lower() for d in domains}
|
||||||
config_domains = set(parsed_args.domains)
|
config_domains = set(parsed_args.domains)
|
||||||
if csr_domains != config_domains:
|
if csr_domains != config_domains:
|
||||||
raise errors.ConfigurationError(
|
raise errors.ConfigurationError(
|
||||||
@@ -847,11 +846,11 @@ class HelpfulArgumentParser(object):
|
|||||||
chosen_topic = "run"
|
chosen_topic = "run"
|
||||||
if chosen_topic == "all":
|
if chosen_topic == "all":
|
||||||
# Addition of condition closes #6209 (removal of duplicate route53 option).
|
# Addition of condition closes #6209 (removal of duplicate route53 option).
|
||||||
return dict([(t, True) if t != 'certbot-route53:auth' else (t, False)
|
return {t: t != 'certbot-route53:auth' for t in self.help_topics}
|
||||||
for t in self.help_topics])
|
|
||||||
elif not chosen_topic:
|
elif not chosen_topic:
|
||||||
return dict([(t, False) for t in self.help_topics])
|
return {t: False for t in self.help_topics}
|
||||||
return dict([(t, t == chosen_topic) for t in self.help_topics])
|
return {t: t == chosen_topic for t in self.help_topics}
|
||||||
|
|
||||||
|
|
||||||
def _add_all_groups(helpful):
|
def _add_all_groups(helpful):
|
||||||
helpful.add_group("automation", description="Flags for automating execution & other tweaks")
|
helpful.add_group("automation", description="Flags for automating execution & other tweaks")
|
||||||
|
|||||||
@@ -224,11 +224,9 @@ def perform_registration(acme, config, tos_cb):
|
|||||||
"Please ensure it is a valid email and attempt "
|
"Please ensure it is a valid email and attempt "
|
||||||
"registration again." % config.email)
|
"registration again." % config.email)
|
||||||
raise errors.Error(msg)
|
raise errors.Error(msg)
|
||||||
else:
|
config.email = display_ops.get_email(invalid=True)
|
||||||
config.email = display_ops.get_email(invalid=True)
|
return perform_registration(acme, config, tos_cb)
|
||||||
return perform_registration(acme, config, tos_cb)
|
raise
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
class Client(object):
|
class Client(object):
|
||||||
@@ -360,7 +358,6 @@ class Client(object):
|
|||||||
return self.obtain_certificate(successful_domains)
|
return self.obtain_certificate(successful_domains)
|
||||||
else:
|
else:
|
||||||
cert, chain = self.obtain_certificate_from_csr(csr, orderr)
|
cert, chain = self.obtain_certificate_from_csr(csr, orderr)
|
||||||
|
|
||||||
return cert, chain, key, csr
|
return cert, chain, key, csr
|
||||||
|
|
||||||
def _get_order_and_authorizations(self, csr_pem, best_effort):
|
def _get_order_and_authorizations(self, csr_pem, best_effort):
|
||||||
@@ -393,8 +390,6 @@ class Client(object):
|
|||||||
|
|
||||||
authzr = self.auth_handler.handle_authorizations(orderr, best_effort)
|
authzr = self.auth_handler.handle_authorizations(orderr, best_effort)
|
||||||
return orderr.update(authorizations=authzr)
|
return orderr.update(authorizations=authzr)
|
||||||
|
|
||||||
# pylint: disable=no-member
|
|
||||||
def obtain_and_enroll_certificate(self, domains, certname):
|
def obtain_and_enroll_certificate(self, domains, certname):
|
||||||
"""Obtain and enroll certificate.
|
"""Obtain and enroll certificate.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Certbot user-supplied configuration."""
|
"""Certbot user-supplied configuration."""
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
from six.moves.urllib import parse # pylint: disable=relative-import
|
from six.moves.urllib import parse
|
||||||
import zope.interface
|
import zope.interface
|
||||||
|
|
||||||
from certbot import errors
|
from certbot import errors
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class ErrorHandler(object):
|
|||||||
# SystemExit is ignored to properly handle forks that don't exec
|
# SystemExit is ignored to properly handle forks that don't exec
|
||||||
if exec_type is SystemExit:
|
if exec_type is SystemExit:
|
||||||
return retval
|
return retval
|
||||||
elif exec_type is None:
|
if exec_type is None:
|
||||||
if not self.call_on_regular_exit:
|
if not self.call_on_regular_exit:
|
||||||
return retval
|
return retval
|
||||||
elif exec_type is errors.SignalExit:
|
elif exec_type is errors.SignalExit:
|
||||||
|
|||||||
@@ -102,9 +102,9 @@ def post_arg_parse_setup(config):
|
|||||||
|
|
||||||
root_logger.addHandler(file_handler)
|
root_logger.addHandler(file_handler)
|
||||||
root_logger.removeHandler(memory_handler)
|
root_logger.removeHandler(memory_handler)
|
||||||
temp_handler = memory_handler.target
|
temp_handler = memory_handler.target # pylint: disable=no-member
|
||||||
memory_handler.setTarget(file_handler)
|
memory_handler.setTarget(file_handler) # pylint: disable=no-member
|
||||||
memory_handler.flush(force=True)
|
memory_handler.flush(force=True) # pylint: disable=unexpected-keyword-arg
|
||||||
memory_handler.close()
|
memory_handler.close()
|
||||||
temp_handler.close()
|
temp_handler.close()
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ def _get_and_save_cert(le_client, config, domains=None, certname=None, lineage=N
|
|||||||
lineage = le_client.obtain_and_enroll_certificate(domains, certname)
|
lineage = le_client.obtain_and_enroll_certificate(domains, certname)
|
||||||
if lineage is False:
|
if lineage is False:
|
||||||
raise errors.Error("Certificate could not be obtained")
|
raise errors.Error("Certificate could not be obtained")
|
||||||
elif lineage is not None:
|
if lineage is not None:
|
||||||
hooks.deploy_hook(config, lineage.names(), lineage.live_dir)
|
hooks.deploy_hook(config, lineage.names(), lineage.live_dir)
|
||||||
finally:
|
finally:
|
||||||
hooks.post_hook(config)
|
hooks.post_hook(config)
|
||||||
@@ -162,19 +162,18 @@ def _handle_subset_cert_request(config, domains, cert):
|
|||||||
cli_flag="--expand",
|
cli_flag="--expand",
|
||||||
force_interactive=True):
|
force_interactive=True):
|
||||||
return "renew", cert
|
return "renew", cert
|
||||||
else:
|
reporter_util = zope.component.getUtility(interfaces.IReporter)
|
||||||
reporter_util = zope.component.getUtility(interfaces.IReporter)
|
reporter_util.add_message(
|
||||||
reporter_util.add_message(
|
"To obtain a new certificate that contains these names without "
|
||||||
"To obtain a new certificate that contains these names without "
|
"replacing your existing certificate for {0}, you must use the "
|
||||||
"replacing your existing certificate for {0}, you must use the "
|
"--duplicate option.{br}{br}"
|
||||||
"--duplicate option.{br}{br}"
|
"For example:{br}{br}{1} --duplicate {2}".format(
|
||||||
"For example:{br}{br}{1} --duplicate {2}".format(
|
existing,
|
||||||
existing,
|
sys.argv[0], " ".join(sys.argv[1:]),
|
||||||
sys.argv[0], " ".join(sys.argv[1:]),
|
br=os.linesep
|
||||||
br=os.linesep
|
),
|
||||||
),
|
reporter_util.HIGH_PRIORITY)
|
||||||
reporter_util.HIGH_PRIORITY)
|
raise errors.Error(USER_CANCELLED)
|
||||||
raise errors.Error(USER_CANCELLED)
|
|
||||||
|
|
||||||
|
|
||||||
def _handle_identical_cert_request(config, lineage):
|
def _handle_identical_cert_request(config, lineage):
|
||||||
@@ -220,7 +219,7 @@ def _handle_identical_cert_request(config, lineage):
|
|||||||
# skipping the menu for this case.
|
# skipping the menu for this case.
|
||||||
raise errors.Error(
|
raise errors.Error(
|
||||||
"Operation canceled. You may re-run the client.")
|
"Operation canceled. You may re-run the client.")
|
||||||
elif response[1] == 0:
|
if response[1] == 0:
|
||||||
return "reinstall", lineage
|
return "reinstall", lineage
|
||||||
elif response[1] == 1:
|
elif response[1] == 1:
|
||||||
return "renew", lineage
|
return "renew", lineage
|
||||||
@@ -312,23 +311,20 @@ def _find_lineage_for_domains_and_certname(config, domains, certname):
|
|||||||
"""
|
"""
|
||||||
if not certname:
|
if not certname:
|
||||||
return _find_lineage_for_domains(config, domains)
|
return _find_lineage_for_domains(config, domains)
|
||||||
else:
|
lineage = cert_manager.lineage_for_certname(config, certname)
|
||||||
lineage = cert_manager.lineage_for_certname(config, certname)
|
if lineage:
|
||||||
if lineage:
|
if domains:
|
||||||
if domains:
|
if set(cert_manager.domains_for_certname(config, certname)) != set(domains):
|
||||||
if set(cert_manager.domains_for_certname(config, certname)) != set(domains):
|
_ask_user_to_confirm_new_names(config, domains, certname,
|
||||||
_ask_user_to_confirm_new_names(config, domains, certname,
|
lineage.names()) # raises if no
|
||||||
lineage.names()) # raises if no
|
return "renew", lineage
|
||||||
return "renew", lineage
|
# unnecessarily specified domains or no domains specified
|
||||||
# unnecessarily specified domains or no domains specified
|
return _handle_identical_cert_request(config, lineage)
|
||||||
return _handle_identical_cert_request(config, lineage)
|
elif domains:
|
||||||
else:
|
return "newcert", None
|
||||||
if domains:
|
raise errors.ConfigurationError("No certificate with name {0} found. "
|
||||||
return "newcert", None
|
"Use -d to specify domains, or run certbot certificates to see "
|
||||||
else:
|
"possible certificate names.".format(certname))
|
||||||
raise errors.ConfigurationError("No certificate with name {0} found. "
|
|
||||||
"Use -d to specify domains, or run certbot certificates to see "
|
|
||||||
"possible certificate names.".format(certname))
|
|
||||||
|
|
||||||
def _get_added_removed(after, before):
|
def _get_added_removed(after, before):
|
||||||
"""Get lists of items removed from `before`
|
"""Get lists of items removed from `before`
|
||||||
@@ -1338,7 +1334,7 @@ def main(cli_args=None):
|
|||||||
make_or_verify_needed_dirs(config)
|
make_or_verify_needed_dirs(config)
|
||||||
except errors.Error:
|
except errors.Error:
|
||||||
# Let plugins_cmd be run as un-privileged user.
|
# Let plugins_cmd be run as un-privileged user.
|
||||||
if config.func != plugins_cmd:
|
if config.func != plugins_cmd: # pylint: disable=comparison-with-callable
|
||||||
raise
|
raise
|
||||||
|
|
||||||
set_displayer(config)
|
set_displayer(config)
|
||||||
|
|||||||
@@ -296,5 +296,5 @@ def _translate_ocsp_query(cert_path, ocsp_output, ocsp_errors):
|
|||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.warning("Unable to properly parse OCSP output: %s\nstderr:%s",
|
logger.warning("Unable to properly parse OCSP output: %s\nstderr:%s",
|
||||||
ocsp_output, ocsp_errors)
|
ocsp_output, ocsp_errors)
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -64,9 +64,8 @@ def get_unprepared_installer(config, plugins):
|
|||||||
inst = list(installers.values())[0]
|
inst = list(installers.values())[0]
|
||||||
logger.debug("Selecting plugin: %s", inst)
|
logger.debug("Selecting plugin: %s", inst)
|
||||||
return inst.init(config)
|
return inst.init(config)
|
||||||
else:
|
raise errors.PluginSelectionError(
|
||||||
raise errors.PluginSelectionError(
|
"Could not select or initialize the requested installer %s." % req_inst)
|
||||||
"Could not select or initialize the requested installer %s." % req_inst)
|
|
||||||
|
|
||||||
def pick_plugin(config, default, plugins, question, ifaces):
|
def pick_plugin(config, default, plugins, question, ifaces):
|
||||||
"""Pick plugin.
|
"""Pick plugin.
|
||||||
@@ -209,7 +208,7 @@ def choose_configurator_plugins(config, plugins, verb):
|
|||||||
need_inst = need_auth = False
|
need_inst = need_auth = False
|
||||||
if verb == "certonly":
|
if verb == "certonly":
|
||||||
need_auth = True
|
need_auth = True
|
||||||
if verb == "install" or verb == "enhance":
|
elif verb in ("install", "enhance"):
|
||||||
need_inst = True
|
need_inst = True
|
||||||
if config.authenticator:
|
if config.authenticator:
|
||||||
logger.warning("Specifying an authenticator doesn't make sense when "
|
logger.warning("Specifying an authenticator doesn't make sense when "
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ class ServerManager(object):
|
|||||||
servers.serve_forever()
|
servers.serve_forever()
|
||||||
|
|
||||||
# if port == 0, then random free port on OS is taken
|
# if port == 0, then random free port on OS is taken
|
||||||
# pylint: disable=no-member
|
|
||||||
# both servers, if they exist, have the same port
|
# both servers, if they exist, have the same port
|
||||||
real_port = servers.getsocknames()[0][1]
|
real_port = servers.getsocknames()[0][1]
|
||||||
self._instances[real_port] = servers
|
self._instances[real_port] = servers
|
||||||
@@ -196,7 +195,7 @@ def _handle_perform_error(error):
|
|||||||
"the appropriate permissions (for example, you "
|
"the appropriate permissions (for example, you "
|
||||||
"aren't running this program as "
|
"aren't running this program as "
|
||||||
"root).".format(error.port))
|
"root).".format(error.port))
|
||||||
elif error.socket_error.errno == socket_errors.EADDRINUSE:
|
if error.socket_error.errno == socket_errors.EADDRINUSE:
|
||||||
display = zope.component.getUtility(interfaces.IDisplay)
|
display = zope.component.getUtility(interfaces.IDisplay)
|
||||||
msg = (
|
msg = (
|
||||||
"Could not bind TCP port {0} because it is already in "
|
"Could not bind TCP port {0} because it is already in "
|
||||||
|
|||||||
@@ -135,8 +135,7 @@ to serve all files under specified web root ({0})."""
|
|||||||
raise errors.PluginError(
|
raise errors.PluginError(
|
||||||
"Every requested domain must have a "
|
"Every requested domain must have a "
|
||||||
"webroot when using the webroot plugin.")
|
"webroot when using the webroot plugin.")
|
||||||
else: # code == display_util.OK
|
return None if index == 0 else known_webroots[index - 1] # code == display_util.OK
|
||||||
return None if index == 0 else known_webroots[index - 1]
|
|
||||||
|
|
||||||
def _prompt_for_new_webroot(self, domain, allowraise=False):
|
def _prompt_for_new_webroot(self, domain, allowraise=False):
|
||||||
code, webroot = ops.validated_directory(
|
code, webroot = ops.validated_directory(
|
||||||
@@ -146,12 +145,10 @@ to serve all files under specified web root ({0})."""
|
|||||||
if code == display_util.CANCEL:
|
if code == display_util.CANCEL:
|
||||||
if not allowraise:
|
if not allowraise:
|
||||||
return None
|
return None
|
||||||
else:
|
raise errors.PluginError(
|
||||||
raise errors.PluginError(
|
"Every requested domain must have a "
|
||||||
"Every requested domain must have a "
|
"webroot when using the webroot plugin.")
|
||||||
"webroot when using the webroot plugin.")
|
return _validate_webroot(webroot) # code == display_util.OK
|
||||||
else: # code == display_util.OK
|
|
||||||
return _validate_webroot(webroot)
|
|
||||||
|
|
||||||
def _create_challenge_dirs(self):
|
def _create_challenge_dirs(self):
|
||||||
path_map = self.conf("map")
|
path_map = self.conf("map")
|
||||||
|
|||||||
@@ -471,5 +471,4 @@ def handle_renewal_request(config):
|
|||||||
if renew_failures or parse_failures:
|
if renew_failures or parse_failures:
|
||||||
raise errors.Error("{0} renew failure(s), {1} parse failure(s)".format(
|
raise errors.Error("{0} renew failure(s), {1} parse failure(s)".format(
|
||||||
len(renew_failures), len(parse_failures)))
|
len(renew_failures), len(parse_failures)))
|
||||||
else:
|
logger.debug("no renewal failures")
|
||||||
logger.debug("no renewal failures")
|
|
||||||
|
|||||||
@@ -1014,10 +1014,8 @@ class RenewableCert(interfaces.RenewableCert):
|
|||||||
"directory %s created.", archive, live_dir)
|
"directory %s created.", archive, live_dir)
|
||||||
|
|
||||||
# Put the data into the appropriate files on disk
|
# Put the data into the appropriate files on disk
|
||||||
target = dict([(kind, os.path.join(live_dir, kind + ".pem"))
|
target = {kind: os.path.join(live_dir, kind + ".pem") for kind in ALL_FOUR}
|
||||||
for kind in ALL_FOUR])
|
archive_target = {kind: os.path.join(archive, kind + "1.pem") for kind in ALL_FOUR}
|
||||||
archive_target = dict([(kind, os.path.join(archive, kind + "1.pem"))
|
|
||||||
for kind in ALL_FOUR])
|
|
||||||
for kind in ALL_FOUR:
|
for kind in ALL_FOUR:
|
||||||
os.symlink(_relpath_from_file(archive_target[kind], target[kind]), target[kind])
|
os.symlink(_relpath_from_file(archive_target[kind], target[kind]), target[kind])
|
||||||
with open(target["cert"], "wb") as f:
|
with open(target["cert"], "wb") as f:
|
||||||
@@ -1082,10 +1080,8 @@ class RenewableCert(interfaces.RenewableCert):
|
|||||||
|
|
||||||
self.cli_config = cli_config
|
self.cli_config = cli_config
|
||||||
target_version = self.next_free_version()
|
target_version = self.next_free_version()
|
||||||
target = dict(
|
target = {kind: os.path.join(self.archive_dir, "{0}{1}.pem".format(kind, target_version))
|
||||||
[(kind,
|
for kind in ALL_FOUR}
|
||||||
os.path.join(self.archive_dir, "{0}{1}.pem".format(kind, target_version)))
|
|
||||||
for kind in ALL_FOUR])
|
|
||||||
|
|
||||||
old_privkey = os.path.join(
|
old_privkey = os.path.join(
|
||||||
self.archive_dir, "privkey{0}.pem".format(prior_version))
|
self.archive_dir, "privkey{0}.pem".format(prior_version))
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ def copy_ownership_and_apply_mode(src, dst, mode, copy_user, copy_group):
|
|||||||
stats = os.stat(src)
|
stats = os.stat(src)
|
||||||
user_id = stats.st_uid if copy_user else -1
|
user_id = stats.st_uid if copy_user else -1
|
||||||
group_id = stats.st_gid if copy_group else -1
|
group_id = stats.st_gid if copy_group else -1
|
||||||
|
# On Windows, os.chown does not exist. This is checked through POSIX_MODE value,
|
||||||
|
# but MyPy/PyLint does not know it and raises an error here on Windows.
|
||||||
|
# We disable specifically the check to fix the issue.
|
||||||
os.chown(dst, user_id, group_id)
|
os.chown(dst, user_id, group_id)
|
||||||
elif copy_user:
|
elif copy_user:
|
||||||
# There is no group handling in Windows
|
# There is no group handling in Windows
|
||||||
@@ -105,7 +108,10 @@ def check_owner(file_path):
|
|||||||
:return: True if given file is owned by current user, False otherwise.
|
:return: True if given file is owned by current user, False otherwise.
|
||||||
"""
|
"""
|
||||||
if POSIX_MODE:
|
if POSIX_MODE:
|
||||||
return os.stat(file_path).st_uid == os.getuid()
|
# On Windows, os.getuid does not exist. This is checked through POSIX_MODE value,
|
||||||
|
# but MyPy/PyLint does not know it and raises an error here on Windows.
|
||||||
|
# We disable specifically the check to fix the issue.
|
||||||
|
return os.stat(file_path).st_uid == os.getuid() # type: ignore
|
||||||
|
|
||||||
# Get owner sid of the file
|
# Get owner sid of the file
|
||||||
security = win32security.GetFileSecurity(file_path, win32security.OWNER_SECURITY_INFORMATION)
|
security = win32security.GetFileSecurity(file_path, win32security.OWNER_SECURITY_INFORMATION)
|
||||||
|
|||||||
@@ -60,11 +60,10 @@ def get_email(invalid=False, optional=True):
|
|||||||
raise errors.Error(
|
raise errors.Error(
|
||||||
"An e-mail address or "
|
"An e-mail address or "
|
||||||
"--register-unsafely-without-email must be provided.")
|
"--register-unsafely-without-email must be provided.")
|
||||||
else:
|
raise errors.Error("An e-mail address must be provided.")
|
||||||
raise errors.Error("An e-mail address must be provided.")
|
if util.safe_email(email):
|
||||||
elif util.safe_email(email):
|
|
||||||
return email
|
return email
|
||||||
elif suggest_unsafe:
|
if suggest_unsafe:
|
||||||
msg += unsafe_suggestion
|
msg += unsafe_suggestion
|
||||||
suggest_unsafe = False # add this message at most once
|
suggest_unsafe = False # add this message at most once
|
||||||
|
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ class FileDisplay(object):
|
|||||||
message = _wrap_lines("%s (Enter 'c' to cancel):" % message) + " "
|
message = _wrap_lines("%s (Enter 'c' to cancel):" % message) + " "
|
||||||
ans = input_with_timeout(message)
|
ans = input_with_timeout(message)
|
||||||
|
|
||||||
if ans == "c" or ans == "C":
|
if ans in ("c", "C"):
|
||||||
return CANCEL, "-1"
|
return CANCEL, "-1"
|
||||||
return OK, ans
|
return OK, ans
|
||||||
|
|
||||||
@@ -258,10 +258,9 @@ class FileDisplay(object):
|
|||||||
selected_tags = self._scrub_checklist_input(indices, tags)
|
selected_tags = self._scrub_checklist_input(indices, tags)
|
||||||
if selected_tags:
|
if selected_tags:
|
||||||
return code, selected_tags
|
return code, selected_tags
|
||||||
else:
|
self.outfile.write(
|
||||||
self.outfile.write(
|
"** Error - Invalid selection **%s" % os.linesep)
|
||||||
"** Error - Invalid selection **%s" % os.linesep)
|
self.outfile.flush()
|
||||||
self.outfile.flush()
|
|
||||||
else:
|
else:
|
||||||
return code, []
|
return code, []
|
||||||
|
|
||||||
@@ -282,18 +281,17 @@ class FileDisplay(object):
|
|||||||
# assert_valid_call(prompt, default, cli_flag, force_interactive)
|
# assert_valid_call(prompt, default, cli_flag, force_interactive)
|
||||||
if self._can_interact(force_interactive):
|
if self._can_interact(force_interactive):
|
||||||
return False
|
return False
|
||||||
elif default is None:
|
if default is None:
|
||||||
msg = "Unable to get an answer for the question:\n{0}".format(prompt)
|
msg = "Unable to get an answer for the question:\n{0}".format(prompt)
|
||||||
if cli_flag:
|
if cli_flag:
|
||||||
msg += (
|
msg += (
|
||||||
"\nYou can provide an answer on the "
|
"\nYou can provide an answer on the "
|
||||||
"command line with the {0} flag.".format(cli_flag))
|
"command line with the {0} flag.".format(cli_flag))
|
||||||
raise errors.Error(msg)
|
raise errors.Error(msg)
|
||||||
else:
|
logger.debug(
|
||||||
logger.debug(
|
"Falling back to default %s for the prompt:\n%s",
|
||||||
"Falling back to default %s for the prompt:\n%s",
|
default, prompt)
|
||||||
default, prompt)
|
return True
|
||||||
return True
|
|
||||||
|
|
||||||
def _can_interact(self, force_interactive):
|
def _can_interact(self, force_interactive):
|
||||||
"""Can we safely interact with the user?
|
"""Can we safely interact with the user?
|
||||||
@@ -308,7 +306,7 @@ class FileDisplay(object):
|
|||||||
if (self.force_interactive or force_interactive or
|
if (self.force_interactive or force_interactive or
|
||||||
sys.stdin.isatty() and self.outfile.isatty()):
|
sys.stdin.isatty() and self.outfile.isatty()):
|
||||||
return True
|
return True
|
||||||
elif not self.skipped_interaction:
|
if not self.skipped_interaction:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Skipped user interaction because Certbot doesn't appear to "
|
"Skipped user interaction because Certbot doesn't appear to "
|
||||||
"be running in a terminal. You should probably include "
|
"be running in a terminal. You should probably include "
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ def dest_namespace(name):
|
|||||||
"""ArgumentParser dest namespace (prefix of all destinations)."""
|
"""ArgumentParser dest namespace (prefix of all destinations)."""
|
||||||
return name.replace("-", "_") + "_"
|
return name.replace("-", "_") + "_"
|
||||||
|
|
||||||
|
|
||||||
private_ips_regex = re.compile(
|
private_ips_regex = re.compile(
|
||||||
r"(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|"
|
r"(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|"
|
||||||
r"(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)")
|
r"(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)")
|
||||||
@@ -294,7 +295,7 @@ class Addr(object):
|
|||||||
# appended to the end
|
# appended to the end
|
||||||
append_to_end = True
|
append_to_end = True
|
||||||
continue
|
continue
|
||||||
elif len(block) > 1:
|
if len(block) > 1:
|
||||||
# remove leading zeros
|
# remove leading zeros
|
||||||
block = block.lstrip("0")
|
block = block.lstrip("0")
|
||||||
if not append_to_end:
|
if not append_to_end:
|
||||||
@@ -373,9 +374,9 @@ def install_version_controlled_file(dest_path, digest_path, src_path, all_hashes
|
|||||||
active_file_digest = crypto_util.sha256sum(dest_path)
|
active_file_digest = crypto_util.sha256sum(dest_path)
|
||||||
if active_file_digest == current_hash: # already up to date
|
if active_file_digest == current_hash: # already up to date
|
||||||
return
|
return
|
||||||
elif active_file_digest in all_hashes: # safe to update
|
if active_file_digest in all_hashes: # safe to update
|
||||||
_install_current_file()
|
_install_current_file()
|
||||||
else: # has been manually modified, not safe to update
|
else: # has been manually modified, not safe to update
|
||||||
# did they modify the current version or an old version?
|
# did they modify the current version or an old version?
|
||||||
if os.path.isfile(digest_path):
|
if os.path.isfile(digest_path):
|
||||||
with open(digest_path, "r") as f:
|
with open(digest_path, "r") as f:
|
||||||
|
|||||||
@@ -197,8 +197,7 @@ class DNSAuthenticator(common.Plugin):
|
|||||||
|
|
||||||
if code == display_util.OK:
|
if code == display_util.OK:
|
||||||
return response
|
return response
|
||||||
else:
|
raise errors.PluginError('{0} required to proceed.'.format(label))
|
||||||
raise errors.PluginError('{0} required to proceed.'.format(label))
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _prompt_for_file(label, validator=None):
|
def _prompt_for_file(label, validator=None):
|
||||||
@@ -231,8 +230,7 @@ class DNSAuthenticator(common.Plugin):
|
|||||||
|
|
||||||
if code == display_util.OK:
|
if code == display_util.OK:
|
||||||
return response
|
return response
|
||||||
else:
|
raise errors.PluginError('{0} required to proceed.'.format(label))
|
||||||
raise errors.PluginError('{0} required to proceed.'.format(label))
|
|
||||||
|
|
||||||
|
|
||||||
class CredentialsConfiguration(object):
|
class CredentialsConfiguration(object):
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class LexiconClient(object):
|
|||||||
result = self._handle_general_error(e, domain_name)
|
result = self._handle_general_error(e, domain_name)
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
raise result
|
raise result # pylint: disable=raising-bad-type
|
||||||
|
|
||||||
raise errors.PluginError('Unable to determine zone identifier for {0} using zone names: {1}'
|
raise errors.PluginError('Unable to determine zone identifier for {0} using zone names: {1}'
|
||||||
.format(domain, domain_name_guesses))
|
.format(domain, domain_name_guesses))
|
||||||
|
|||||||
@@ -28,18 +28,14 @@ class BaseAuthenticatorTest(object):
|
|||||||
challb=acme_util.DNS01, domain=DOMAIN, account_key=KEY)
|
challb=acme_util.DNS01, domain=DOMAIN, account_key=KEY)
|
||||||
|
|
||||||
def test_more_info(self):
|
def test_more_info(self):
|
||||||
# pylint: disable=no-member
|
self.assertTrue(isinstance(self.auth.more_info(), six.string_types)) # pylint: disable=no-member
|
||||||
self.assertTrue(isinstance(self.auth.more_info(), six.string_types))
|
|
||||||
|
|
||||||
def test_get_chall_pref(self):
|
def test_get_chall_pref(self):
|
||||||
# pylint: disable=no-member
|
self.assertEqual(self.auth.get_chall_pref(None), [challenges.DNS01]) # pylint: disable=no-member
|
||||||
self.assertEqual(self.auth.get_chall_pref(None), [challenges.DNS01])
|
|
||||||
|
|
||||||
def test_parser_arguments(self):
|
def test_parser_arguments(self):
|
||||||
m = mock.MagicMock()
|
m = mock.MagicMock()
|
||||||
|
self.auth.add_parser_arguments(m) # pylint: disable=no-member
|
||||||
# pylint: disable=no-member
|
|
||||||
self.auth.add_parser_arguments(m)
|
|
||||||
|
|
||||||
m.assert_any_call('propagation-seconds', type=int, default=mock.ANY, help=mock.ANY)
|
m.assert_any_call('propagation-seconds', type=int, default=mock.ANY, help=mock.ANY)
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,7 @@ def _guess_loader(filename, loader_pem, loader_der):
|
|||||||
return loader_pem
|
return loader_pem
|
||||||
elif ext.lower() == '.der':
|
elif ext.lower() == '.der':
|
||||||
return loader_der
|
return loader_der
|
||||||
else: # pragma: no cover
|
raise ValueError("Loader could not be recognized based on extension") # pragma: no cover
|
||||||
raise ValueError("Loader could not be recognized based on extension")
|
|
||||||
|
|
||||||
|
|
||||||
def load_cert(*names):
|
def load_cert(*names):
|
||||||
@@ -235,8 +234,7 @@ class FreezableMock(object):
|
|||||||
if self._frozen:
|
if self._frozen:
|
||||||
if name in self._frozen_set:
|
if name in self._frozen_set:
|
||||||
raise AttributeError('Cannot change frozen attribute ' + name)
|
raise AttributeError('Cannot change frozen attribute ' + name)
|
||||||
else:
|
return setattr(self._mock, name, value)
|
||||||
return setattr(self._mock, name, value)
|
|
||||||
|
|
||||||
if name != '_frozen_set':
|
if name != '_frozen_set':
|
||||||
self._frozen_set.add(name)
|
self._frozen_set.add(name)
|
||||||
@@ -250,7 +248,7 @@ class FreezableMock(object):
|
|||||||
def _create_get_utility_mock():
|
def _create_get_utility_mock():
|
||||||
display = FreezableMock()
|
display = FreezableMock()
|
||||||
# Use pylint code for disable to keep on single line under line length limit
|
# Use pylint code for disable to keep on single line under line length limit
|
||||||
for name in interfaces.IDisplay.names(): # pylint: disable=no-member,E1120
|
for name in interfaces.IDisplay.names(): # pylint: E1120
|
||||||
if name != 'notification':
|
if name != 'notification':
|
||||||
frozen_mock = FreezableMock(frozen=True, func=_assert_valid_call)
|
frozen_mock = FreezableMock(frozen=True, func=_assert_valid_call)
|
||||||
setattr(display, name, frozen_mock)
|
setattr(display, name, frozen_mock)
|
||||||
@@ -275,7 +273,7 @@ def _create_get_utility_mock_with_stdout(stdout):
|
|||||||
|
|
||||||
display = FreezableMock()
|
display = FreezableMock()
|
||||||
# Use pylint code for disable to keep on single line under line length limit
|
# Use pylint code for disable to keep on single line under line length limit
|
||||||
for name in interfaces.IDisplay.names(): # pylint: disable=no-member,E1120
|
for name in interfaces.IDisplay.names(): # pylint: E1120
|
||||||
if name == 'notification':
|
if name == 'notification':
|
||||||
frozen_mock = FreezableMock(frozen=True,
|
frozen_mock = FreezableMock(frozen=True,
|
||||||
func=_write_msg)
|
func=_write_msg)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from certbot.compat import filesystem
|
|||||||
from certbot.compat import os
|
from certbot.compat import os
|
||||||
|
|
||||||
if sys.platform.startswith('linux'):
|
if sys.platform.startswith('linux'):
|
||||||
import distro
|
import distro # pylint: disable=import-error
|
||||||
_USE_DISTRO = True
|
_USE_DISTRO = True
|
||||||
else:
|
else:
|
||||||
_USE_DISTRO = False
|
_USE_DISTRO = False
|
||||||
@@ -105,10 +105,9 @@ def exe_exists(exe):
|
|||||||
path, _ = os.path.split(exe)
|
path, _ = os.path.split(exe)
|
||||||
if path:
|
if path:
|
||||||
return filesystem.is_executable(exe)
|
return filesystem.is_executable(exe)
|
||||||
else:
|
for path in os.environ["PATH"].split(os.pathsep):
|
||||||
for path in os.environ["PATH"].split(os.pathsep):
|
if filesystem.is_executable(os.path.join(path, exe)):
|
||||||
if filesystem.is_executable(os.path.join(path, exe)):
|
return True
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -436,7 +435,6 @@ def add_deprecated_argument(add_argument, argument_name, nargs):
|
|||||||
# In version 0.12.0 ACTION_TYPES_THAT_DONT_NEED_A_VALUE was
|
# In version 0.12.0 ACTION_TYPES_THAT_DONT_NEED_A_VALUE was
|
||||||
# changed from a set to a tuple.
|
# changed from a set to a tuple.
|
||||||
if isinstance(configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE, set):
|
if isinstance(configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE, set):
|
||||||
# pylint: disable=no-member
|
|
||||||
configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE.add(
|
configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE.add(
|
||||||
_ShowWarning)
|
_ShowWarning)
|
||||||
else:
|
else:
|
||||||
@@ -537,7 +535,7 @@ def enforce_domain_sanity(domain):
|
|||||||
for l in labels:
|
for l in labels:
|
||||||
if not l:
|
if not l:
|
||||||
raise errors.ConfigurationError("{0} it contains an empty label.".format(msg))
|
raise errors.ConfigurationError("{0} it contains an empty label.".format(msg))
|
||||||
elif len(l) > 63:
|
if len(l) > 63:
|
||||||
raise errors.ConfigurationError("{0} label {1} is too long.".format(msg, l))
|
raise errors.ConfigurationError("{0} label {1} is too long.".format(msg, l))
|
||||||
|
|
||||||
return domain
|
return domain
|
||||||
@@ -571,7 +569,6 @@ def get_strict_version(normalized):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
# strict version ending with "a" and a number designates a pre-release
|
# strict version ending with "a" and a number designates a pre-release
|
||||||
# pylint: disable=no-member
|
|
||||||
return distutils.version.StrictVersion(normalized.replace(".dev", "a"))
|
return distutils.version.StrictVersion(normalized.replace(".dev", "a"))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -74,21 +74,21 @@ elif os.name == 'nt':
|
|||||||
install_requires.append(pywin32_req)
|
install_requires.append(pywin32_req)
|
||||||
|
|
||||||
dev_extras = [
|
dev_extras = [
|
||||||
'astroid==1.6.5',
|
|
||||||
'coverage',
|
'coverage',
|
||||||
'ipdb',
|
'ipdb',
|
||||||
'pytest',
|
'pytest',
|
||||||
'pytest-cov',
|
'pytest-cov',
|
||||||
'pytest-xdist',
|
'pytest-xdist',
|
||||||
'pylint==1.9.4',
|
|
||||||
'tox',
|
'tox',
|
||||||
'twine',
|
'twine',
|
||||||
'wheel',
|
'wheel',
|
||||||
]
|
]
|
||||||
|
|
||||||
dev3_extras = [
|
dev3_extras = [
|
||||||
|
'astroid',
|
||||||
'mypy',
|
'mypy',
|
||||||
'typing', # for python3.4
|
'pylint',
|
||||||
|
'typing', # for python3.4
|
||||||
]
|
]
|
||||||
|
|
||||||
docs_extras = [
|
docs_extras = [
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ class ReportFailedAuthzrsTest(unittest.TestCase):
|
|||||||
self.authzr1.body.identifier.value = 'example.com'
|
self.authzr1.body.identifier.value = 'example.com'
|
||||||
self.authzr1.body.challenges = [http_01, http_01]
|
self.authzr1.body.challenges = [http_01, http_01]
|
||||||
|
|
||||||
kwargs["error"] = messages.Error(typ="dnssec", detail="detail")
|
kwargs["error"] = messages.Error.with_code("dnssec", detail="detail")
|
||||||
http_01_diff = messages.ChallengeBody(**kwargs)
|
http_01_diff = messages.ChallengeBody(**kwargs)
|
||||||
|
|
||||||
self.authzr2 = mock.MagicMock()
|
self.authzr2 = mock.MagicMock()
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ class CertificatesTest(BaseCertManagerTest):
|
|||||||
mock_verifier.return_value = None
|
mock_verifier.return_value = None
|
||||||
mock_report.return_value = ""
|
mock_report.return_value = ""
|
||||||
self._certificates(self.config)
|
self._certificates(self.config)
|
||||||
self.assertFalse(mock_logger.warning.called) #pylint: disable=no-member
|
self.assertFalse(mock_logger.warning.called)
|
||||||
self.assertTrue(mock_report.called)
|
self.assertTrue(mock_report.called)
|
||||||
self.assertTrue(mock_utility.called)
|
self.assertTrue(mock_utility.called)
|
||||||
self.assertTrue(mock_renewable_cert.called)
|
self.assertTrue(mock_renewable_cert.called)
|
||||||
@@ -196,7 +196,7 @@ class CertificatesTest(BaseCertManagerTest):
|
|||||||
|
|
||||||
filesystem.makedirs(empty_config.renewal_configs_dir)
|
filesystem.makedirs(empty_config.renewal_configs_dir)
|
||||||
self._certificates(empty_config)
|
self._certificates(empty_config)
|
||||||
self.assertFalse(mock_logger.warning.called) #pylint: disable=no-member
|
self.assertFalse(mock_logger.warning.called)
|
||||||
self.assertTrue(mock_utility.called)
|
self.assertTrue(mock_utility.called)
|
||||||
shutil.rmtree(empty_tempdir)
|
shutil.rmtree(empty_tempdir)
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ class CertificatesTest(BaseCertManagerTest):
|
|||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
out = get_report()
|
out = get_report()
|
||||||
self.assertTrue('3 days' in out)
|
self.assertTrue('3 days' in out)
|
||||||
self.assertTrue('VALID' in out and 'INVALID' not in out)
|
self.assertTrue('VALID' in out and 'INVALID' not in out)
|
||||||
|
|
||||||
cert.is_test_cert = True
|
cert.is_test_cert = True
|
||||||
mock_revoked.return_value = True
|
mock_revoked.return_value = True
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ class RegisterTest(test_util.ConfigTestCase):
|
|||||||
def test_unsupported_error(self):
|
def test_unsupported_error(self):
|
||||||
from acme import messages
|
from acme import messages
|
||||||
msg = "Test"
|
msg = "Test"
|
||||||
mx_err = messages.Error(detail=msg, typ="malformed", title="title")
|
mx_err = messages.Error.with_code("malformed", detail=msg, title="title")
|
||||||
with mock.patch("certbot._internal.client.acme_client.BackwardsCompatibleClientV2") as mock_client:
|
with mock.patch("certbot._internal.client.acme_client.BackwardsCompatibleClientV2") as mock_client:
|
||||||
mock_client().client.directory.__getitem__ = mock.Mock(
|
mock_client().client.directory.__getitem__ = mock.Mock(
|
||||||
side_effect=self._new_acct_dir_mock
|
side_effect=self._new_acct_dir_mock
|
||||||
|
|||||||
@@ -363,6 +363,8 @@ class CheckPermissionsTest(test_util.TempDirTestCase):
|
|||||||
self.assertTrue(filesystem.check_owner(self.probe_path))
|
self.assertTrue(filesystem.check_owner(self.probe_path))
|
||||||
|
|
||||||
import os as std_os # pylint: disable=os-module-forbidden
|
import os as std_os # pylint: disable=os-module-forbidden
|
||||||
|
# See related inline comment in certbot.compat.filesystem.check_owner method
|
||||||
|
# that explains why MyPy/PyLint check disable is needed here.
|
||||||
uid = std_os.getuid()
|
uid = std_os.getuid()
|
||||||
|
|
||||||
with mock.patch('os.getuid') as mock_uid:
|
with mock.patch('os.getuid') as mock_uid:
|
||||||
|
|||||||
@@ -311,12 +311,12 @@ class FileOutputDisplayTest(unittest.TestCase):
|
|||||||
def test_methods_take_force_interactive(self):
|
def test_methods_take_force_interactive(self):
|
||||||
# Every IDisplay method implemented by FileDisplay must take
|
# Every IDisplay method implemented by FileDisplay must take
|
||||||
# force_interactive to prevent workflow regressions.
|
# force_interactive to prevent workflow regressions.
|
||||||
for name in interfaces.IDisplay.names(): # pylint: disable=no-member,no-value-for-parameter
|
for name in interfaces.IDisplay.names():
|
||||||
if six.PY2:
|
if six.PY2:
|
||||||
getargspec = inspect.getargspec # pylint: disable=no-member
|
getargspec = inspect.getargspec
|
||||||
else:
|
else:
|
||||||
getargspec = inspect.getfullargspec # pylint: disable=no-member
|
getargspec = inspect.getfullargspec
|
||||||
arg_spec = getargspec(getattr(self.displayer, name))
|
arg_spec = getargspec(getattr(self.displayer, name)) # pylint: disable=deprecated-method
|
||||||
self.assertTrue("force_interactive" in arg_spec.args)
|
self.assertTrue("force_interactive" in arg_spec.args)
|
||||||
|
|
||||||
|
|
||||||
@@ -372,14 +372,14 @@ class NoninteractiveDisplayTest(unittest.TestCase):
|
|||||||
# NoninteractiveDisplay.
|
# NoninteractiveDisplay.
|
||||||
|
|
||||||
# Use pylint code for disable to keep on single line under line length limit
|
# Use pylint code for disable to keep on single line under line length limit
|
||||||
for name in interfaces.IDisplay.names(): # pylint: disable=no-member,E1120
|
for name in interfaces.IDisplay.names(): # pylint: disable=E1120
|
||||||
method = getattr(self.displayer, name)
|
method = getattr(self.displayer, name)
|
||||||
# asserts method accepts arbitrary keyword arguments
|
# asserts method accepts arbitrary keyword arguments
|
||||||
if six.PY2:
|
if six.PY2:
|
||||||
result = inspect.getargspec(method).keywords # pylint: disable=no-member
|
result = inspect.getargspec(method).keywords # pylint:deprecated-method
|
||||||
self.assertFalse(result is None)
|
self.assertFalse(result is None)
|
||||||
else:
|
else:
|
||||||
result = inspect.getfullargspec(method).varkw # pylint: disable=no-member
|
result = inspect.getfullargspec(method).varkw
|
||||||
self.assertFalse(result is None)
|
self.assertFalse(result is None)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class SubscribeTest(unittest.TestCase):
|
|||||||
@test_util.patch_get_utility()
|
@test_util.patch_get_utility()
|
||||||
def test_bad_status(self, mock_get_utility):
|
def test_bad_status(self, mock_get_utility):
|
||||||
self.json['status'] = False
|
self.json['status'] = False
|
||||||
self._call() # pylint: disable=no-value-for-parameter
|
self._call()
|
||||||
actual = self._get_reported_message(mock_get_utility)
|
actual = self._get_reported_message(mock_get_utility)
|
||||||
expected_part = 'because your e-mail address appears to be invalid.'
|
expected_part = 'because your e-mail address appears to be invalid.'
|
||||||
self.assertTrue(expected_part in actual)
|
self.assertTrue(expected_part in actual)
|
||||||
@@ -120,7 +120,7 @@ class SubscribeTest(unittest.TestCase):
|
|||||||
def test_not_ok(self, mock_get_utility):
|
def test_not_ok(self, mock_get_utility):
|
||||||
self.response.ok = False
|
self.response.ok = False
|
||||||
self.response.raise_for_status.side_effect = requests.exceptions.HTTPError
|
self.response.raise_for_status.side_effect = requests.exceptions.HTTPError
|
||||||
self._call() # pylint: disable=no-value-for-parameter
|
self._call()
|
||||||
actual = self._get_reported_message(mock_get_utility)
|
actual = self._get_reported_message(mock_get_utility)
|
||||||
unexpected_part = 'because'
|
unexpected_part = 'because'
|
||||||
self.assertFalse(unexpected_part in actual)
|
self.assertFalse(unexpected_part in actual)
|
||||||
@@ -128,7 +128,7 @@ class SubscribeTest(unittest.TestCase):
|
|||||||
@test_util.patch_get_utility()
|
@test_util.patch_get_utility()
|
||||||
def test_response_not_json(self, mock_get_utility):
|
def test_response_not_json(self, mock_get_utility):
|
||||||
self.response.json.side_effect = ValueError()
|
self.response.json.side_effect = ValueError()
|
||||||
self._call() # pylint: disable=no-value-for-parameter
|
self._call()
|
||||||
actual = self._get_reported_message(mock_get_utility)
|
actual = self._get_reported_message(mock_get_utility)
|
||||||
expected_part = 'problem'
|
expected_part = 'problem'
|
||||||
self.assertTrue(expected_part in actual)
|
self.assertTrue(expected_part in actual)
|
||||||
@@ -136,7 +136,7 @@ class SubscribeTest(unittest.TestCase):
|
|||||||
@test_util.patch_get_utility()
|
@test_util.patch_get_utility()
|
||||||
def test_response_json_missing_status_element(self, mock_get_utility):
|
def test_response_json_missing_status_element(self, mock_get_utility):
|
||||||
self.json.clear()
|
self.json.clear()
|
||||||
self._call() # pylint: disable=no-value-for-parameter
|
self._call()
|
||||||
actual = self._get_reported_message(mock_get_utility)
|
actual = self._get_reported_message(mock_get_utility)
|
||||||
expected_part = 'problem'
|
expected_part = 'problem'
|
||||||
self.assertTrue(expected_part in actual)
|
self.assertTrue(expected_part in actual)
|
||||||
@@ -147,7 +147,7 @@ class SubscribeTest(unittest.TestCase):
|
|||||||
|
|
||||||
@test_util.patch_get_utility()
|
@test_util.patch_get_utility()
|
||||||
def test_subscribe(self, mock_get_utility):
|
def test_subscribe(self, mock_get_utility):
|
||||||
self._call() # pylint: disable=no-value-for-parameter
|
self._call()
|
||||||
self.assertFalse(mock_get_utility.called)
|
self.assertFalse(mock_get_utility.called)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,25 +13,27 @@ class FailedChallengesTest(unittest.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
from certbot.errors import FailedChallenges
|
from certbot.errors import FailedChallenges
|
||||||
self.error = FailedChallenges(set([achallenges.DNS(
|
self.error = FailedChallenges({achallenges.DNS(
|
||||||
domain="example.com", challb=messages.ChallengeBody(
|
domain="example.com", challb=messages.ChallengeBody(
|
||||||
chall=acme_util.DNS01, uri=None,
|
chall=acme_util.DNS01, uri=None,
|
||||||
error=messages.Error(typ="tls", detail="detail")))]))
|
error=messages.Error.with_code("tls", detail="detail")))})
|
||||||
|
|
||||||
def test_str(self):
|
def test_str(self):
|
||||||
self.assertTrue(str(self.error).startswith(
|
self.assertTrue(str(self.error).startswith(
|
||||||
"Failed authorization procedure. example.com (dns-01): tls"))
|
"Failed authorization procedure. example.com (dns-01): "
|
||||||
|
"urn:ietf:params:acme:error:tls"))
|
||||||
|
|
||||||
def test_unicode(self):
|
def test_unicode(self):
|
||||||
from certbot.errors import FailedChallenges
|
from certbot.errors import FailedChallenges
|
||||||
arabic_detail = u'\u0639\u062f\u0627\u0644\u0629'
|
arabic_detail = u'\u0639\u062f\u0627\u0644\u0629'
|
||||||
arabic_error = FailedChallenges(set([achallenges.DNS(
|
arabic_error = FailedChallenges({achallenges.DNS(
|
||||||
domain="example.com", challb=messages.ChallengeBody(
|
domain="example.com", challb=messages.ChallengeBody(
|
||||||
chall=acme_util.DNS01, uri=None,
|
chall=acme_util.DNS01, uri=None,
|
||||||
error=messages.Error(typ="tls", detail=arabic_detail)))]))
|
error=messages.Error.with_code("tls", detail=arabic_detail)))})
|
||||||
|
|
||||||
self.assertTrue(str(arabic_error).startswith(
|
self.assertTrue(str(arabic_error).startswith(
|
||||||
"Failed authorization procedure. example.com (dns-01): tls"))
|
"Failed authorization procedure. example.com (dns-01): "
|
||||||
|
"urn:ietf:params:acme:error:tls"))
|
||||||
|
|
||||||
|
|
||||||
class StandaloneBindErrorTest(unittest.TestCase):
|
class StandaloneBindErrorTest(unittest.TestCase):
|
||||||
|
|||||||
@@ -37,12 +37,10 @@ class EnhancementTest(test_util.ConfigTestCase):
|
|||||||
self.assertTrue([i for i in enabled if i["name"] == "somethingelse"])
|
self.assertTrue([i for i in enabled if i["name"] == "somethingelse"])
|
||||||
|
|
||||||
def test_are_requested(self):
|
def test_are_requested(self):
|
||||||
self.assertEqual(
|
self.assertEqual(len(list(enhancements.enabled_enhancements(self.config))), 0)
|
||||||
len([i for i in enhancements.enabled_enhancements(self.config)]), 0)
|
|
||||||
self.assertFalse(enhancements.are_requested(self.config))
|
self.assertFalse(enhancements.are_requested(self.config))
|
||||||
self.config.auto_hsts = True
|
self.config.auto_hsts = True
|
||||||
self.assertEqual(
|
self.assertEqual(len(list(enhancements.enabled_enhancements(self.config))), 1)
|
||||||
len([i for i in enhancements.enabled_enhancements(self.config)]), 1)
|
|
||||||
self.assertTrue(enhancements.are_requested(self.config))
|
self.assertTrue(enhancements.are_requested(self.config))
|
||||||
|
|
||||||
def test_are_supported(self):
|
def test_are_supported(self):
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class ServerManagerTest(unittest.TestCase):
|
|||||||
|
|
||||||
def _test_run_stop(self, challenge_type):
|
def _test_run_stop(self, challenge_type):
|
||||||
server = self.mgr.run(port=0, challenge_type=challenge_type)
|
server = self.mgr.run(port=0, challenge_type=challenge_type)
|
||||||
port = server.getsocknames()[0][1] # pylint: disable=no-member
|
port = server.getsocknames()[0][1]
|
||||||
self.assertEqual(self.mgr.running(), {port: server})
|
self.assertEqual(self.mgr.running(), {port: server})
|
||||||
self.mgr.stop(port=port)
|
self.mgr.stop(port=port)
|
||||||
self.assertEqual(self.mgr.running(), {})
|
self.assertEqual(self.mgr.running(), {})
|
||||||
@@ -47,7 +47,7 @@ class ServerManagerTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_run_idempotent(self):
|
def test_run_idempotent(self):
|
||||||
server = self.mgr.run(port=0, challenge_type=challenges.HTTP01)
|
server = self.mgr.run(port=0, challenge_type=challenges.HTTP01)
|
||||||
port = server.getsocknames()[0][1] # pylint: disable=no-member
|
port = server.getsocknames()[0][1]
|
||||||
server2 = self.mgr.run(port=port, challenge_type=challenges.HTTP01)
|
server2 = self.mgr.run(port=port, challenge_type=challenges.HTTP01)
|
||||||
self.assertEqual(self.mgr.running(), {port: server})
|
self.assertEqual(self.mgr.running(), {port: server})
|
||||||
self.assertTrue(server is server2)
|
self.assertTrue(server is server2)
|
||||||
|
|||||||
@@ -356,8 +356,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||||||
basename = os.path.basename(path)
|
basename = os.path.basename(path)
|
||||||
if "fullchain" in basename and basename.startswith("prev"):
|
if "fullchain" in basename and basename.startswith("prev"):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
else:
|
real_unlink(path)
|
||||||
real_unlink(path)
|
|
||||||
|
|
||||||
self._write_out_ex_kinds()
|
self._write_out_ex_kinds()
|
||||||
with mock.patch("certbot._internal.storage.os.unlink") as mock_unlink:
|
with mock.patch("certbot._internal.storage.os.unlink") as mock_unlink:
|
||||||
@@ -372,8 +371,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||||||
# pylint: disable=missing-docstring
|
# pylint: disable=missing-docstring
|
||||||
if "fullchain" in os.path.basename(path):
|
if "fullchain" in os.path.basename(path):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
else:
|
real_unlink(path)
|
||||||
real_unlink(path)
|
|
||||||
|
|
||||||
self._write_out_ex_kinds()
|
self._write_out_ex_kinds()
|
||||||
with mock.patch("certbot._internal.storage.os.unlink") as mock_unlink:
|
with mock.patch("certbot._internal.storage.os.unlink") as mock_unlink:
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ def make_and_verify_selection(server_root, temp_dir):
|
|||||||
ans = six.moves.input("(Y)es/(N)o: ").lower()
|
ans = six.moves.input("(Y)es/(N)o: ").lower()
|
||||||
if ans.startswith("y"):
|
if ans.startswith("y"):
|
||||||
return
|
return
|
||||||
elif ans.startswith("n"):
|
if ans.startswith("n"):
|
||||||
sys.exit("Your files were not submitted")
|
sys.exit("Your files were not submitted")
|
||||||
|
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ def safe_config_file(config_file):
|
|||||||
empty_or_all_comments = False
|
empty_or_all_comments = False
|
||||||
if line.startswith("-----BEGIN"):
|
if line.startswith("-----BEGIN"):
|
||||||
return False
|
return False
|
||||||
elif ":" not in line:
|
if ":" not in line:
|
||||||
possible_password_file = False
|
possible_password_file = False
|
||||||
# If file isn't empty or commented out and could be a password file,
|
# If file isn't empty or commented out and could be a password file,
|
||||||
# don't include it in selection. It is safe to include the file if
|
# don't include it in selection. It is safe to include the file if
|
||||||
|
|||||||
+1
-1
@@ -173,7 +173,7 @@ def setup_certificate(workspace):
|
|||||||
|
|
||||||
key_path = os.path.join(workspace, 'cert.key')
|
key_path = os.path.join(workspace, 'cert.key')
|
||||||
with open(key_path, 'wb') as file_handle:
|
with open(key_path, 'wb') as file_handle:
|
||||||
file_handle.write(private_key.private_bytes(
|
file_handle.write(private_key.private_bytes( # type: ignore
|
||||||
encoding=serialization.Encoding.PEM,
|
encoding=serialization.Encoding.PEM,
|
||||||
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||||
encryption_algorithm=serialization.NoEncryption()
|
encryption_algorithm=serialization.NoEncryption()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ alabaster==0.7.10
|
|||||||
apipkg==1.4
|
apipkg==1.4
|
||||||
appnope==0.1.0
|
appnope==0.1.0
|
||||||
asn1crypto==0.22.0
|
asn1crypto==0.22.0
|
||||||
astroid==1.6.5
|
astroid==2.3.3
|
||||||
attrs==17.3.0
|
attrs==17.3.0
|
||||||
Babel==2.5.1
|
Babel==2.5.1
|
||||||
backports.functools-lru-cache==1.5
|
backports.functools-lru-cache==1.5
|
||||||
@@ -33,17 +33,18 @@ importlib-metadata==0.23
|
|||||||
ipdb==0.10.2
|
ipdb==0.10.2
|
||||||
ipython==5.5.0
|
ipython==5.5.0
|
||||||
ipython-genutils==0.2.0
|
ipython-genutils==0.2.0
|
||||||
isort==4.2.5
|
isort==4.3.21
|
||||||
Jinja2==2.9.6
|
Jinja2==2.9.6
|
||||||
jmespath==0.9.3
|
jmespath==0.9.3
|
||||||
josepy==1.1.0
|
josepy==1.1.0
|
||||||
lazy-object-proxy==1.3.1
|
lazy-object-proxy==1.4.3
|
||||||
logger==1.4
|
logger==1.4
|
||||||
logilab-common==1.4.1
|
logilab-common==1.4.1
|
||||||
MarkupSafe==1.0
|
MarkupSafe==1.0
|
||||||
mccabe==0.6.1
|
mccabe==0.6.1
|
||||||
more-itertools==5.0.0
|
more-itertools==5.0.0
|
||||||
mypy==0.600
|
mypy==0.710
|
||||||
|
mypy-extensions==0.4.3
|
||||||
ndg-httpsclient==0.3.2
|
ndg-httpsclient==0.3.2
|
||||||
oauth2client==4.0.0
|
oauth2client==4.0.0
|
||||||
packaging==19.2
|
packaging==19.2
|
||||||
@@ -58,7 +59,7 @@ py==1.8.0
|
|||||||
pyasn1==0.1.9
|
pyasn1==0.1.9
|
||||||
pyasn1-modules==0.0.10
|
pyasn1-modules==0.0.10
|
||||||
Pygments==2.2.0
|
Pygments==2.2.0
|
||||||
pylint==1.9.4
|
pylint==2.4.3
|
||||||
# If pynsist version is upgraded, our NSIS template windows-installer/template.nsi
|
# If pynsist version is upgraded, our NSIS template windows-installer/template.nsi
|
||||||
# must be upgraded if necessary using the new built-in one from pynsist.
|
# must be upgraded if necessary using the new built-in one from pynsist.
|
||||||
pynsist==2.4
|
pynsist==2.4
|
||||||
@@ -90,10 +91,10 @@ tox==3.14.0
|
|||||||
tqdm==4.19.4
|
tqdm==4.19.4
|
||||||
traitlets==4.3.2
|
traitlets==4.3.2
|
||||||
twine==1.11.0
|
twine==1.11.0
|
||||||
typed-ast==1.1.0
|
typed-ast==1.4.0
|
||||||
typing==3.6.4
|
typing==3.6.4
|
||||||
uritemplate==3.0.0
|
uritemplate==3.0.0
|
||||||
virtualenv==16.6.2
|
virtualenv==16.6.2
|
||||||
wcwidth==0.1.7
|
wcwidth==0.1.7
|
||||||
wrapt==1.11.1
|
wrapt==1.11.2
|
||||||
zipp==0.6.0
|
zipp==0.6.0
|
||||||
|
|||||||
@@ -122,12 +122,13 @@ commands =
|
|||||||
python tox.cover.py
|
python tox.cover.py
|
||||||
|
|
||||||
[testenv:lint]
|
[testenv:lint]
|
||||||
basepython = python2.7
|
basepython = python3
|
||||||
# separating into multiple invocations disables cross package
|
# separating into multiple invocations disables cross package
|
||||||
# duplicate code checking; if one of the commands fails, others will
|
# duplicate code checking; if one of the commands fails, others will
|
||||||
# continue, but tox return code will reflect previous error
|
# continue, but tox return code will reflect previous error
|
||||||
commands =
|
commands =
|
||||||
{[base]install_packages}
|
{[base]install_packages}
|
||||||
|
{[base]pip_install} certbot[dev3]
|
||||||
python -m pylint --reports=n --rcfile=.pylintrc {[base]source_paths}
|
python -m pylint --reports=n --rcfile=.pylintrc {[base]source_paths}
|
||||||
|
|
||||||
[testenv:mypy]
|
[testenv:mypy]
|
||||||
|
|||||||
Reference in New Issue
Block a user